From 99b48867cac52b2b5bbb44f73bcb67d16a8a84a7 Mon Sep 17 00:00:00 2001 From: Josef Svensson Date: Fri, 23 Feb 2018 15:40:53 +0100 Subject: [PATCH 1/4] Added ability to blocke files from a folder, added posibility to decide in what relative folder libs should be saved to --- tools/linuxdeployqt/main.cpp | 20 +++++++++++-- tools/linuxdeployqt/shared.cpp | 51 ++++++++++++++++++++++------------ tools/linuxdeployqt/shared.h | 2 ++ 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/tools/linuxdeployqt/main.cpp b/tools/linuxdeployqt/main.cpp index afbc3e90..814224be 100644 --- a/tools/linuxdeployqt/main.cpp +++ b/tools/linuxdeployqt/main.cpp @@ -99,10 +99,8 @@ int main(int argc, char **argv) qInfo() << ""; qInfo() << "See the \"Deploying Applications on Linux\" topic in the"; qInfo() << "documentation for more information about deployment on Linux."; - return 1; } - QString desktopFile = ""; QString desktopExecEntry = ""; QString desktopIconEntry = ""; @@ -199,6 +197,9 @@ int main(int argc, char **argv) extern bool fhsLikeMode; extern QString fhsPrefix; extern QStringList librarySearchPath; + extern QString librarySavePath; + extern QString blockedFolder; + extern bool alwaysOwerwriteEnabled; QStringList additionalExecutables; bool qmldirArgumentUsed = false; @@ -234,6 +235,7 @@ int main(int argc, char **argv) QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); relativeBinPath = relativePrefix + "/bin/" + appName; } + if(appDirPath == "/"){ LogError() << "'/' is not a valid AppDir. Please refer to the documentation."; LogError() << "Consider adding INSTALL_ROOT or DESTDIR to your install steps."; @@ -411,6 +413,20 @@ int main(int argc, char **argv) LogDebug() << "Argument found:" << argument; int index = argument.indexOf("="); extraQtPlugins = QString(argument.mid(index + 1)).split(","); + } else if (argument.startsWith(QByteArray("-save-lib-path"))) { + LogDebug() << "Argument found:" << argument; + int index = argument.indexOf('='); + if (index == -1) + LogError() << "Missing library path"; + else + librarySavePath = argument.mid(index+1); + } else if (argument.startsWith(QByteArray("-exclude-libs-in-folder"))) { + LogDebug() << "Argument found:" << argument; + int index = argument.indexOf('='); + if (index == -1) + LogError() << "Missing exclude folder path"; + else + blockedFolder = argument.mid(index+1); } else if (argument.startsWith("-")) { LogError() << "Error: arguments must not start with --, only -" << "\n"; return 1; diff --git a/tools/linuxdeployqt/shared.cpp b/tools/linuxdeployqt/shared.cpp index 2f25e600..2ceb2dcf 100644 --- a/tools/linuxdeployqt/shared.cpp +++ b/tools/linuxdeployqt/shared.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,8 @@ bool fhsLikeMode = false; QString fhsPrefix; bool alwaysOwerwriteEnabled = false; QStringList librarySearchPath; +QString librarySavePath; +QString blockedFolder; bool appstoreCompliant = false; int logLevel = 1; int qtDetected = 0; @@ -435,12 +438,7 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, { (void)rpaths; - if(fhsLikeMode == false){ - bundleLibraryDirectory= "lib"; // relative to bundle - } else { - QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); - bundleLibraryDirectory = relativePrefix + "/lib/"; - } + handleFshLibPath(appDirPath); LogDebug() << "bundleLibraryDirectory:" << bundleLibraryDirectory; LibraryInfo info; @@ -465,12 +463,11 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, echo -ne '"'$item'" << ' done */ - QStringList excludelist; excludelist << "libasound.so.2" << "libcom_err.so.2" << "libcrypt.so.1" << "libc.so.6" << "libdl.so.2" << "libdrm.so.2" << "libexpat.so.1" << "libfontconfig.so.1" << "libgcc_s.so.1" << "libgdk_pixbuf-2.0.so.0" << "libgio-2.0.so.0" << "libglib-2.0.so.0" << "libGL.so.1" << "libgobject-2.0.so.0" << "libgpg-error.so.0" << "libICE.so.6" << "libkeyutils.so.1" << "libm.so.6" << "libnsl.so.1" << "libnss3.so" << "libnssutil3.so" << "libp11-kit.so.0" << "libpangoft2-1.0.so.0" << "libpangocairo-1.0.so.0" << "libpango-1.0.so.0" << "libpthread.so.0" << "libresolv.so.2" << "librt.so.1" << "libSM.so.6" << "libstdc++.so.6" << "libusb-1.0.so.0" << "libuuid.so.1" << "libX11.so.6" << "libxcb.so.1" << "libz.so.1"; LogDebug() << "excludelist:" << excludelist; if (! trimmed.contains("libicu")) { - if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName())) { + if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName()) || QFileInfo(trimmed).absolutePath().startsWith(blockedFolder)) { LogDebug() << "Skipping blacklisted" << trimmed; return info; } @@ -556,6 +553,7 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, } if (!info.sourceFilePath.isEmpty() && QFile::exists(info.sourceFilePath)) { + qInfo() << "TJA"; info.installName = findDependencyInfo(info.sourceFilePath).installName; if (info.installName.startsWith("@rpath/")) info.deployedInstallName = info.installName; @@ -716,13 +714,7 @@ void recursiveCopyAndDeploy(const QString &appDirPath, const QSet &rpat runStrip(fileDestinationPath); // Find out the relative path to the lib/ directory and set it as the rpath - // FIXME: remove code duplication - the next few lines exist elsewhere already - if(fhsLikeMode == false){ - bundleLibraryDirectory= "lib"; // relative to bundle - } else { - QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); - bundleLibraryDirectory = relativePrefix + "/lib/"; - } + handleFshLibPath(appDirPath); QDir dir(QFileInfo(fileDestinationPath).canonicalFilePath()); QString relativePath = dir.relativeFilePath(appDirPath + "/" + bundleLibraryDirectory); @@ -845,7 +837,7 @@ void changeIdentification(const QString &id, const QString &binaryPath) { LogNormal() << "Checking rpath in" << binaryPath; QString oldRpath = runPatchelf(QStringList() << "--print-rpath" << binaryPath); - LogDebug() << "oldRpath:" << oldRpath; +//if(oldRpath.startsWith("$")) return; if (oldRpath.startsWith("/")){ LogDebug() << "Old rpath in" << binaryPath << "starts with /, hence adding it to LD_LIBRARY_PATH"; // FIXME: Split along ":" characters, check each one, only append to LD_LIBRARY_PATH if not already there @@ -858,8 +850,8 @@ void changeIdentification(const QString &id, const QString &binaryPath) setenv("LD_LIBRARY_PATH",newPath.toUtf8().constData(),1); } } - LogNormal() << "Changing rpath in" << binaryPath << "to" << id; - runPatchelf(QStringList() << "--set-rpath" << id << binaryPath); + LogNormal() << "Changing rpath in" << binaryPath << "to" << id; + runPatchelf(QStringList() << "--set-rpath" << id << binaryPath); // qt_prfxpath: if (binaryPath.contains("libQt5Core")) { @@ -1866,3 +1858,26 @@ bool deployTranslations(const QString &sourcePath, const QString &target, quint6 } // for prefixes. return true; } + + +void handleFshLibPath(const QString& appDirPath) +{ + if(fhsLikeMode == false){ + bundleLibraryDirectory = librarySavePath.isEmpty() ? "lib" : librarySavePath; // relative to bundle + } else { + QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); + bundleLibraryDirectory = relativePrefix + "/" + librarySavePath; + } +} + +QString stripAbsolutePathFromRPath(QString& rpath) +{ + QString ret; + QChar divider = ':'; + QStringList subPaths = rpath.split(divider); + for(QString sub : subPaths) { + if(!sub.startsWith("/")) ret += divider + sub; + } + return ret; +} + diff --git a/tools/linuxdeployqt/shared.h b/tools/linuxdeployqt/shared.h index 33175219..b32f64b8 100644 --- a/tools/linuxdeployqt/shared.h +++ b/tools/linuxdeployqt/shared.h @@ -135,5 +135,7 @@ bool checkAppImagePrerequisites(const QString &appBundlePath); void findUsedModules(DeploymentInfo &info); void deployTranslations(const QString &appDirPath, quint64 usedQtModules); bool deployTranslations(const QString &sourcePath, const QString &target, quint64 usedQtModules); +void handleFshLibPath(const QString& appDirPath); +QString stripAbsolutePathFromRPath(QString& rPath); #endif From 46c97e20e4a11f1cb463cb060f4b62cdfbcb465d Mon Sep 17 00:00:00 2001 From: Josef Svensson Date: Mon, 26 Feb 2018 13:56:35 +0100 Subject: [PATCH 2/4] Added some description of added flags and fixed some errors when not passing the flags --- tools/linuxdeployqt/main.cpp | 8 ++++++-- tools/linuxdeployqt/shared.cpp | 32 +++++++++++++------------------- tools/linuxdeployqt/shared.h | 1 - 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/tools/linuxdeployqt/main.cpp b/tools/linuxdeployqt/main.cpp index 814224be..56a5e47d 100644 --- a/tools/linuxdeployqt/main.cpp +++ b/tools/linuxdeployqt/main.cpp @@ -81,6 +81,9 @@ int main(int argc, char **argv) qInfo() << " -no-translations : Skip deployment of translations."; qInfo() << " -extra-plugins= : List of extra plugins which should be deployed,"; qInfo() << " separated by comma."; + qInfo() << " -save-lib-path : Relative path from folder below bin to where to save the deployed libs,"; + qInfo() << " defaults to /lib, should not be used with -appimage"; + qInfo() << " -exclude-folder: : Excludes all libs in folder and subfolders."; qInfo() << " -version : Print version statement and exit."; qInfo() << ""; qInfo() << "linuxdeployqt takes an application as input and makes it"; @@ -369,6 +372,7 @@ int main(int argc, char **argv) LogDebug() << "Argument found:" << argument; appimage = true; bundleAllButCoreLibs = true; + librarySavePath = ""; } else if (argument == QByteArray("-no-strip")) { LogDebug() << "Argument found:" << argument; runStripEnabled = false; @@ -418,9 +422,9 @@ int main(int argc, char **argv) int index = argument.indexOf('='); if (index == -1) LogError() << "Missing library path"; - else + else if (!appimage) librarySavePath = argument.mid(index+1); - } else if (argument.startsWith(QByteArray("-exclude-libs-in-folder"))) { + } else if (argument.startsWith(QByteArray("-exclude-folder"))) { LogDebug() << "Argument found:" << argument; int index = argument.indexOf('='); if (index == -1) diff --git a/tools/linuxdeployqt/shared.cpp b/tools/linuxdeployqt/shared.cpp index 2ceb2dcf..0d6bf5e4 100644 --- a/tools/linuxdeployqt/shared.cpp +++ b/tools/linuxdeployqt/shared.cpp @@ -467,7 +467,7 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, excludelist << "libasound.so.2" << "libcom_err.so.2" << "libcrypt.so.1" << "libc.so.6" << "libdl.so.2" << "libdrm.so.2" << "libexpat.so.1" << "libfontconfig.so.1" << "libgcc_s.so.1" << "libgdk_pixbuf-2.0.so.0" << "libgio-2.0.so.0" << "libglib-2.0.so.0" << "libGL.so.1" << "libgobject-2.0.so.0" << "libgpg-error.so.0" << "libICE.so.6" << "libkeyutils.so.1" << "libm.so.6" << "libnsl.so.1" << "libnss3.so" << "libnssutil3.so" << "libp11-kit.so.0" << "libpangoft2-1.0.so.0" << "libpangocairo-1.0.so.0" << "libpango-1.0.so.0" << "libpthread.so.0" << "libresolv.so.2" << "librt.so.1" << "libSM.so.6" << "libstdc++.so.6" << "libusb-1.0.so.0" << "libuuid.so.1" << "libX11.so.6" << "libxcb.so.1" << "libz.so.1"; LogDebug() << "excludelist:" << excludelist; if (! trimmed.contains("libicu")) { - if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName()) || QFileInfo(trimmed).absolutePath().startsWith(blockedFolder)) { + if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName()) || (!blockedFolder.isEmpty() && QFileInfo(trimmed).absolutePath().startsWith(blockedFolder))) { LogDebug() << "Skipping blacklisted" << trimmed; return info; } @@ -553,7 +553,6 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, } if (!info.sourceFilePath.isEmpty() && QFile::exists(info.sourceFilePath)) { - qInfo() << "TJA"; info.installName = findDependencyInfo(info.sourceFilePath).installName; if (info.installName.startsWith("@rpath/")) info.deployedInstallName = info.installName; @@ -837,7 +836,7 @@ void changeIdentification(const QString &id, const QString &binaryPath) { LogNormal() << "Checking rpath in" << binaryPath; QString oldRpath = runPatchelf(QStringList() << "--print-rpath" << binaryPath); -//if(oldRpath.startsWith("$")) return; + QString newRpath; if (oldRpath.startsWith("/")){ LogDebug() << "Old rpath in" << binaryPath << "starts with /, hence adding it to LD_LIBRARY_PATH"; // FIXME: Split along ":" characters, check each one, only append to LD_LIBRARY_PATH if not already there @@ -849,9 +848,13 @@ void changeIdentification(const QString &id, const QString &binaryPath) LogDebug() << "Added to LD_LIBRARY_PATH:" << newPath; setenv("LD_LIBRARY_PATH",newPath.toUtf8().constData(),1); } + } else if(oldRpath.startsWith("$ORIGIN") && oldRpath != id) { + newRpath = oldRpath + ":" + id; + } else { + newRpath = id; } - LogNormal() << "Changing rpath in" << binaryPath << "to" << id; - runPatchelf(QStringList() << "--set-rpath" << id << binaryPath); + LogNormal() << "Changing rpath in" << binaryPath << "to" << newRpath; + runPatchelf(QStringList() << "--set-rpath" << newRpath << binaryPath); // qt_prfxpath: if (binaryPath.contains("libQt5Core")) { @@ -1143,10 +1146,11 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a qtDetectionComplete = 1; QString libraryPath; + QString prefix = librarySavePath.isEmpty() ? "lib/" : librarySavePath; if(fhsLikeMode == false){ - libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("lib/" + bundleLibraryDirectory); + libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath(prefix + bundleLibraryDirectory); } else { - libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("../lib/" + bundleLibraryDirectory); + libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("../" + prefix + bundleLibraryDirectory); } /* Make ldd detect pre-existing libraries in the AppDir. @@ -1866,18 +1870,8 @@ void handleFshLibPath(const QString& appDirPath) bundleLibraryDirectory = librarySavePath.isEmpty() ? "lib" : librarySavePath; // relative to bundle } else { QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); - bundleLibraryDirectory = relativePrefix + "/" + librarySavePath; + QString tmp = librarySavePath.isEmpty() ? "/lib/" : librarySavePath; + bundleLibraryDirectory = relativePrefix + tmp; } } -QString stripAbsolutePathFromRPath(QString& rpath) -{ - QString ret; - QChar divider = ':'; - QStringList subPaths = rpath.split(divider); - for(QString sub : subPaths) { - if(!sub.startsWith("/")) ret += divider + sub; - } - return ret; -} - diff --git a/tools/linuxdeployqt/shared.h b/tools/linuxdeployqt/shared.h index b32f64b8..9d80a812 100644 --- a/tools/linuxdeployqt/shared.h +++ b/tools/linuxdeployqt/shared.h @@ -136,6 +136,5 @@ void findUsedModules(DeploymentInfo &info); void deployTranslations(const QString &appDirPath, quint64 usedQtModules); bool deployTranslations(const QString &sourcePath, const QString &target, quint64 usedQtModules); void handleFshLibPath(const QString& appDirPath); -QString stripAbsolutePathFromRPath(QString& rPath); #endif From 63ec3e00c9b005042b4e76314ea7b07e61077cfa Mon Sep 17 00:00:00 2001 From: Josef Svensson Date: Mon, 26 Feb 2018 14:04:16 +0100 Subject: [PATCH 3/4] Updated README with new Usage --- README.md | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 2e5edc55..37a8dd5c 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,32 @@ Please download __linuxdeployqt-x86_64.AppImage__ from the [Releases](https://gi ## Usage ``` -Usage: linuxdeployqt app-binary [options] +Usage: linuxdeployqt [options] Options: - -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug - -no-plugins : Skip plugin deployment - -appimage : Create an AppImage - -no-strip : Don't run 'strip' on the binaries - -bundle-non-qt-libs : Also bundle non-core, non-Qt libraries - -executable= : Let the given executable use the deployed libraries too - -qmldir= : Scan for QML imports to bundle from the given directory, determined by Qt's qmlimportscanner - -always-overwrite : Copy files even if the target file exists - -qmake= : The qmake executable to use - -no-translations : Skip deployment of translations - -extra-plugins= : List of extra plugins which should be deployed, separated by comma + -verbose=<0-3> : 0 = no output, 1 = error/warning (default), + 2 = normal, 3 = debug + -no-plugins : Skip plugin deployment + -appimage : Create an AppImage (implies -bundle-non-qt-libs) + -no-strip : Don't run 'strip' on the binaries + -bundle-non-qt-libs : Also bundle non-core, non-Qt libraries + -executable= : Let the given executable use the deployed libraries + too + -qmldir= : Scan for QML imports in the given path + -always-overwrite : Copy files even if the target file exists + -qmake= : The qmake executable to use + -no-translations : Skip deployment of translations. + -extra-plugins= : List of extra plugins which should be deployed, + separated by comma. + -save-lib-path : Relative path from folder below bin to where to save the deployed libs, + defaults to /lib + -exclude-folder: : Excludes all libs in folder and subfolders. + -version : Print version statement and exit. linuxdeployqt takes an application as input and makes it self-contained by copying in the Qt libraries and plugins that the application uses. + ``` #### Simplest example From c634a92ef7ceea8f63b77719fd2b79c88ab39011 Mon Sep 17 00:00:00 2001 From: Josef Svensson Date: Mon, 26 Feb 2018 14:12:59 +0100 Subject: [PATCH 4/4] Fixed some formatting issues to make pull request as small as possible --- README.md | 1 - tools/linuxdeployqt/main.cpp | 4 ++-- tools/linuxdeployqt/shared.cpp | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 37a8dd5c..b2b70965 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,6 @@ Options: linuxdeployqt takes an application as input and makes it self-contained by copying in the Qt libraries and plugins that the application uses. - ``` #### Simplest example diff --git a/tools/linuxdeployqt/main.cpp b/tools/linuxdeployqt/main.cpp index 56a5e47d..75f9d156 100644 --- a/tools/linuxdeployqt/main.cpp +++ b/tools/linuxdeployqt/main.cpp @@ -102,8 +102,10 @@ int main(int argc, char **argv) qInfo() << ""; qInfo() << "See the \"Deploying Applications on Linux\" topic in the"; qInfo() << "documentation for more information about deployment on Linux."; + return 1; } + QString desktopFile = ""; QString desktopExecEntry = ""; QString desktopIconEntry = ""; @@ -202,7 +204,6 @@ int main(int argc, char **argv) extern QStringList librarySearchPath; extern QString librarySavePath; extern QString blockedFolder; - extern bool alwaysOwerwriteEnabled; QStringList additionalExecutables; bool qmldirArgumentUsed = false; @@ -238,7 +239,6 @@ int main(int argc, char **argv) QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); relativeBinPath = relativePrefix + "/bin/" + appName; } - if(appDirPath == "/"){ LogError() << "'/' is not a valid AppDir. Please refer to the documentation."; LogError() << "Consider adding INSTALL_ROOT or DESTDIR to your install steps."; diff --git a/tools/linuxdeployqt/shared.cpp b/tools/linuxdeployqt/shared.cpp index 0d6bf5e4..9ff7c723 100644 --- a/tools/linuxdeployqt/shared.cpp +++ b/tools/linuxdeployqt/shared.cpp @@ -836,6 +836,7 @@ void changeIdentification(const QString &id, const QString &binaryPath) { LogNormal() << "Checking rpath in" << binaryPath; QString oldRpath = runPatchelf(QStringList() << "--print-rpath" << binaryPath); + LogDebug() << "oldRpath:" << oldRpath; QString newRpath; if (oldRpath.startsWith("/")){ LogDebug() << "Old rpath in" << binaryPath << "starts with /, hence adding it to LD_LIBRARY_PATH";