diff --git a/.travis.yml b/.travis.yml index 54fed16..7484a78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,14 +23,16 @@ install: script: - source /opt/qt*/bin/qt*-env.sh - /opt/qt*/bin/qmake linuxdeployqt.pro - - make -j7 + + - make -j2 + - mkdir -p linuxdeployqt.AppDir/usr/bin/ - cp /usr/local/bin/patchelf linuxdeployqt.AppDir/usr/bin/ - cp /usr/local/bin/appimagetool linuxdeployqt.AppDir/usr/bin/ - find linuxdeployqt.AppDir/ - - export VERSION=continuous - - cp ./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/linuxdeployqt - - ./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/linuxdeployqt -verbose=3 -appimage + - export VERSION=continuousfhs + - cp ./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/usr/bin/ + - ./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/usr/bin/linuxdeployqt -verbose=3 -appimage - ls -lh - find *.AppDir - wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh diff --git a/README.md b/README.md index 8020dbd..7870eda 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,8 @@ tar xf patchelf-0.9.tar.bz2 * Optional if you want to generate AppImages: Download [appimagetool](https://github.com/probonopd/AppImageKit/releases) and put it into your $PATH, e.g., into `/usr/local/bin`. Make sure it is renamed to `appimagetool` and is `chmod a+x` ``` -wget https://github.com/probonopd/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool -chmod a+x appimagetool -sudo mv appimagetool /usr/local/bin/ +sudo wget -c "https://github.com/probonopd/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" -O /usr/local/bin/appimagetool +sudo chmod a+x /usr/local/bin/appimagetool ``` ## Usage diff --git a/linuxdeployqt/main.cpp b/linuxdeployqt/main.cpp index dfae9d5..356c55c 100644 --- a/linuxdeployqt/main.cpp +++ b/linuxdeployqt/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char **argv) { QCoreApplication app(argc, argv); - QString appBinaryPath; + extern QString appBinaryPath; if (argc > 1) { appBinaryPath = QString::fromLocal8Bit(argv[1]); @@ -91,34 +91,54 @@ int main(int argc, char **argv) return 1; } - QDir dir; - // QString appDir = QDir::cleanPath(appFile + "/../" + appName + ".AppDir"); QString appDir = QDir::cleanPath(appBinaryPath + "/../"); - if (QDir().exists(appDir) == false) { qDebug() << "Error: Could not find AppDir" << appDir; return 1; } - QString appDirPath = appDir; - - QFile appRun(appDir + "/AppRun"); - - if(appRun.exists()){ - appRun.remove(); - } - QFile::link(appName, appDir + "/AppRun"); - bool plugins = true; bool appimage = false; extern bool runStripEnabled; extern bool bundleAllButCoreLibs; + extern bool fhsLikeMode; + extern QString fhsPrefix; extern bool alwaysOwerwriteEnabled; extern QStringList librarySearchPath; QStringList additionalExecutables; bool qmldirArgumentUsed = false; QStringList qmlDirs; + /* FHS-like mode is for an application that has been installed to a $PREFIX which is otherwise empty, e.g., /path/to/usr. + * In this case, we want to construct an AppDir in /path/to. */ + if (QDir().exists((QDir::cleanPath(appBinaryPath + "/../../bin"))) == true) { + fhsPrefix = QDir::cleanPath(appBinaryPath + "/../../"); + qDebug() << "FHS-like mode with PREFIX, fhsPrefix:" << fhsPrefix; + fhsLikeMode = true; + } else { + qDebug() << "Not using FHS-like mode, appBinaryPath:" << appBinaryPath; + } + + QString appDirPath; + QString relativeBinPath; + if(fhsLikeMode == false){ + appDirPath = appDir; + relativeBinPath = appName; + } else { + appDirPath = QDir::cleanPath(fhsPrefix + "/../"); + QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); + relativeBinPath = relativePrefix + "/bin/" + appName; + } + qDebug() << "appDirPath:" << appDirPath; + qDebug() << "relativeBinPath:" << relativeBinPath; + + QFile appRun(appDirPath + "/AppRun"); + if(appRun.exists()){ + appRun.remove(); + } + + QFile::link(relativeBinPath, appDirPath + "/AppRun"); + for (int i = 2; i < argc; ++i) { QByteArray argument = QByteArray(argv[i]); if (argument == QByteArray("-no-plugins")) { @@ -175,8 +195,10 @@ int main(int argc, char **argv) } if (appimage) { - if(checkAppImagePrerequisites(appDirPath) == false) + if(checkAppImagePrerequisites(appDirPath) == false){ + LogError() << "checkAppImagePrerequisites failed\n"; return 1; + } } DeploymentInfo deploymentInfo = deployQtLibraries(appDirPath, additionalExecutables); diff --git a/shared/shared.cpp b/shared/shared.cpp index 1d958f8..fd679c9 100644 --- a/shared/shared.cpp +++ b/shared/shared.cpp @@ -44,9 +44,11 @@ #include #include "shared.h" - +QString appBinaryPath; bool runStripEnabled = true; bool bundleAllButCoreLibs = false; +bool fhsLikeMode = false; +QString fhsPrefix; bool alwaysOwerwriteEnabled = false; QStringList librarySearchPath; bool appstoreCompliant = false; @@ -81,7 +83,7 @@ QDebug operator<<(QDebug debug, const LibraryInfo &info) return debug; } -const QString bundleLibraryDirectory = "lib"; // the same directory as the main executable; could define a relative subdirectory here +QString bundleLibraryDirectory; inline QDebug operator<<(QDebug debug, const AppDirInfo &info) { @@ -217,6 +219,14 @@ int containsHowOften(QStringList haystack, QString needle) { LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, const QSet &rpaths) { + if(fhsLikeMode == false){ + bundleLibraryDirectory= "lib"; // relative to bundle + } else { + QString relativePrefix = fhsPrefix.replace(appDirPath+"/", ""); + bundleLibraryDirectory = relativePrefix + "/lib/"; + } + LogDebug() << "bundleLibraryDirectory:" << bundleLibraryDirectory; + LibraryInfo info; QString trimmed = line.trimmed(); @@ -338,21 +348,6 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath, return info; } -QString findAppBinary(const QString &appDirPath) -{ - QString binaryPath; - - // FIXME: Do without the need for an AppRun symlink - // by passing appBinaryPath from main.cpp here - binaryPath = appDirPath + "/" + "AppRun"; - - if (QFile::exists(binaryPath)) - return binaryPath; - - LogError() << "Could not find bundle binary for" << appDirPath << "at" << binaryPath; - exit(1); -} - QStringList findAppLibraries(const QString &appDirPath) { QStringList result; @@ -678,7 +673,7 @@ void runStrip(const QString &binaryPath) void stripAppBinary(const QString &bundlePath) { - runStrip(findAppBinary(bundlePath)); + runStrip(appBinaryPath); } /* @@ -772,7 +767,7 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a applicationBundle.path = appDirPath; LogDebug() << "applicationBundle.path:" << applicationBundle.path; - applicationBundle.binaryPath = findAppBinary(appDirPath); + applicationBundle.binaryPath = appBinaryPath; LogDebug() << "applicationBundle.binaryPath:" << applicationBundle.binaryPath; // Determine the location of the Qt to be bundled @@ -804,7 +799,11 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a setenv("LD_LIBRARY_PATH",newPath.toUtf8().constData(),1); } - changeIdentification("$ORIGIN/" + bundleLibraryDirectory, applicationBundle.binaryPath); + if(fhsLikeMode == false){ + changeIdentification("$ORIGIN/" + bundleLibraryDirectory, applicationBundle.binaryPath); + } else { + changeIdentification("$ORIGIN/../lib/" + bundleLibraryDirectory, applicationBundle.binaryPath); + } applicationBundle.libraryPaths = findAppLibraries(appDirPath); LogDebug() << "applicationBundle.libraryPaths:" << applicationBundle.libraryPaths; @@ -986,7 +985,7 @@ void createQtConf(const QString &appDirPath) "Qml2Imports = qml\n"; QString filePath = appDirPath + "/"; // Is picked up when placed next to the main executable - QString fileName = filePath + "qt.conf"; + QString fileName = appBinaryPath + "/../qt.conf"; QDir().mkpath(filePath); @@ -1036,7 +1035,7 @@ void deployPlugins(const QString &appDirPath, DeploymentInfo deploymentInfo) { AppDirInfo applicationBundle; applicationBundle.path = appDirPath; - applicationBundle.binaryPath = findAppBinary(appDirPath); + applicationBundle.binaryPath = appBinaryPath; const QString pluginDestinationPath = appDirPath + "/" + "plugins"; deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo); @@ -1104,7 +1103,7 @@ bool deployQmlImports(const QString &appDirPath, DeploymentInfo deploymentInfo, LogDebug() << qmlImportScannerPath << argumentList; qmlImportScanner.start(qmlImportScannerPath, argumentList); if (!qmlImportScanner.waitForStarted()) { - LogError() << "Could not start qmlimpoortscanner. Process error is" << qmlImportScanner.errorString(); + LogError() << "Could not start qmlimportscanner. Process error is" << qmlImportScanner.errorString(); return false; } qmlImportScanner.waitForFinished(); @@ -1208,7 +1207,6 @@ void changeQtLibraries(const QList libraries, const QStringList &bi void changeQtLibraries(const QString appPath, const QString &qtPath) { - const QString appBinaryPath = findAppBinary(appPath); const QStringList libraryPaths = findAppLibraries(appPath); const QList libraries = getQtLibrariesForPaths(QStringList() << appBinaryPath << libraryPaths, appPath, getBinaryRPaths(appBinaryPath, true)); if (libraries.isEmpty()) { @@ -1223,6 +1221,12 @@ void changeQtLibraries(const QString appPath, const QString &qtPath) bool checkAppImagePrerequisites(const QString &appDirPath) { + if(fhsLikeMode == true){ + /* In FHS-like mode, we assume that there will be a desktop file + * and icon file that appimagetool will be able to pick up */ + return true; + } + QDirIterator iter(appDirPath, QStringList() << QString::fromLatin1("*.desktop"), QDir::Files, QDirIterator::Subdirectories); if (!iter.hasNext()) { diff --git a/shared/shared.h b/shared/shared.h index 736f920..31cc688 100644 --- a/shared/shared.h +++ b/shared/shared.h @@ -40,8 +40,11 @@ extern int logLevel; #define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:" #define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:" +extern QString appBinaryPath; extern bool runStripEnabled; extern bool bundleAllButCoreLibs; +extern bool fhsLikeMode; +extern QString fhsPrefix; class LibraryInfo {