summaryrefslogtreecommitdiffstats
path: root/src/macdeployqt
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@theqtcompany.com>2016-02-17 17:56:46 +0100
committerAlexandru Croitor <alexandru.croitor@theqtcompany.com>2016-02-23 14:51:47 +0000
commit6cd2ac8a9044f450766ae05b1b56c458699c21b6 (patch)
treeeb94ec4c8364859b89a49b8dcb18bf41e880bf1e /src/macdeployqt
parent1381b25560127fa08c91f6d8ff99ed104a907b82 (diff)
macdeployqt: Fix code-signing errors.
Starting from Qt 5.6 all frameworks / plugins contain an embedded rpath. macdeployqt reads the rpath to get the dependencies which should be signed first, and because the rpath points to a "lib" directory which does not exist in the bundle structure, it shows errors. The solution is to additionally use the rpaths embedded in the bundle executable. Also because on 5.5 and previously rpaths were not included in frameworks, the getBinaryDependencies() always returned an empty set of dependencies, because it didn't have an rpath to resolve the paths to the dependencies (which was probably a bug). Now that the rpaths are present, the dependency list for a framework also contains itself as a dependency, which leads to an infinite loop while code-signing. The fix consists in not repeatedly adding binaries that were alread scheduled for code-singning. Change-Id: I97b418b90f325f88f375ffec83ad68c7dd4528ca Task-number: QTBUG-51101 Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
Diffstat (limited to 'src/macdeployqt')
-rw-r--r--src/macdeployqt/shared/shared.cpp73
-rw-r--r--src/macdeployqt/shared/shared.h4
2 files changed, 53 insertions, 24 deletions
diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp
index 4f72d5a10..6fb5f6778 100644
--- a/src/macdeployqt/shared/shared.cpp
+++ b/src/macdeployqt/shared/shared.cpp
@@ -377,7 +377,7 @@ QStringList findAppLibraries(const QString &appBundlePath)
return result;
}
-QStringList findAppBundleFiles(const QString &appBundlePath)
+QStringList findAppBundleFiles(const QString &appBundlePath, bool absolutePath = false)
{
QStringList result;
@@ -388,7 +388,7 @@ QStringList findAppBundleFiles(const QString &appBundlePath)
iter.next();
if (iter.fileInfo().isSymLink())
continue;
- result << iter.fileInfo().filePath();
+ result << (absolutePath ? iter.fileInfo().absoluteFilePath() : iter.fileInfo().filePath());
}
return result;
@@ -510,7 +510,9 @@ QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QSt
return result;
}
-QStringList getBinaryDependencies(const QString executablePath, const QString &path)
+QStringList getBinaryDependencies(const QString executablePath,
+ const QString &path,
+ const QList<QString> &additionalBinariesContainingRpaths)
{
QStringList binaries;
@@ -539,6 +541,10 @@ QStringList getBinaryDependencies(const QString executablePath, const QString &p
} 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;
@@ -1010,7 +1016,6 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
}
foreach (const QString &plugin, pluginList) {
-
QString sourcePath = pluginSourcePath + "/" + plugin;
if (useDebugLibs) {
// Use debug plugins if found.
@@ -1025,10 +1030,8 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl
if (copyFilePrintStatus(sourcePath, destinationPath)) {
runStrip(destinationPath);
-
QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs);
deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath);
-
}
}
}
@@ -1260,7 +1263,9 @@ void codesignFile(const QString &identity, const QString &filePath)
}
}
-QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath)
+QSet<QString> codesignBundle(const QString &identity,
+ const QString &appBundlePath,
+ QList<QString> additionalBinariesContainingRpaths)
{
// Code sign all binaries in the app bundle. This needs to
// be done inside-out, e.g sign framework dependencies
@@ -1273,27 +1278,38 @@ QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePa
LogNormal() << "Signing" << appBundlePath << "with identity" << identity;
QStack<QString> pendingBinaries;
+ QSet<QString> pendingBinariesSet;
QSet<QString> signedBinaries;
// Create the root code-binary set. This set consists of the application
// executable(s) and the plugins.
- QString rootBinariesPath = appBundlePath + "/Contents/MacOS/";
+ QString appBundleAbsolutePath = QFileInfo(appBundlePath).absoluteFilePath();
+ QString rootBinariesPath = appBundleAbsolutePath + "/Contents/MacOS/";
QStringList foundRootBinaries = QDir(rootBinariesPath).entryList(QStringList() << "*", QDir::Files);
- foreach (const QString &binary, foundRootBinaries)
- pendingBinaries.push(rootBinariesPath + binary);
+ foreach (const QString &binary, foundRootBinaries) {
+ QString binaryPath = rootBinariesPath + binary;
+ pendingBinaries.push(binaryPath);
+ pendingBinariesSet.insert(binaryPath);
+ additionalBinariesContainingRpaths.append(binaryPath);
+ }
- QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/");
- foreach (const QString &binary, foundPluginBinaries)
+ bool getAbsoltuePath = true;
+ QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/", getAbsoltuePath);
+ foreach (const QString &binary, foundPluginBinaries) {
pendingBinaries.push(binary);
+ pendingBinariesSet.insert(binary);
+ }
// Add frameworks for processing.
QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath);
foreach (const QString &frameworkPath, frameworkPaths) {
// Add all files for a framework as a catch all.
- QStringList bundleFiles = findAppBundleFiles(frameworkPath);
- foreach (const QString &binary, bundleFiles)
+ QStringList bundleFiles = findAppBundleFiles(frameworkPath, getAbsoltuePath);
+ foreach (const QString &binary, bundleFiles) {
pendingBinaries.push(binary);
+ pendingBinariesSet.insert(binary);
+ }
// Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g
// used by QtWebEngine).
@@ -1303,7 +1319,9 @@ QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePa
QString helpersPath = helpersIterator.filePath();
QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs);
foreach (const QString &innerBundleName, innerBundleNames)
- signedBinaries += codesignBundle(identity, helpersPath + "/" + innerBundleName);
+ signedBinaries += codesignBundle(identity,
+ helpersPath + "/" + innerBundleName,
+ additionalBinariesContainingRpaths);
}
// Also make sure to sign any libraries that will not be found by otool because they
@@ -1312,35 +1330,43 @@ QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePa
while (librariesIterator.hasNext()) {
librariesIterator.next();
QString librariesPath = librariesIterator.filePath();
- bundleFiles = findAppBundleFiles(librariesPath);
- foreach (const QString &binary, bundleFiles)
+ bundleFiles = findAppBundleFiles(librariesPath, getAbsoltuePath);
+ foreach (const QString &binary, bundleFiles) {
pendingBinaries.push(binary);
+ pendingBinariesSet.insert(binary);
+ }
}
}
- // Sign all binares; use otool to find and sign dependencies first.
+ // Sign all binaries; use otool to find and sign dependencies first.
while (!pendingBinaries.isEmpty()) {
QString binary = pendingBinaries.pop();
if (signedBinaries.contains(binary))
continue;
- // Check if there are unsigned dependencies, sign these first
- QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary).toSet().subtract(signedBinaries).toList();
+ // Check if there are unsigned dependencies, sign these first.
+ QStringList dependencies =
+ getBinaryDependencies(rootBinariesPath, binary, additionalBinariesContainingRpaths).toSet()
+ .subtract(signedBinaries)
+ .subtract(pendingBinariesSet)
+ .toList();
if (!dependencies.isEmpty()) {
pendingBinaries.push(binary);
+ pendingBinariesSet.insert(binary);
int dependenciesSkipped = 0;
foreach (const QString &dependency, dependencies) {
// Skip dependencies that are outside the current app bundle, because this might
// cause a codesign error if the current bundle is part of the dependency (e.g.
// a bundle is part of a framework helper, and depends on that framework).
// The dependencies will be taken care of after the current bundle is signed.
- if (!dependency.startsWith(appBundlePath)) {
+ if (!dependency.startsWith(appBundleAbsolutePath)) {
++dependenciesSkipped;
LogNormal() << "Skipping outside dependency: " << dependency;
continue;
}
pendingBinaries.push(dependency);
+ pendingBinariesSet.insert(dependency);
}
// If all dependencies were skipped, make sure the binary is actually signed, instead
@@ -1352,9 +1378,10 @@ QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePa
}
}
- // All dependencies are signed, now sign this binary
+ // All dependencies are signed, now sign this binary.
codesignFile(identity, binary);
signedBinaries.insert(binary);
+ pendingBinariesSet.remove(binary);
}
LogNormal() << "Finished codesigning " << appBundlePath << "with identity" << identity;
@@ -1375,7 +1402,7 @@ QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePa
}
void codesign(const QString &identity, const QString &appBundlePath) {
- codesignBundle(identity, appBundlePath);
+ codesignBundle(identity, appBundlePath, QList<QString>());
}
void createDiskImage(const QString &appBundlePath)
diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h
index a6d58607c..604e3ef4a 100644
--- a/src/macdeployqt/shared/shared.h
+++ b/src/macdeployqt/shared/shared.h
@@ -109,7 +109,9 @@ QString findAppBinary(const QString &appBundlePath);
QStringList findAppFrameworkNames(const QString &appBundlePath);
QStringList findAppFrameworkPaths(const QString &appBundlePath);
void codesignFile(const QString &identity, const QString &filePath);
-QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath);
+QSet<QString> codesignBundle(const QString &identity,
+ const QString &appBundlePath,
+ QList<QString> additionalBinariesContainingRpaths);
void codesign(const QString &identity, const QString &appBundlePath);
void createDiskImage(const QString &appBundlePath);