diff --git a/README.md b/README.md index 2e5edc55..b2b70965 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,27 @@ 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 diff --git a/tools/linuxdeployqt/main.cpp b/tools/linuxdeployqt/main.cpp index afbc3e90..75f9d156 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"; @@ -199,6 +202,8 @@ 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; @@ -367,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; @@ -411,6 +417,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 if (!appimage) + librarySavePath = argument.mid(index+1); + } else if (argument.startsWith(QByteArray("-exclude-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..9ff7c723 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()) || (!blockedFolder.isEmpty() && QFileInfo(trimmed).absolutePath().startsWith(blockedFolder))) { LogDebug() << "Skipping blacklisted" << trimmed; return info; } @@ -716,13 +713,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); @@ -846,6 +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; + 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 @@ -857,9 +849,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")) { @@ -1151,10 +1147,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,3 +1863,16 @@ 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+"/", ""); + QString tmp = librarySavePath.isEmpty() ? "/lib/" : librarySavePath; + bundleLibraryDirectory = relativePrefix + tmp; + } +} + diff --git a/tools/linuxdeployqt/shared.h b/tools/linuxdeployqt/shared.h index 33175219..9d80a812 100644 --- a/tools/linuxdeployqt/shared.h +++ b/tools/linuxdeployqt/shared.h @@ -135,5 +135,6 @@ 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); #endif