diff options
author | Alexandru Croitor <alexandru.croitor@theqtcompany.com> | 2016-02-17 17:56:46 +0100 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@theqtcompany.com> | 2016-02-23 14:51:47 +0000 |
commit | 6cd2ac8a9044f450766ae05b1b56c458699c21b6 (patch) | |
tree | eb94ec4c8364859b89a49b8dcb18bf41e880bf1e /src/macdeployqt | |
parent | 1381b25560127fa08c91f6d8ff99ed104a907b82 (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.cpp | 73 | ||||
-rw-r--r-- | src/macdeployqt/shared/shared.h | 4 |
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); |