Merge branch 'master' into master

This commit is contained in:
TheAssassin
2017-10-29 13:46:54 +01:00
committed by GitHub
6 changed files with 133 additions and 92 deletions
+17 -3
View File
@@ -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()) {
+78 -77
View File
@@ -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;
+3 -1
View File
@@ -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);