Merge branch 'master' of https://github.com/probonopd/linuxdeployqt
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
load(qt_build_config)
|
||||||
|
|
||||||
|
CONFIG += warning_clean exceptions
|
||||||
|
|
||||||
|
MODULE_VERSION = 0.5.0
|
||||||
+9
-3
@@ -1,8 +1,8 @@
|
|||||||
# Building from source
|
# Building from source
|
||||||
|
|
||||||
If you just would like to bundle your application, it is normally not necessary that you build `linuxdeployqt` yourself. Instead, download __linuxdeployqt-x86_64.AppImage__ from the [Releases](https://github.com/probonopd/linuxdeployqt/releases) page and `chmod a+x` it. This bundle, by the way, has been generated using `linuxdeployqt` itself as part of our Travis CI continuous build pipeline.
|
If you just would like to bundle your application for x86_64 platforms, it is normally not necessary that you build `linuxdeployqt` yourself. Instead, download __linuxdeployqt-x86_64.AppImage__ from the [Releases](https://github.com/probonopd/linuxdeployqt/releases) page and `chmod a+x` it. This bundle, by the way, has been generated using `linuxdeployqt` itself as part of our Travis CI continuous build pipeline.
|
||||||
|
|
||||||
So, if you still think you would like to compile from source, here are the steps:
|
So, if you are on another platform (e.g. i686, ARM) or would like to compile from source, here are the steps:
|
||||||
|
|
||||||
* Get and build linuxdeployqt e.g., using Qt 5.7.0 (you could use this [Qt Creator AppImage](https://bintray.com/probono/AppImages/QtCreator#files) for this)
|
* Get and build linuxdeployqt e.g., using Qt 5.7.0 (you could use this [Qt Creator AppImage](https://bintray.com/probono/AppImages/QtCreator#files) for this)
|
||||||
|
|
||||||
@@ -12,10 +12,16 @@ git clone https://github.com/probonopd/linuxdeployqt.git
|
|||||||
# Then build in Qt Creator, or use
|
# Then build in Qt Creator, or use
|
||||||
export PATH=$(readlink -f /tmp/.mount_QtCreator-*-x86_64/*/gcc_64/bin/):$PATH
|
export PATH=$(readlink -f /tmp/.mount_QtCreator-*-x86_64/*/gcc_64/bin/):$PATH
|
||||||
cd linuxdeployqt
|
cd linuxdeployqt
|
||||||
qmake linuxdeployqt.pro
|
qmake
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Optional if you want to install `linuxdeployqt` into your Qt installation, and make it a part of your Qt just like any other tool (qmake, etc.)
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
* Build and install [patchelf](https://nixos.org/patchelf.html) (a small utility to modify the dynamic linker and RPATH of ELF executables; similar to `install_name_tool` on macOS). To learn more about this, see http://blog.qt.io/blog/2011/10/28/rpath-and-runpath/
|
* Build and install [patchelf](https://nixos.org/patchelf.html) (a small utility to modify the dynamic linker and RPATH of ELF executables; similar to `install_name_tool` on macOS). To learn more about this, see http://blog.qt.io/blog/2011/10/28/rpath-and-runpath/
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# linuxdeployqt [](https://travis-ci.org/probonopd/linuxdeployqt) [](http://discourse.appimage.org/t/linuxdeployqt-new-linux-deployment-tool-for-qt/57) [](https://gitter.im/probonopd/AppImageKit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://webchat.freenode.net/?channels=AppImage)
|
# linuxdeployqt [](https://travis-ci.org/probonopd/linuxdeployqt) [](https://www.codacy.com/app/probonopd/linuxdeployqt?utm_source=github.com&utm_medium=referral&utm_content=probonopd/linuxdeployqt&utm_campaign=Badge_Grade) [](http://discourse.appimage.org/t/linuxdeployqt-new-linux-deployment-tool-for-qt/57) [](https://gitter.im/probonopd/AppImageKit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://webchat.freenode.net/?channels=AppImage)
|
||||||
|
|
||||||
This Linux Deployment Tool for Qt, `linuxdeployqt`, takes an application as input and makes it self-contained by copying in the Qt libraries and plugins that the application uses into a bundle. This can optionally be put into an [AppImage](http://appimage.org/), and, using [fpm](https://github.com/probonopd/linuxdeployqt/issues/9), into cross-distro deb and rpm packages.
|
This Linux Deployment Tool for Qt, `linuxdeployqt`, takes an application as input and makes it self-contained by copying in the Qt libraries and plugins that the application uses into a bundle. This can optionally be put into an [AppImage](http://appimage.org/), and, using [fpm](https://github.com/probonopd/linuxdeployqt/issues/9), into cross-distro deb and rpm packages.
|
||||||
|
|
||||||
@@ -18,27 +18,6 @@ Please download __linuxdeployqt-x86_64.AppImage__ from the [Releases](https://gi
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
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:__ 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
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```
|
|
||||||
find $HOME/build-*-*_Qt_* \( -name "moc_*" -or -name "*.o" -or -name "qrc_*" -or -name "Makefile*" -or -name "*.a" \) -exec rm {} \;
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you could use `$DESTDIR`.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: linuxdeployqt app-binary [options]
|
Usage: linuxdeployqt app-binary [options]
|
||||||
|
|
||||||
@@ -49,8 +28,9 @@ Options:
|
|||||||
-no-strip : Don't run 'strip' on the binaries
|
-no-strip : Don't run 'strip' on the binaries
|
||||||
-bundle-non-qt-libs : Also bundle non-core, non-Qt libraries
|
-bundle-non-qt-libs : Also bundle non-core, non-Qt libraries
|
||||||
-executable=<path> : Let the given executable use the deployed libraries too
|
-executable=<path> : Let the given executable use the deployed libraries too
|
||||||
-qmldir=<path> : Scan for QML imports in the given path
|
-qmldir=<path> : 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
|
-always-overwrite : Copy files even if the target file exists
|
||||||
|
-qmake=<path> : The qmake executable to use
|
||||||
-no-translations : Skip deployment of translations
|
-no-translations : Skip deployment of translations
|
||||||
|
|
||||||
linuxdeployqt takes an application as input and makes it
|
linuxdeployqt takes an application as input and makes it
|
||||||
@@ -58,6 +38,46 @@ self-contained by copying in the Qt libraries and plugins that
|
|||||||
the application uses.
|
the application uses.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Simplest example
|
||||||
|
|
||||||
|
Given that a desktop file should be provided with an AppImage, `linuxdeployqt` can use that to determine the parameters of the build.
|
||||||
|
|
||||||
|
`linuxdeployqt ./path/to/appdir/usr/share/application_name.desktop`
|
||||||
|
|
||||||
|
Where the _desktop_ file specifies the executable to be run (with `EXEC=`), the name of the applications and an icon.
|
||||||
|
See [desktop file specification](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html).
|
||||||
|
|
||||||
|
For a more detailed example, see "Using linuxdeployqt with Travis CI" below.
|
||||||
|
|
||||||
|
#### Checking library inclusion
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
#### QMake configuration
|
||||||
|
|
||||||
|
__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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
#### Remove unecessary files
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```
|
||||||
|
find $HOME/build-*-*_Qt_* \( -name "moc_*" -or -name "*.o" -or -name "qrc_*" -or -name "Makefile*" -or -name "*.a" \) -exec rm {} \;
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you could use `$DESTDIR`.
|
||||||
|
|
||||||
## Using linuxdeployqt with Travis CI
|
## Using linuxdeployqt with Travis CI
|
||||||
|
|
||||||
A common use case for `linuxdeployqt` is to use it on Travis CI after the `make` command. The following example illustrates how to use `linuxdeployqt` with Travis CI. Create a `.travis.yml` file similar to this one (be sure to customize it, e.g., change `APPNAME` to the name of your application as it is spelled in the `Name=` entry of the `.desktop` file):
|
A common use case for `linuxdeployqt` is to use it on Travis CI after the `make` command. The following example illustrates how to use `linuxdeployqt` with Travis CI. Create a `.travis.yml` file similar to this one (be sure to customize it, e.g., change `APPNAME` to the name of your application as it is spelled in the `Name=` entry of the `.desktop` file):
|
||||||
@@ -69,24 +89,24 @@ sudo: require
|
|||||||
dist: trusty
|
dist: trusty
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y
|
- sudo add-apt-repository ppa:beineri/opt-qt59-trusty -y
|
||||||
- sudo apt-get update -qq
|
- sudo apt-get update -qq
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- sudo apt-get -y install qt58base
|
- sudo apt-get -y install qt59base
|
||||||
- source /opt/qt*/bin/qt*-env.sh
|
- source /opt/qt*/bin/qt*-env.sh
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- qmake PREFIX=/usr
|
- qmake PREFIX=/usr
|
||||||
- make -j$(nproc)
|
- make -j$(nproc)
|
||||||
- make INSTALL_ROOT=appdir install ; find appdir/
|
- 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
|
- chmod a+x linuxdeployqt*.AppImage
|
||||||
- unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
|
- 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 -bundle-non-qt-libs
|
||||||
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage
|
- ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage
|
||||||
|
|
||||||
|
after_success:
|
||||||
- find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq
|
- 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
|
- curl --upload-file ./APPNAME*.AppImage https://transfer.sh/APPNAME-git.$(git rev-parse --short HEAD)-x86_64.AppImage
|
||||||
```
|
```
|
||||||
@@ -95,8 +115,14 @@ When you save your change, then Travis CI should build and upload an AppImage fo
|
|||||||
|
|
||||||
For this to work, you need to enable Travis CI for your repository as [described here](https://travis-ci.org/getting_started) __prior to merging this__, if you haven't already done so.
|
For this to work, you need to enable Travis CI for your repository as [described here](https://travis-ci.org/getting_started) __prior to merging this__, if you haven't already done so.
|
||||||
|
|
||||||
|
By default, qmake `.pro` files generated by Qt Creator unfortunately don't support `make install` out of the box. In this case you will get
|
||||||
|
|
||||||
Note that if `qmake` does not allow for `make install` or does not install the desktop file and icon, then change it similar to https://github.com/probonopd/FeedTheMonkey/blob/master/FeedTheMonkey.pro.
|
```
|
||||||
|
make: Nothing to be done for `install'.
|
||||||
|
find: `appdir/': No such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
If `qmake` does not allow for `make install` or does not install the desktop file and icon, then you need to change your `.pro` file it similar to https://github.com/probonopd/FeedTheMonkey/blob/master/FeedTheMonkey.pro.
|
||||||
|
|
||||||
```
|
```
|
||||||
- make INSTALL_ROOT=appdir install ; find appdir/
|
- make INSTALL_ROOT=appdir install ; find appdir/
|
||||||
|
|||||||
+1
-2
@@ -1,2 +1 @@
|
|||||||
TEMPLATE = subdirs
|
load(qt_parts)
|
||||||
SUBDIRS = linuxdeployqt
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
QT = core
|
|
||||||
SOURCES += main.cpp ../shared/shared.cpp
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
TEMPLATE = aux
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
%modules = (
|
||||||
|
);
|
||||||
|
|
||||||
|
%moduleheaders = (
|
||||||
|
);
|
||||||
+2
-2
@@ -10,8 +10,8 @@ mkdir -p linuxdeployqt.AppDir/usr/bin/
|
|||||||
cp /usr/bin/patchelf /usr/local/bin/{appimagetool,mksquashfs,zsyncmake} linuxdeployqt.AppDir/usr/bin/
|
cp /usr/bin/patchelf /usr/local/bin/{appimagetool,mksquashfs,zsyncmake} linuxdeployqt.AppDir/usr/bin/
|
||||||
find linuxdeployqt.AppDir/
|
find linuxdeployqt.AppDir/
|
||||||
export VERSION=continuous
|
export VERSION=continuous
|
||||||
cp ./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/usr/bin/
|
cp ./bin/linuxdeployqt linuxdeployqt.AppDir/usr/bin/
|
||||||
./linuxdeployqt/linuxdeployqt linuxdeployqt.AppDir/linuxdeployqt.desktop -verbose=3 -appimage
|
./bin/linuxdeployqt linuxdeployqt.AppDir/linuxdeployqt.desktop -verbose=3 -appimage
|
||||||
ls -lh
|
ls -lh
|
||||||
find *.AppDir
|
find *.AppDir
|
||||||
xpra start :99
|
xpra start :99
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
SUBDIRS += \
|
||||||
|
QtQuickControls2Application \
|
||||||
|
QtWebEngineApplication \
|
||||||
|
QtWidgetsApplication
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
tests-ci.sh \
|
||||||
|
tests-environment.sh \
|
||||||
|
tests.sh
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
option(host_build)
|
||||||
|
|
||||||
|
QT = core
|
||||||
|
CONFIG += console
|
||||||
|
|
||||||
|
TARGET = linuxdeployqt
|
||||||
|
VERSION = $$MODULE_VERSION
|
||||||
|
|
||||||
|
DEFINES += BUILD_LINUXDEPLOYQT
|
||||||
|
|
||||||
|
load(qt_tool)
|
||||||
|
|
||||||
|
HEADERS += shared.h
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
shared.cpp
|
||||||
|
|
||||||
|
DEFINES -= QT_USE_QSTRINGBUILDER #leads to compile errors if not disabled
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
#include "../shared/shared.h"
|
#include "shared.h"
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
@@ -188,7 +188,7 @@ int main(int argc, char **argv)
|
|||||||
if (QDir().exists(appBinaryPath)) {
|
if (QDir().exists(appBinaryPath)) {
|
||||||
qDebug() << "app-binary:" << appBinaryPath;
|
qDebug() << "app-binary:" << appBinaryPath;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Error: Could not find app-binary" << appBinaryPath;
|
LogError() << "Error: Could not find app-binary" << appBinaryPath;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +202,11 @@ int main(int argc, char **argv)
|
|||||||
QString relativePrefix = fhsPrefix.replace(appDirPath+"/", "");
|
QString relativePrefix = fhsPrefix.replace(appDirPath+"/", "");
|
||||||
relativeBinPath = relativePrefix + "/bin/" + appName;
|
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.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
qDebug() << "appDirPath:" << appDirPath;
|
qDebug() << "appDirPath:" << appDirPath;
|
||||||
qDebug() << "relativeBinPath:" << relativeBinPath;
|
qDebug() << "relativeBinPath:" << relativeBinPath;
|
||||||
|
|
||||||
@@ -50,18 +50,18 @@ bool runStripEnabled = true;
|
|||||||
bool bundleAllButCoreLibs = false;
|
bool bundleAllButCoreLibs = false;
|
||||||
bool fhsLikeMode = false;
|
bool fhsLikeMode = false;
|
||||||
QString fhsPrefix;
|
QString fhsPrefix;
|
||||||
bool alwaysOwerwriteEnabled = false;
|
static bool alwaysOwerwriteEnabled = false;
|
||||||
QStringList librarySearchPath;
|
static QStringList librarySearchPath;
|
||||||
bool appstoreCompliant = false;
|
static bool appstoreCompliant = false;
|
||||||
int logLevel = 1;
|
int logLevel = 1;
|
||||||
bool qtDetected = 0;
|
static int qtDetected = 0;
|
||||||
bool qtDetectionComplete = 0; // As long as Qt is not detected yet, ldd may encounter "not found" messages, continue anyway
|
static bool qtDetectionComplete = 0; // As long as Qt is not detected yet, ldd may encounter "not found" messages, continue anyway
|
||||||
bool deployLibrary = false;
|
static bool deployLibrary = false;
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
QMap<QString,QString> qtToBeBundledInfo;
|
static QMap<QString,QString> qtToBeBundledInfo;
|
||||||
|
|
||||||
enum QtModule
|
enum QtModule
|
||||||
#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
|
#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
|
||||||
@@ -202,7 +202,7 @@ QDebug operator<<(QDebug debug, const LibraryInfo &info)
|
|||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString bundleLibraryDirectory;
|
static QString bundleLibraryDirectory;
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const AppDirInfo &info)
|
inline QDebug operator<<(QDebug debug, const AppDirInfo &info)
|
||||||
{
|
{
|
||||||
@@ -298,6 +298,14 @@ LddInfo findDependencyInfo(const QString &binaryPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (QString outputLine, outputLines) {
|
foreach (QString outputLine, outputLines) {
|
||||||
|
|
||||||
|
if(outputLine.contains("libQt5")){
|
||||||
|
qtDetected = 5;
|
||||||
|
}
|
||||||
|
if(outputLine.contains("libQtCore.so.4")){
|
||||||
|
qtDetected = 4;
|
||||||
|
}
|
||||||
|
|
||||||
// LogDebug() << "ldd outputLine:" << outputLine;
|
// LogDebug() << "ldd outputLine:" << outputLine;
|
||||||
if ((outputLine.contains("not found")) && (qtDetectionComplete == 1)){
|
if ((outputLine.contains("not found")) && (qtDetectionComplete == 1)){
|
||||||
LogError() << "ldd outputLine:" << outputLine.replace("\t", "");
|
LogError() << "ldd outputLine:" << outputLine.replace("\t", "");
|
||||||
@@ -374,7 +382,7 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
QStringList excludelist;
|
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" << "libgdk-x11-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" << "libgssapi_krb5.so.2" << "libgtk-x11-2.0.so.0" << "libhcrypto.so.4" << "libhx509.so.5" << "libICE.so.6" << "libidn.so.11" << "libk5crypto.so.3" << "libkeyutils.so.1" << "libkrb5.so.26" << "libkrb5.so.3" << "libkrb5support.so.0" << "libm.so.6" << "libnss3.so" << "libnssutil3.so" << "libp11-kit.so.0" << "libpangoft2-1.0.so.0" << "libpangocairo-1.0.so.0" << "libpango-1.0.so.0" << "libpcre.so.3" << "libpthread.so.0" << "libresolv.so.2" << "libroken.so.18" << "librt.so.1" << "libselinux.so.1" << "libSM.so.6" << "libstdc++.so.6" << "libusb-1.0.so.0" << "libuuid.so.1" << "libwind.so.0" << "libX11.so.6" << "libxcb.so.1" << "libz.so.1";
|
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" << "libgdk-x11-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" << "libgssapi_krb5.so.2" << "libgtk-x11-2.0.so.0" << "libICE.so.6" << "libidn.so.11" << "libk5crypto.so.3" << "libkeyutils.so.1" << "libm.so.6" << "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" << "libselinux.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;
|
LogDebug() << "excludelist:" << excludelist;
|
||||||
if (! trimmed.contains("libicu")) {
|
if (! trimmed.contains("libicu")) {
|
||||||
if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName())) {
|
if (containsHowOften(excludelist, QFileInfo(trimmed).completeBaseName())) {
|
||||||
@@ -577,53 +585,6 @@ QList<LibraryInfo> getQtLibrariesForPaths(const QStringList &paths, const QStrin
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList getBinaryDependencies(const QString executablePath,
|
|
||||||
const QString &path,
|
|
||||||
const QList<QString> &additionalBinariesContainingRpaths)
|
|
||||||
{
|
|
||||||
QStringList binaries;
|
|
||||||
|
|
||||||
const QList<DylibInfo> dependencies = findDependencyInfo(path).dependencies;
|
|
||||||
|
|
||||||
bool rpathsLoaded = false;
|
|
||||||
QSet<QString> rpaths;
|
|
||||||
|
|
||||||
// return bundle-local dependencies. (those starting with @executable_path)
|
|
||||||
foreach (const DylibInfo &info, dependencies) {
|
|
||||||
QString trimmedLine = info.binaryPath;
|
|
||||||
if (trimmedLine.startsWith("@executable_path/")) {
|
|
||||||
QString binary = QDir::cleanPath(executablePath + trimmedLine.mid(QStringLiteral("@executable_path/").length()));
|
|
||||||
if (binary != path)
|
|
||||||
binaries.append(binary);
|
|
||||||
} else if (trimmedLine.startsWith("@rpath/")) {
|
|
||||||
if (!rpathsLoaded) {
|
|
||||||
rpaths = getBinaryRPaths(path, true, executablePath);
|
|
||||||
foreach (const QString &binaryPath, additionalBinariesContainingRpaths) {
|
|
||||||
QSet<QString> binaryRpaths = getBinaryRPaths(binaryPath, true);
|
|
||||||
rpaths += binaryRpaths;
|
|
||||||
}
|
|
||||||
rpathsLoaded = true;
|
|
||||||
}
|
|
||||||
bool resolved = false;
|
|
||||||
foreach (const QString &rpath, rpaths) {
|
|
||||||
QString binary = QDir::cleanPath(rpath + "/" + trimmedLine.mid(QStringLiteral("@rpath/").length()));
|
|
||||||
LogDebug() << "Checking for" << binary;
|
|
||||||
if (QFile::exists(binary)) {
|
|
||||||
binaries.append(binary);
|
|
||||||
resolved = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!resolved && !rpaths.isEmpty()) {
|
|
||||||
LogError() << "Cannot resolve rpath" << trimmedLine;
|
|
||||||
LogError() << " using" << rpaths;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return binaries;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copies everything _inside_ sourcePath to destinationPath
|
// copies everything _inside_ sourcePath to destinationPath
|
||||||
bool recursiveCopy(const QString &sourcePath, const QString &destinationPath)
|
bool recursiveCopy(const QString &sourcePath, const QString &destinationPath)
|
||||||
{
|
{
|
||||||
@@ -717,26 +678,28 @@ QString copyDylib(const LibraryInfo &library, const QString path)
|
|||||||
return dylibDestinationBinaryPath;
|
return dylibDestinationBinaryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runPatchelf(QStringList options)
|
QString runPatchelf(QStringList options)
|
||||||
{
|
{
|
||||||
QProcess patchelftool;
|
QProcess patchelftool;
|
||||||
|
LogDebug() << "options:" << options;
|
||||||
patchelftool.start("patchelf", options);
|
patchelftool.start("patchelf", options);
|
||||||
if (!patchelftool.waitForStarted()) {
|
if (!patchelftool.waitForStarted()) {
|
||||||
if(patchelftool.errorString().contains("execvp: No such file or directory")){
|
if(patchelftool.errorString().contains("No such file or directory")){
|
||||||
LogError() << "Could not start patchelf.";
|
LogError() << "Could not start patchelf.";
|
||||||
LogError() << "Make sure it is installed on your $PATH, e.g., in /usr/local/bin.";
|
LogError() << "Make sure it is installed on your $PATH, e.g., in /usr/local/bin.";
|
||||||
LogError() << "You can get it from https://nixos.org/patchelf.html.";
|
LogError() << "You can get it from https://nixos.org/patchelf.html.";
|
||||||
} else {
|
} else {
|
||||||
LogError() << "Could not start patchelftool. Process error is" << patchelftool.errorString();
|
LogError() << "Could not start patchelf tool. Process error is" << patchelftool.errorString();
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
patchelftool.waitForFinished();
|
patchelftool.waitForFinished();
|
||||||
if (patchelftool.exitCode() != 0) {
|
if (patchelftool.exitCode() != 0) {
|
||||||
LogError() << "runPatchelf:" << patchelftool.readAllStandardError();
|
LogError() << "runPatchelf:" << patchelftool.readAllStandardError();
|
||||||
LogError() << "runPatchelf:" << patchelftool.readAllStandardOutput();
|
// LogError() << "runPatchelf:" << patchelftool.readAllStandardOutput();
|
||||||
// exit(1); // Do not exit because this could be a script that patchelf can't work on
|
// exit(1); // Do not exit because this could be a script that patchelf can't work on
|
||||||
}
|
}
|
||||||
|
return(patchelftool.readAllStandardOutput().trimmed());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool patchQtCore(const QString &path, const QString &variable, const QString &value)
|
bool patchQtCore(const QString &path, const QString &variable, const QString &value)
|
||||||
@@ -789,6 +752,21 @@ bool patchQtCore(const QString &path, const QString &variable, const QString &va
|
|||||||
|
|
||||||
void changeIdentification(const QString &id, const QString &binaryPath)
|
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("/")){
|
||||||
|
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
|
||||||
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
|
QString oldPath = env.value("LD_LIBRARY_PATH");
|
||||||
|
if (not oldPath.contains(oldRpath)){
|
||||||
|
QString newPath = oldRpath + ":" + oldPath; // FIXME: If we use a ldd replacement, we still need to observe this path
|
||||||
|
// FIXME: Directory layout might be different for system Qt; cannot assume lib/ to always be inside the Qt directory
|
||||||
|
LogDebug() << "Added to LD_LIBRARY_PATH:" << newPath;
|
||||||
|
setenv("LD_LIBRARY_PATH",newPath.toUtf8().constData(),1);
|
||||||
|
}
|
||||||
|
}
|
||||||
LogNormal() << "Changing rpath in" << binaryPath << "to" << id;
|
LogNormal() << "Changing rpath in" << binaryPath << "to" << id;
|
||||||
runPatchelf(QStringList() << "--set-rpath" << id << binaryPath);
|
runPatchelf(QStringList() << "--set-rpath" << id << binaryPath);
|
||||||
|
|
||||||
@@ -942,7 +920,7 @@ DeploymentInfo deployQtLibraries(QList<LibraryInfo> libraries,
|
|||||||
deploymentInfo.qtPath = library.libraryDirectory;
|
deploymentInfo.qtPath = library.libraryDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(library.libraryName.contains("libQt") and library.libraryName.contains("Widgets.so")) {
|
if(library.libraryName.contains("libQt") and library.libraryName.contains("Widgets.so")) {
|
||||||
deploymentInfo.requiresQtWidgetsLibrary = true;
|
deploymentInfo.requiresQtWidgetsLibrary = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,15 +992,6 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
|
|||||||
|
|
||||||
// Find out whether Qt is a dependency of the application to be bundled
|
// Find out whether Qt is a dependency of the application to be bundled
|
||||||
LddInfo lddInfo = findDependencyInfo(appBinaryPath);
|
LddInfo lddInfo = findDependencyInfo(appBinaryPath);
|
||||||
foreach (const DylibInfo dep, lddInfo.dependencies) {
|
|
||||||
LogDebug() << "dep.binaryPath" << dep.binaryPath;
|
|
||||||
if(dep.binaryPath.contains("libQt5")){
|
|
||||||
qtDetected = 5;
|
|
||||||
}
|
|
||||||
if(dep.binaryPath.contains("libQtCore.so.4")){
|
|
||||||
qtDetected = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(qtDetected != 0){
|
if(qtDetected != 0){
|
||||||
|
|
||||||
@@ -1032,21 +1001,22 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
|
|||||||
// Use the qmake executable passed in by the user:
|
// Use the qmake executable passed in by the user:
|
||||||
QString qmakePath = qmake;
|
QString qmakePath = 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()) {
|
if (qmakePath.isEmpty()) {
|
||||||
qmakePath = QStandardPaths::findExecutable("qmake");
|
// Try to find a version specific qmake first
|
||||||
}
|
// openSUSE has qmake for Qt 4 and qmake-qt5 for Qt 5
|
||||||
|
// Qt 4 on Fedora comes with suffix -qt4
|
||||||
// But openSUSE has qmake for Qt 4 and qmake-qt5 for Qt 5
|
// http://www.geopsy.org/wiki/index.php/Installing_Qt_binary_packages
|
||||||
// Qt 4 on Fedora comes with suffix -qt4
|
|
||||||
// http://www.geopsy.org/wiki/index.php/Installing_Qt_binary_packages
|
|
||||||
if(qmakePath.isEmpty()){
|
|
||||||
if(qtDetected == 5){
|
if(qtDetected == 5){
|
||||||
qmakePath = QStandardPaths::findExecutable("qmake-qt5");
|
qmakePath = QStandardPaths::findExecutable("qmake-qt5");
|
||||||
}
|
LogDebug() << "qmake 5";
|
||||||
if(qtDetected == 4){
|
} else if(qtDetected == 4){
|
||||||
qmakePath = QStandardPaths::findExecutable("qmake-qt4");
|
qmakePath = QStandardPaths::findExecutable("qmake-qt4");
|
||||||
|
LogDebug() << "qmake 4";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(qmakePath == ""){
|
||||||
|
// The upstream name of the binary is "qmake", for Qt 4 and Qt 5
|
||||||
|
qmakePath = QStandardPaths::findExecutable("qmake");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1055,6 +1025,7 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogNormal() << "Using qmake: " << qmakePath;
|
||||||
QString output = captureOutput(qmakePath + " -query");
|
QString output = captureOutput(qmakePath + " -query");
|
||||||
LogDebug() << "-query output from qmake:" << output;
|
LogDebug() << "-query output from qmake:" << output;
|
||||||
|
|
||||||
@@ -1089,10 +1060,14 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
|
|||||||
/* From now on let ldd exit if it doesn't find something */
|
/* From now on let ldd exit if it doesn't find something */
|
||||||
qtDetectionComplete = 1;
|
qtDetectionComplete = 1;
|
||||||
|
|
||||||
|
QString libraryPath;
|
||||||
if(fhsLikeMode == false){
|
if(fhsLikeMode == false){
|
||||||
changeIdentification("$ORIGIN/lib/" + bundleLibraryDirectory, QFileInfo(applicationBundle.binaryPath).canonicalFilePath());
|
libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("lib/" + bundleLibraryDirectory);
|
||||||
} else {
|
} else {
|
||||||
changeIdentification("$ORIGIN/../lib/" + bundleLibraryDirectory, QFileInfo(applicationBundle.binaryPath).canonicalFilePath());
|
libraryPath = QFileInfo(applicationBundle.binaryPath).dir().filePath("../lib/" + bundleLibraryDirectory);
|
||||||
|
}
|
||||||
|
foreach (const QString &executable, QStringList() << applicationBundle.binaryPath << additionalExecutables) {
|
||||||
|
changeIdentification("$ORIGIN/" + QFileInfo(executable).dir().relativeFilePath(libraryPath) + "/" + bundleLibraryDirectory, QFileInfo(executable).canonicalFilePath());
|
||||||
}
|
}
|
||||||
applicationBundle.libraryPaths = findAppLibraries(appDirPath);
|
applicationBundle.libraryPaths = findAppLibraries(appDirPath);
|
||||||
LogDebug() << "applicationBundle.libraryPaths:" << applicationBundle.libraryPaths;
|
LogDebug() << "applicationBundle.libraryPaths:" << applicationBundle.libraryPaths;
|
||||||
@@ -1288,21 +1263,21 @@ void createQtConf(const QString &appDirPath)
|
|||||||
// See https://github.com/probonopd/linuxdeployqt/issues/ 75, 98, 99
|
// See https://github.com/probonopd/linuxdeployqt/issues/ 75, 98, 99
|
||||||
QByteArray contents;
|
QByteArray contents;
|
||||||
if(fhsLikeMode){
|
if(fhsLikeMode){
|
||||||
contents = "# Generated by linuxdeployqt\n"
|
contents = "# Generated by linuxdeployqt\n"
|
||||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||||
"[Paths]\n"
|
"[Paths]\n"
|
||||||
"Prefix = ../\n"
|
"Prefix = ../\n"
|
||||||
"Plugins = plugins\n"
|
"Plugins = plugins\n"
|
||||||
"Imports = qml\n"
|
"Imports = qml\n"
|
||||||
"Qml2Imports = qml\n";
|
"Qml2Imports = qml\n";
|
||||||
} else {
|
} else {
|
||||||
contents = "# Generated by linuxdeployqt\n"
|
contents = "# Generated by linuxdeployqt\n"
|
||||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||||
"[Paths]\n"
|
"[Paths]\n"
|
||||||
"Prefix = ./\n"
|
"Prefix = ./\n"
|
||||||
"Plugins = plugins\n"
|
"Plugins = plugins\n"
|
||||||
"Imports = qml\n"
|
"Imports = qml\n"
|
||||||
"Qml2Imports = qml\n";
|
"Qml2Imports = qml\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filePath = appDirPath + "/"; // Is picked up when placed next to the main executable
|
QString filePath = appDirPath + "/"; // Is picked up when placed next to the main executable
|
||||||
@@ -1629,7 +1604,7 @@ void deployTranslations(const QString &appDirPath, quint64 usedQtModules)
|
|||||||
LogDebug() << "Deploying translations...";
|
LogDebug() << "Deploying translations...";
|
||||||
QString qtTranslationsPath = qtToBeBundledInfo.value("QT_INSTALL_TRANSLATIONS");
|
QString qtTranslationsPath = qtToBeBundledInfo.value("QT_INSTALL_TRANSLATIONS");
|
||||||
if (qtTranslationsPath.isEmpty() || !QFile::exists(qtTranslationsPath)) {
|
if (qtTranslationsPath.isEmpty() || !QFile::exists(qtTranslationsPath)) {
|
||||||
LogError() << "Qt translations path could not be determined";
|
LogDebug() << "Qt translations path could not be determined, maybe there are no translations?";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
|
SUBDIRS += linuxdeployqt
|
||||||
Reference in New Issue
Block a user