Browse Source

Allow the qmake executable to be passed on CLI

This change adds a new command line option `qmake` to the tool which
allows the user to specify the qmake executable to be used. By default,
if that option is omitted, the behavior is unchanged (i.e. the tool first
searches for the `qmake` executable and - if this is not successful -
then for either `qmake-qt5` or `qmake-qt4`. If the new option is used,
no search takes place and instead the executable provided is used as-is.

This implements a part of the functionality as discussed in issue #94.
master
Martin Höher 8 years ago
parent
commit
a3a6376573
  1. 11
      README.md
  2. 18
      linuxdeployqt/main.cpp
  3. 56
      shared/shared.cpp
  4. 4
      shared/shared.h

11
README.md

@ -20,7 +20,7 @@ Please download __linuxdeployqt-x86_64.AppImage__ from the [Releases](https://gi
Open in Qt Creator and build your application. Run it from the command line and inspect it with `ldd` to make sure the correct libraries from the correct locations are getting loaded, as `linuxdeployqt` will use `ldd` internally to determine from where to copy libraries into the bundle.
__Important:__ `linuxdeployqt` deploys the Qt instance that qmake on the $PATH points to, so make sure that it is the correct one. Verify that qmake finds the correct Qt instance like this before running the `linuxdeployqt` tool:
__Important:__ By default, `linuxdeployqt` deploys the Qt instance that qmake on the $PATH points to, so make sure that it is the correct one. Verify that qmake finds the correct Qt instance like this before running the `linuxdeployqt` tool:
```
qmake -v
@ -29,6 +29,7 @@ QMake version 3.0
Using Qt version 5.7.0 in /tmp/.mount_QtCreator-5.7.0-x86_64/5.7/gcc_64/lib
```
If this does not show the correct path to your Qt instance that you want to be bundled, then adjust your `$PATH` to find the correct `qmake`.
Alternatively, use the `-qmake` command line option to point the tool directly to the qmake executable to be used.
Before running linuxdeployqt it may be wise to delete unneeded files that you do not wish to distribute from the build directory. These may be autogenerated during the build. You can delete them like so:
@ -69,8 +70,8 @@ dist: trusty
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y
- sudo apt-get update -qq
install:
install:
- sudo apt-get -y install qt58base
- source /opt/qt*/bin/qt*-env.sh
@ -80,14 +81,14 @@ script:
- make INSTALL_ROOT=appdir install ; find appdir/
after_success:
- wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
- wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
- chmod a+x linuxdeployqt*.AppImage
- unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -bundle-non-qt-libs
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage
- find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq
- curl --upload-file ./APPNAME*.AppImage https://transfer.sh/APPNAME-git.$(git rev-parse --short HEAD)-x86_64.AppImage
```
```
When you save your change, then Travis CI should build and upload an AppImage for you. More likely than not, some fine-tuning will still be required.

18
linuxdeployqt/main.cpp

@ -55,13 +55,15 @@ int main(int argc, char **argv)
qDebug() << " -executable=<path> : Let the given executable use the deployed libraries too";
qDebug() << " -qmldir=<path> : Scan for QML imports in the given path";
qDebug() << " -always-overwrite : Copy files even if the target file exists";
qDebug() << " -qmake=<path> : The qmake executable to use";
qDebug() << "";
qDebug() << "linuxdeployqt takes an application as input and makes it";
qDebug() << "self-contained by copying in the Qt libraries and plugins that";
qDebug() << "the application uses.";
qDebug() << "";
qDebug() << "It deploys the Qt instance that qmake on the $PATH points to,";
qDebug() << "so make sure that it is the correct one.";
qDebug() << "By default it deploys the Qt instance that qmake on the $PATH points to.";
qDebug() << "The '-qmake' option can be used to point to the qmake executable";
qDebug() << "to be used instead.";
qDebug() << "";
qDebug() << "Plugins related to a Qt library are copied in with the library.";
/* TODO: To be implemented
@ -145,7 +147,7 @@ int main(int argc, char **argv)
// Allow binaries next to linuxdeployqt to be found; this is useful for bundling
// this application itself together with helper binaries such as patchelf
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString oldPath = env.value("PATH");
QString oldPath = env.value("PATH");
QString newPath = QCoreApplication::applicationDirPath() + ":" + oldPath;
LogDebug() << newPath;
setenv("PATH",newPath.toUtf8().constData(),1);
@ -169,6 +171,7 @@ int main(int argc, char **argv)
QStringList additionalExecutables;
bool qmldirArgumentUsed = false;
QStringList qmlDirs;
QString qmakeExecutable;
/* 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. */
@ -304,7 +307,7 @@ int main(int argc, char **argv)
qDebug() << "preExistingToplevelIcon:" << preExistingToplevelIcon;
} else {
qDebug() << "iconToBeUsed:" << iconToBeUsed;
QString targetIconPath = appDirPath + "/" + QFileInfo(iconToBeUsed).fileName();
QString targetIconPath = appDirPath + "/" + QFileInfo(iconToBeUsed).fileName();
if (QFile::copy(iconToBeUsed, targetIconPath)){
qDebug() << "Copied" << iconToBeUsed << "to" << targetIconPath;
QFile::copy(targetIconPath, appDirPath + "/.DirIcon");
@ -358,6 +361,10 @@ int main(int argc, char **argv)
} else if (argument == QByteArray("-always-overwrite")) {
LogDebug() << "Argument found:" << argument;
alwaysOwerwriteEnabled = true;
} else if (argument.startsWith("-qmake=")) {
LogDebug() << "Argument found:" << argument;
int index = argument.indexOf("=");
qmakeExecutable = argument.mid(index+1);
} else if (argument.startsWith("-")) {
LogError() << "Unknown argument" << argument << "\n";
return 1;
@ -371,7 +378,8 @@ int main(int argc, char **argv)
}
}
DeploymentInfo deploymentInfo = deployQtLibraries(appDirPath, additionalExecutables);
DeploymentInfo deploymentInfo = deployQtLibraries(appDirPath, additionalExecutables,
qmakeExecutable);
// Convenience: Look for .qml files in the current directoty if no -qmldir specified.
if (qmlDirs.isEmpty()) {

56
shared/shared.cpp

@ -99,20 +99,20 @@ inline QDebug operator<<(QDebug debug, const AppDirInfo &info)
// on architecture. See "vDSO names" in the notes section of vdso(7)
// for more information.
static bool lddOutputContainsLinuxVDSO(const QString &lddOutput) {
// aarch64, arm, mips, x86_64, x86/x32
if (lddOutput.contains(QStringLiteral("linux-vdso.so.1"))) {
return true;
// ppc32, s390
} else if (lddOutput.contains(QStringLiteral("linux-vdso32.so.1"))) {
return true;
// ppc64, s390x
} else if (lddOutput.contains(QStringLiteral("linux-vdso64.so.1"))) {
return true;
// ia64, sh, i386
} else if (lddOutput.contains(QStringLiteral("linux-gate.so.1"))) {
return true;
}
return false;
// aarch64, arm, mips, x86_64, x86/x32
if (lddOutput.contains(QStringLiteral("linux-vdso.so.1"))) {
return true;
// ppc32, s390
} else if (lddOutput.contains(QStringLiteral("linux-vdso32.so.1"))) {
return true;
// ppc64, s390x
} else if (lddOutput.contains(QStringLiteral("linux-vdso64.so.1"))) {
return true;
// ia64, sh, i386
} else if (lddOutput.contains(QStringLiteral("linux-gate.so.1"))) {
return true;
}
return false;
}
bool copyFilePrintStatus(const QString &from, const QString &to)
@ -879,7 +879,7 @@ static QString captureOutput(const QString &command)
return process.readAllStandardOutput();
}
DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &additionalExecutables)
DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &additionalExecutables, const QString& qmake)
{
AppDirInfo applicationBundle;
@ -906,15 +906,19 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
// Determine the location of the Qt to be bundled
LogDebug() << "Using qmake to determine the location of the Qt to be bundled";
QString qmakePath = "";
// Use the qmake executable passed in by the user:
QString qmakePath = qmake;
// The upstream name of the binary is "qmake", for Qt 4 and Qt 5
qmakePath = QStandardPaths::findExecutable("qmake");
// If we did not get a qmake, first try to find "qmake", which is the
// upstream name of the binary in both Qt4 and Qt5:
if (qmakePath.isEmpty()) {
qmakePath = QStandardPaths::findExecutable("qmake");
}
// But openSUSE has qmake for Qt 4 and qmake-qt5 for Qt 5
// Qt 4 on Fedora comes with suffix -qt4
// http://www.geopsy.org/wiki/index.php/Installing_Qt_binary_packages
if(qmakePath == ""){
if(qmakePath.isEmpty()){
if(qtDetected == 5){
qmakePath = QStandardPaths::findExecutable("qmake-qt5");
}
@ -1016,7 +1020,7 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
}
} else {
pluginList.append(QStringLiteral("imageformats/") + plugin);
}
}
}
}
@ -1026,8 +1030,8 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
foreach (const QString &plugin, xcbglintegrationPlugins) {
pluginList.append(QStringLiteral("xcbglintegrations/") + plugin);
}
}
}
// Also deploy plugins/iconengines/libqsvgicon.so whenever libQt5Svg.so.* is about to be deployed,
// https://github.com/probonopd/linuxdeployqt/issues/36
if (containsHowOften(deploymentInfo.deployedLibraries, "libQt5Svg")) {
@ -1069,7 +1073,7 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
QString sourcePath;
QString destinationPath;
// Qt WebEngine if libQt5WebEngineCore is in use
// https://doc-snapshots.qt.io/qt5-5.7/qtwebengine-deploying.html
// TODO: Rather than hardcode the source paths, somehow get them dynamically
@ -1124,7 +1128,7 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
destinationPath = QDir::cleanPath(dstTranslations + "/qtwebengine_locales");
recursiveCopy(sourcePath, destinationPath);
}
LogNormal() << "pluginList after having detected hopefully all required plugins:" << pluginList;
foreach (const QString &plugin, pluginList) {
@ -1143,7 +1147,7 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
QString relativePath = dir.relativeFilePath(appDirInfo.path + "/" + libraries[0].libraryDestinationDirectory);
relativePath.remove(0, 3); // remove initial '../'
changeIdentification("$ORIGIN/" + relativePath, QFileInfo(destinationPath).canonicalFilePath());
}
}
}
@ -1224,7 +1228,7 @@ bool deployQmlImports(const QString &appDirPath, DeploymentInfo deploymentInfo,
argumentList.append(qtToBeBundledInfo.value("QT_INSTALL_QML"));
LogDebug() << "qmlImportsPath (QT_INSTALL_QML):" << qtToBeBundledInfo.value("QT_INSTALL_QML");
// run qmlimportscanner
QProcess qmlImportScanner;
LogDebug() << qmlImportScannerPath << argumentList;

4
shared/shared.h

@ -112,7 +112,9 @@ QString findAppBinary(const QString &appDirPath);
QList<LibraryInfo> getQtLibraries(const QString &path, const QString &appDirPath, const QSet<QString> &rpaths);
QList<LibraryInfo> getQtLibraries(const QStringList &lddLines, const QString &appDirPath, const QSet<QString> &rpaths);
QString copyLibrary(const LibraryInfo &library, const QString path);
DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &additionalExecutables);
DeploymentInfo deployQtLibraries(const QString &appDirPath,
const QStringList &additionalExecutables,
const QString &qmake);
DeploymentInfo deployQtLibraries(QList<LibraryInfo> libraries,const QString &bundlePath, const QStringList &binaryPaths, bool useLoaderPath);
void deployPlugins(const QString &appDirPath, DeploymentInfo deploymentInfo);
bool deployQmlImports(const QString &appDirPath, DeploymentInfo deploymentInfo, QStringList &qmlDirs);

Loading…
Cancel
Save