summaryrefslogtreecommitdiffstats
path: root/src/macdeployqt
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-05-19 22:45:30 +0200
committerLiang Qi <liang.qi@qt.io>2016-05-19 22:45:30 +0200
commit5aa15fbed1375dfa7f19b0263e69e5bcf2c29ddc (patch)
tree34e1dc512dbdef33ab68d1f367bdd4c99153c053 /src/macdeployqt
parent6ef8d67413511f07abb4f71593ed6d8567f61ca8 (diff)
parent87cfa3b24f12ae4cd1ddbb5450b307b95334feb1 (diff)
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts: .qmake.conf Change-Id: I5fde87a1ac22e933c926e0d86996791a38d92c4e
Diffstat (limited to 'src/macdeployqt')
-rw-r--r--src/macdeployqt/shared/shared.cpp120
-rw-r--r--src/macdeployqt/shared/shared.h20
2 files changed, 91 insertions, 49 deletions
diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp
index 35dd1402b..3b0c954cc 100644
--- a/src/macdeployqt/shared/shared.cpp
+++ b/src/macdeployqt/shared/shared.cpp
@@ -46,6 +46,7 @@
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
+#include <QRegularExpression>
#include "shared.h"
#ifdef Q_OS_DARWIN
@@ -165,6 +166,56 @@ void patch_debugInInfoPlist(const QString &infoPlistPath)
infoPlist.write(contents);
}
+OtoolInfo findDependencyInfo(const QString &binaryPath)
+{
+ OtoolInfo info;
+ info.binaryPath = binaryPath;
+
+ LogDebug() << "Using otool:";
+ LogDebug() << " inspecting" << binaryPath;
+ QProcess otool;
+ otool.start("otool", QStringList() << "-L" << binaryPath);
+ otool.waitForFinished();
+
+ if (otool.exitCode() != 0) {
+ LogError() << otool.readAllStandardError();
+ }
+
+ static const QRegularExpression regexp(QStringLiteral(
+ "^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), "
+ "current version (\\d+\\.\\d+\\.\\d+)\\)$"));
+
+ QString output = otool.readAllStandardOutput();
+ QStringList outputLines = output.split("\n", QString::SkipEmptyParts);
+ outputLines.removeFirst(); // remove line containing the binary path
+ if (binaryPath.contains(".framework/") || binaryPath.endsWith(".dylib")) {
+ const auto match = regexp.match(outputLines.first());
+ if (match.hasMatch()) {
+ info.installName = match.captured(1);
+ info.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
+ info.currentVersion = QVersionNumber::fromString(match.captured(3));
+ } else {
+ LogError() << "Could not parse otool output line:" << outputLines.first();
+ }
+ outputLines.removeFirst();
+ }
+
+ for (const QString &outputLine : outputLines) {
+ const auto match = regexp.match(outputLine);
+ if (match.hasMatch()) {
+ DylibInfo dylib;
+ dylib.binaryPath = match.captured(1);
+ dylib.compatibilityVersion = QVersionNumber::fromString(match.captured(2));
+ dylib.currentVersion = QVersionNumber::fromString(match.captured(3));
+ info.dependencies << dylib;
+ } else {
+ LogError() << "Could not parse otool output line:" << outputLine;
+ }
+ }
+
+ return info;
+}
+
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
{
FrameworkInfo info;
@@ -231,13 +282,11 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
if (state == QtPath) {
// Check for library name part
if (part < parts.count() && parts.at(part).contains(".dylib ")) {
- info.installName += "/" + (qtPath + currentPart + "/").simplified();
- info.frameworkDirectory = info.installName;
+ info.frameworkDirectory += "/" + (qtPath + currentPart + "/").simplified();
state = DylibName;
continue;
} else if (part < parts.count() && parts.at(part).endsWith(".framework")) {
- info.installName += "/" + (qtPath + "lib/").simplified();
- info.frameworkDirectory = info.installName;
+ info.frameworkDirectory += "/" + (qtPath + "lib/").simplified();
state = FrameworkName;
continue;
} else if (trimmed.startsWith("/") == false) { // If the line does not contain a full path, the app is using a binary Qt package.
@@ -264,11 +313,10 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
++part;
continue;
} if (state == DylibName) {
- name = currentPart.split(" (compatibility").at(0);
+ name = currentPart;
info.isDylib = true;
info.frameworkName = name;
info.binaryName = name.left(name.indexOf('.')) + suffix + name.mid(name.indexOf('.'));
- info.installName += name;
info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName;
info.frameworkPath = info.frameworkDirectory + info.binaryName;
info.sourceFilePath = info.frameworkPath;
@@ -284,7 +332,6 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
info.binaryDirectory = "Versions/" + info.version;
info.binaryName = name + suffix;
info.binaryPath = "/" + info.binaryDirectory + "/" + info.binaryName;
- info.installName += info.frameworkName + "/" + info.binaryDirectory + "/" + name;
info.deployedInstallName = "@executable_path/../Frameworks/" + info.frameworkName + info.binaryPath;
info.frameworkPath = info.frameworkDirectory + info.frameworkName;
info.sourceFilePath = info.frameworkPath + info.binaryPath;
@@ -296,6 +343,9 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundl
}
}
+ info.installName = findDependencyInfo(info.sourceFilePath).installName;
+ if (info.installName.startsWith("@rpath/"))
+ info.deployedInstallName = info.installName;
return info;
}
@@ -395,11 +445,11 @@ QStringList findAppBundleFiles(const QString &appBundlePath, bool absolutePath =
return result;
}
-QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
+QList<FrameworkInfo> getQtFrameworks(const QList<DylibInfo> &dependencies, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
{
QList<FrameworkInfo> libraries;
- foreach(const QString line, otoolLines) {
- FrameworkInfo info = parseOtoolLibraryLine(line, appBundlePath, rpaths, useDebugLibs);
+ for (const DylibInfo &dylibInfo : dependencies) {
+ FrameworkInfo info = parseOtoolLibraryLine(dylibInfo.binaryPath, appBundlePath, rpaths, useDebugLibs);
if (info.frameworkName.isEmpty() == false) {
LogDebug() << "Adding framework:";
LogDebug() << info;
@@ -477,23 +527,8 @@ QSet<QString> getBinaryRPaths(const QString &path, bool resolve = true, QString
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
{
- LogDebug() << "Using otool:";
- LogDebug() << " inspecting" << path;
- QProcess otool;
- otool.start("otool", QStringList() << "-L" << path);
- otool.waitForFinished();
-
- if (otool.exitCode() != 0) {
- LogError() << otool.readAllStandardError();
- }
-
- QString output = otool.readAllStandardOutput();
- QStringList outputLines = output.split("\n");
- outputLines.removeFirst(); // remove line containing the binary path
- if (path.contains(".framework") || path.contains(".dylib"))
- outputLines.removeFirst(); // frameworks and dylibs print install name of themselves first.
-
- return getQtFrameworks(outputLines, appBundlePath, rpaths + getBinaryRPaths(path), useDebugLibs);
+ const OtoolInfo info = findDependencyInfo(path);
+ return getQtFrameworks(info.dependencies, appBundlePath, rpaths + getBinaryRPaths(path), useDebugLibs);
}
QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs)
@@ -517,24 +552,14 @@ QStringList getBinaryDependencies(const QString executablePath,
{
QStringList binaries;
- QProcess otool;
- otool.start("otool", QStringList() << "-L" << path);
- otool.waitForFinished();
-
- if (otool.exitCode() != 0) {
- LogError() << otool.readAllStandardError();
- }
-
- QString output = otool.readAllStandardOutput();
- QStringList outputLines = output.split("\n");
- outputLines.removeFirst(); // remove line containing the binary path
+ const auto dependencies = findDependencyInfo(path).dependencies;
bool rpathsLoaded = false;
QSet<QString> rpaths;
// return bundle-local dependencies. (those starting with @executable_path)
- foreach (const QString &line, outputLines) {
- QString trimmedLine = line.mid(0, line.indexOf("(")).trimmed(); // remove "(compatibility version ...)" and whitespace
+ 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)
@@ -875,15 +900,10 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks,
const FrameworkInfo framework = frameworks.takeFirst();
copiedFrameworks.append(framework.frameworkName);
- // Get the qt path from one of the Qt frameworks;
- if (deploymentInfo.qtPath.isNull() && framework.frameworkName.contains("Qt")
- && framework.frameworkDirectory.contains("/lib"))
- {
- deploymentInfo.qtPath = framework.frameworkDirectory;
- deploymentInfo.qtPath.chop(5); // remove "/lib/"
- }
+ if (deploymentInfo.qtPath.isNull())
+ deploymentInfo.qtPath = QLibraryInfo::location(QLibraryInfo::PrefixPath);
- if (framework.installName.startsWith("@executable_path/") || framework.installName.startsWith("@rpath/")) {
+ if (framework.frameworkDirectory.startsWith(bundlePath)) {
LogError() << framework.frameworkName << "already deployed, skipping.";
continue;
}
@@ -939,7 +959,9 @@ DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringLis
applicationBundle.libraryPaths = findAppLibraries(appBundlePath);
QStringList allBinaryPaths = QStringList() << applicationBundle.binaryPath << applicationBundle.libraryPaths
<< additionalExecutables;
- QList<FrameworkInfo> frameworks = getQtFrameworksForPaths(allBinaryPaths, appBundlePath, getBinaryRPaths(applicationBundle.binaryPath, true), useDebugLibs);
+ QSet<QString> allLibraryPaths = getBinaryRPaths(applicationBundle.binaryPath, true);
+ allLibraryPaths.insert(QLibraryInfo::location(QLibraryInfo::LibrariesPath));
+ QList<FrameworkInfo> frameworks = getQtFrameworksForPaths(allBinaryPaths, appBundlePath, allLibraryPaths, useDebugLibs);
if (frameworks.isEmpty() && !alwaysOwerwriteEnabled) {
LogWarning();
LogWarning() << "Could not find any external Qt frameworks to deploy in" << appBundlePath;
diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h
index 4b4e9bed0..9aee2d424 100644
--- a/src/macdeployqt/shared/shared.h
+++ b/src/macdeployqt/shared/shared.h
@@ -37,6 +37,7 @@
#include <QStringList>
#include <QDebug>
#include <QSet>
+#include <QVersionNumber>
extern int logLevel;
#define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:"
@@ -65,6 +66,24 @@ public:
QString binaryDestinationDirectory;
};
+class DylibInfo
+{
+public:
+ QString binaryPath;
+ QVersionNumber currentVersion;
+ QVersionNumber compatibilityVersion;
+};
+
+class OtoolInfo
+{
+public:
+ QString installName;
+ QString binaryPath;
+ QVersionNumber currentVersion;
+ QVersionNumber compatibilityVersion;
+ QList<DylibInfo> dependencies;
+};
+
bool operator==(const FrameworkInfo &a, const FrameworkInfo &b);
QDebug operator<<(QDebug debug, const FrameworkInfo &info);
@@ -92,6 +111,7 @@ inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info);
void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs);
void changeQtFrameworks(const QList<FrameworkInfo> frameworks, const QStringList &binaryPaths, const QString &qtPath);
+OtoolInfo findDependencyInfo(const QString &binaryPath);
FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);
QString findAppBinary(const QString &appBundlePath);
QList<FrameworkInfo> getQtFrameworks(const QString &path, const QString &appBundlePath, const QSet<QString> &rpaths, bool useDebugLibs);