From 557bad2241df2c33972c7e6bdbf0c528cee27cc8 Mon Sep 17 00:00:00 2001 From: TheAssassin Date: Wed, 15 Jul 2020 03:17:37 +0200 Subject: [PATCH] Add --deploy-deps-only --- include/linuxdeploy/core/appdir.h | 5 +++ src/core/appdir.cpp | 55 +++++++++++++++++++++++++++++++ src/main.cpp | 32 ++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/include/linuxdeploy/core/appdir.h b/include/linuxdeploy/core/appdir.h index dab1cd9..d67ff95 100644 --- a/include/linuxdeploy/core/appdir.h +++ b/include/linuxdeploy/core/appdir.h @@ -57,6 +57,11 @@ namespace linuxdeploy { // deploy executable bool deployExecutable(const boost::filesystem::path& path, const boost::filesystem::path& destination = ""); + // deploy dependencies for ELF file in AppDir, without copying it into the library dir + // + // the dependencies end up in the regular location + bool deployDependenciesOnlyForElfFile(const boost::filesystem::path& elfFilePath, bool failSilentForNonElfFile = false); + // deploy desktop file bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile); diff --git a/src/core/appdir.cpp b/src/core/appdir.cpp index 88758b0..65e45dd 100644 --- a/src/core/appdir.cpp +++ b/src/core/appdir.cpp @@ -830,6 +830,61 @@ namespace linuxdeploy { return true; } + // TODO: quite similar to deployDependenciesForExistingFiles... maybe they should be merged or use each other + bool AppDir::deployDependenciesOnlyForElfFile(const boost::filesystem::path& elfFilePath, bool failSilentForNonElfFile) { + // preconditions: file must be an ELF one, and file must be contained in the AppDir + const auto absoluteElfFilePath = bf::absolute(elfFilePath); + + // can't bundle directories + if (!bf::is_regular_file(absoluteElfFilePath)) { + ldLog() << LD_DEBUG << "Skipping non-file directory entry:" << absoluteElfFilePath << std::endl; + return false; + } + + // to do a proper prefix check, we need a proper absolute path for the AppDir + const auto absoluteAppDirPath = bf::absolute(this->path()); + ldLog() << LD_DEBUG << "absolute AppDir path:" << absoluteAppDirPath << std::endl; + + // a fancy way to check STL strings for prefixes is to "ab"use rfind + if (absoluteElfFilePath.string().rfind(absoluteAppDirPath.string()) != 0) { + ldLog() << LD_ERROR << "File" << absoluteElfFilePath << "is not contained in AppDir, its dependencies cannot be deployed into the AppDir" << std::endl; + return false; + } + + // make sure we have an ELF file + try { + elf::ElfFile(absoluteElfFilePath.string()); + } catch (const elf::ElfFileParseError& e) { + auto level = LD_ERROR; + + if (failSilentForNonElfFile) { + level = LD_WARNING; + } + + ldLog() << level << "Not an ELF file:" << absoluteElfFilePath << std::endl; + + return failSilentForNonElfFile; + } + + // relative path makes for a nicer and more consistent log + ldLog() << "Deploying dependencies for ELF file in AppDir:" << elfFilePath << std::endl; + + // bundle dependencies + if (!d->deployElfDependencies(absoluteElfFilePath)) + return false; + + // set rpath correctly + const auto rpathDestination = this->path() / "usr/lib"; + ldLog() << LD_DEBUG << "rpath destination:" << rpathDestination << std::endl; + + const auto rpath = PrivateData::calculateRelativeRPath(elfFilePath.parent_path(), rpathDestination); + ldLog() << LD_DEBUG << "Calculated rpath:" << rpath << std::endl; + + d->setElfRPathOperations[absoluteElfFilePath] = rpath; + + return true; + } + void AppDir::setDisableCopyrightFilesDeployment(bool disable) { d->disableCopyrightFilesDeployment = disable; } diff --git a/src/main.cpp b/src/main.cpp index fcbb962..62b2322 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,6 +36,8 @@ int main(int argc, char** argv) { args::ValueFlagList executablePaths(parser, "executable", "Executable to deploy", {'e', "executable"}); + args::ValueFlagList deployDepsOnlyPaths(parser, "path", "Path to ELF file or directory containing such files (libraries or executables) in the AppDir whose dependencies shall be deployed by linuxdeploy without copying them into the AppDir", {"deploy-deps-only"}); + args::ValueFlagList desktopFilePaths(parser, "desktop file", "Desktop file to deploy", {'d', "desktop-file"}); args::Flag createDesktopFile(parser, "", "Create basic desktop file that is good enough for some tests", {"create-desktop-file"}); @@ -147,6 +149,36 @@ int main(int argc, char** argv) { } } + // deploy executables to usr/bin, and deploy their dependencies to usr/lib + if (deployDepsOnlyPaths) { + ldLog() << std::endl << "-- Deploying dependencies only for ELF files --" << std::endl; + + for (const auto& path : deployDepsOnlyPaths.Get()) { + if (bf::is_directory(path)) { + ldLog() << "Deploying files in directory" << path << std::endl; + + for (auto it = bf::directory_iterator{path}; it != bf::directory_iterator{}; ++it) { + if (!bf::is_regular_file(*it)) { + continue; + } + + if (!appDir.deployDependenciesOnlyForElfFile(*it, true)) { + ldLog() << LD_WARNING << "Failed to deploy dependencies for ELF file" << *it << LD_NO_SPACE << ", skipping" << std::endl; + return 1; + } + } + } else if (bf::is_regular_file(path)) { + if (!appDir.deployDependenciesOnlyForElfFile(path)) { + ldLog() << LD_ERROR << "Failed to deploy dependencies for ELF file: " << path << std::endl; + return 1; + } + } else { + ldLog() << LD_ERROR << "No such file or directory: " << path << std::endl; + return 1; + } + } + } + // perform deferred copy operations before running input plugins to make sure all files the plugins might expect // are in place ldLog() << std::endl << "-- Copying files into AppDir --" << std::endl;