Merge branch 'master' into master
This commit is contained in:
@@ -55,14 +55,16 @@ 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() << " -no-translations : Skip deployment of translations.";
|
||||
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
|
||||
@@ -86,6 +88,12 @@ int main(int argc, char **argv)
|
||||
* to do when using linuxdeployqt. */
|
||||
if (firstArgument.endsWith(".desktop")){
|
||||
qDebug() << "Desktop file as first argument:" << firstArgument;
|
||||
|
||||
/* Check if the desktop file really exists */
|
||||
if (! QFile::exists(firstArgument)) {
|
||||
LogError() << "Desktop file in first argument does not exist!";
|
||||
return 1;
|
||||
}
|
||||
QSettings * settings = 0;
|
||||
settings = new QSettings(firstArgument, QSettings::IniFormat);
|
||||
desktopExecEntry = settings->value("Desktop Entry/Exec", "r").toString().split(' ').first().split('/').last().trimmed();
|
||||
@@ -171,6 +179,7 @@ int main(int argc, char **argv)
|
||||
bool qmldirArgumentUsed = false;
|
||||
bool skipTranslations = 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. */
|
||||
@@ -365,6 +374,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 == QByteArray("-no-translations")) {
|
||||
LogDebug() << "Argument found:" << argument;
|
||||
skipTranslations = true;
|
||||
@@ -381,7 +394,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()) {
|
||||
|
||||
@@ -61,7 +61,7 @@ bool deployLibrary = false;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
QMap<QString,QString> qtToBeBundledInfo;
|
||||
static QMap<QString,QString> qtToBeBundledInfo;
|
||||
|
||||
enum QtModule
|
||||
#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
|
||||
@@ -202,7 +202,7 @@ QDebug operator<<(QDebug debug, const LibraryInfo &info)
|
||||
return debug;
|
||||
}
|
||||
|
||||
QString bundleLibraryDirectory;
|
||||
static QString bundleLibraryDirectory;
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const AppDirInfo &info)
|
||||
{
|
||||
@@ -217,20 +217,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)
|
||||
@@ -298,6 +298,14 @@ LddInfo findDependencyInfo(const QString &binaryPath)
|
||||
}
|
||||
|
||||
foreach (QString outputLine, outputLines) {
|
||||
|
||||
if(outputLine.contains("libQt5")){
|
||||
qtDetected = 5;
|
||||
}
|
||||
if(outputLine.contains("libQtCore.so.4")){
|
||||
qtDetected = 4;
|
||||
}
|
||||
|
||||
// LogDebug() << "ldd outputLine:" << outputLine;
|
||||
if ((outputLine.contains("not found")) && (qtDetectionComplete == 1)){
|
||||
LogError() << "ldd outputLine:" << outputLine.replace("\t", "");
|
||||
@@ -375,7 +383,7 @@ LibraryInfo parseLddLibraryLine(const QString &line, const QString &appDirPath,
|
||||
*/
|
||||
|
||||
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" << "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";
|
||||
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" << "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())) {
|
||||
@@ -749,16 +757,16 @@ void changeIdentification(const QString &id, const QString &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);
|
||||
}
|
||||
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;
|
||||
runPatchelf(QStringList() << "--set-rpath" << id << binaryPath);
|
||||
@@ -912,8 +920,8 @@ DeploymentInfo deployQtLibraries(QList<LibraryInfo> libraries,
|
||||
LogNormal() << "Setting deploymentInfo.qtPath to:" << 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;
|
||||
}
|
||||
|
||||
@@ -974,7 +982,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;
|
||||
|
||||
@@ -985,39 +993,32 @@ DeploymentInfo deployQtLibraries(const QString &appDirPath, const QStringList &a
|
||||
|
||||
// Find out whether Qt is a dependency of the application to be bundled
|
||||
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){
|
||||
|
||||
// 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;
|
||||
|
||||
if (qmakePath.isEmpty()) {
|
||||
// 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
|
||||
// http://www.geopsy.org/wiki/index.php/Installing_Qt_binary_packages
|
||||
if(qtDetected == 5){
|
||||
qmakePath = QStandardPaths::findExecutable("qmake-qt5");
|
||||
LogDebug() << "qmake 5";
|
||||
} else if(qtDetected == 4){
|
||||
qmakePath = QStandardPaths::findExecutable("qmake-qt4");
|
||||
LogDebug() << "qmake 4";
|
||||
}
|
||||
|
||||
// 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
|
||||
// http://www.geopsy.org/wiki/index.php/Installing_Qt_binary_packages
|
||||
if(qtDetected == 5){
|
||||
qmakePath = QStandardPaths::findExecutable("qmake-qt5");
|
||||
LogDebug() << "qmake 5";
|
||||
} else if(qtDetected == 4){
|
||||
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");
|
||||
if(qmakePath == ""){
|
||||
// The upstream name of the binary is "qmake", for Qt 4 and Qt 5
|
||||
qmakePath = QStandardPaths::findExecutable("qmake");
|
||||
}
|
||||
}
|
||||
|
||||
if(qmakePath == ""){
|
||||
@@ -1122,7 +1123,7 @@ void deployPlugins(const AppDirInfo &appDirInfo, const QString &pluginSourcePath
|
||||
}
|
||||
} else {
|
||||
pluginList.append(QStringLiteral("imageformats/") + plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,8 +1133,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")) {
|
||||
@@ -1175,7 +1176,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
|
||||
@@ -1232,7 +1233,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) {
|
||||
@@ -1251,7 +1252,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());
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1263,23 +1264,23 @@ void createQtConf(const QString &appDirPath)
|
||||
// See https://github.com/probonopd/linuxdeployqt/issues/ 75, 98, 99
|
||||
QByteArray contents;
|
||||
if(fhsLikeMode){
|
||||
contents = "# Generated by linuxdeployqt\n"
|
||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||
"[Paths]\n"
|
||||
"Prefix = ../\n"
|
||||
"Plugins = plugins\n"
|
||||
"Imports = qml\n"
|
||||
"Qml2Imports = qml\n";
|
||||
contents = "# Generated by linuxdeployqt\n"
|
||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||
"[Paths]\n"
|
||||
"Prefix = ../\n"
|
||||
"Plugins = plugins\n"
|
||||
"Imports = qml\n"
|
||||
"Qml2Imports = qml\n";
|
||||
} else {
|
||||
contents = "# Generated by linuxdeployqt\n"
|
||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||
"[Paths]\n"
|
||||
"Prefix = ./\n"
|
||||
"Plugins = plugins\n"
|
||||
"Imports = qml\n"
|
||||
"Qml2Imports = qml\n";
|
||||
contents = "# Generated by linuxdeployqt\n"
|
||||
"# https://github.com/probonopd/linuxdeployqt/\n"
|
||||
"[Paths]\n"
|
||||
"Prefix = ./\n"
|
||||
"Plugins = plugins\n"
|
||||
"Imports = qml\n"
|
||||
"Qml2Imports = qml\n";
|
||||
}
|
||||
|
||||
|
||||
QString filePath = appDirPath + "/"; // Is picked up when placed next to the main executable
|
||||
QString fileName = QDir::cleanPath(appBinaryPath + "/../qt.conf");
|
||||
|
||||
@@ -1403,7 +1404,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;
|
||||
|
||||
@@ -114,7 +114,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 createQtConf(const QString &appDirPath);
|
||||
void createQtConfForQtWebEngineProcess(const QString &appDirPath);
|
||||
|
||||
Reference in New Issue
Block a user