windeployqt: Add --release-with-debug-info option..
authorFriedemann Kleint <Friedemann.Kleint@digia.com>
Mon, 27 Oct 2014 14:23:35 +0000 (15:23 +0100)
committerFriedemann Kleint <Friedemann.Kleint@digia.com>
Wed, 29 Oct 2014 14:45:06 +0000 (15:45 +0100)
The option can be used for Qt builds with
-force-debug-info -release .
For those, deployment fails with "Unable to find the platform
plugin." since the DLLs are detected as debug-built. If windeployqt is
extended to actually read Qt configuration information, the value can be
obtained from there.

Task-number: QTBUG-42072
Change-Id: If8b4a0e41821b5f0f4b7023b1b9a3d49e50628a1
Reviewed-by: Jarred Nicholls <jarred.nicholls@gmail.com>
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
src/windeployqt/main.cpp
src/windeployqt/qmlutils.cpp
src/windeployqt/qmlutils.h
src/windeployqt/utils.cpp
src/windeployqt/utils.h

index c178a20..6f7a731 100644 (file)
@@ -227,7 +227,8 @@ struct Options {
 
     Options() : plugins(true), libraries(true), quickImports(true), translations(true), systemD3dCompiler(true), compilerRunTime(false)
               , angleDetection(AngleDetectionAuto), platform(Windows), additionalLibraries(0), disabledLibraries(0)
-              , updateFileFlags(0), json(0), list(ListNone), debugDetection(DebugDetectionAuto) {}
+              , updateFileFlags(0), json(0), list(ListNone), debugDetection(DebugDetectionAuto)
+              , debugMatchAll(false) {}
 
     bool plugins;
     bool libraries;
@@ -247,6 +248,7 @@ struct Options {
     JsonOutput *json;
     ListOption list;
     DebugDetection debugDetection;
+    bool debugMatchAll;
 };
 
 // Return binary from folder
@@ -302,6 +304,9 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
     QCommandLineOption releaseOption(QStringLiteral("release"),
                                    QStringLiteral("Assume release binaries."));
     parser->addOption(releaseOption);
+    QCommandLineOption releaseWithDebugInfoOption(QStringLiteral("release-with-debug-info"),
+                                                  QStringLiteral("Assume release binaries with debug information."));
+    parser->addOption(releaseWithDebugInfoOption);
 
     QCommandLineOption forceOption(QStringLiteral("force"),
                                     QStringLiteral("Force updating files."));
@@ -429,15 +434,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
         return CommandLineParseError;
     }
 
-    switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
-    case OptionAuto:
-        break;
-    case OptionEnabled:
-        options->debugDetection = Options::DebugDetectionForceDebug;
-        break;
-    case OptionDisabled:
-         options->debugDetection = Options::DebugDetectionForceRelease;
-        break;
+    if (parser->isSet(releaseWithDebugInfoOption)) {
+        options->debugMatchAll = true; // PE analysis will detect "debug", turn off matching.
+        options->debugDetection = Options::DebugDetectionForceRelease;
+    } else {
+        switch (parseExclusiveOptions(parser, debugOption, releaseOption)) {
+        case OptionAuto:
+            break;
+        case OptionEnabled:
+            options->debugDetection = Options::DebugDetectionForceDebug;
+            break;
+        case OptionDisabled:
+            options->debugDetection = Options::DebugDetectionForceRelease;
+            break;
+        }
     }
 
     switch (parseExclusiveOptions(parser, angleOption, noAngleOption)) {
@@ -629,15 +639,16 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin
 // Tries to pre-filter by namefilter and does check via PE.
 class DllDirectoryFileEntryFunction {
 public:
-    explicit DllDirectoryFileEntryFunction(Platform platform, bool debug, const QString &prefix = QString()) :
-        m_platform(platform), m_dllDebug(debug), m_prefix(prefix) {}
+    explicit DllDirectoryFileEntryFunction(Platform platform,
+                                           DebugMatchMode debugMatchMode, const QString &prefix = QString()) :
+        m_platform(platform), m_debugMatchMode(debugMatchMode), m_prefix(prefix) {}
 
     QStringList operator()(const QDir &dir) const
-        { return findSharedLibraries(dir, m_platform, m_dllDebug, m_prefix); }
+        { return findSharedLibraries(dir, m_platform, m_debugMatchMode, m_prefix); }
 
 private:
     const Platform m_platform;
-    const bool m_dllDebug;
+    const DebugMatchMode m_debugMatchMode;
     const QString m_prefix;
 };
 
@@ -645,9 +656,9 @@ private:
 // QML import trees: DLLs (matching debgug) and .qml/,js, etc.
 class QmlDirectoryFileEntryFunction {
 public:
-    explicit QmlDirectoryFileEntryFunction(Platform platform, bool debug, bool skipQmlSources = false)
+    explicit QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, bool skipQmlSources = false)
         : m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(skipQmlSources))
-        , m_dllFilter(platform, debug)
+        , m_dllFilter(platform, debugMatchMode)
     {}
 
     QStringList operator()(const QDir &dir) const { return m_dllFilter(dir) + m_qmlNameFilter(dir);  }
@@ -708,7 +719,7 @@ static quint64 qtModule(const QString &module)
 
 QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
                           const QString &qtPluginsDirName, const QString &libraryLocation,
-                          bool debug, Platform platform, QString *platformPlugin)
+                          DebugMatchMode debugMatchMode, Platform platform, QString *platformPlugin)
 {
     QString errorMessage;
     if (qtPluginsDirName.isEmpty())
@@ -744,7 +755,7 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules,
             } else {
                 filter  = QLatin1String("*");
             }
-            const QStringList plugins = findSharedLibraries(subDir, platform ,debug, filter);
+            const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
             foreach (const QString &plugin, plugins) {
                 const QString pluginPath = subDir.absoluteFilePath(plugin);
                 if (isPlatformPlugin)
@@ -962,6 +973,8 @@ static DeployResult deploy(const Options &options,
         return result;
 
     const bool isDebug = options.debugDetection == Options::DebugDetectionAuto ? detectedDebug: options.debugDetection == Options::DebugDetectionForceDebug;
+    const DebugMatchMode debugMatchMode = options.debugMatchAll
+        ? MatchDebugOrRelease : (isDebug ? MatchDebug : MatchRelease);
 
     // Determine application type, check Quick2 is used by looking at the
     // direct dependencies (do not be fooled by QtWebKit depending on it).
@@ -970,7 +983,7 @@ static DeployResult deploy(const Options &options,
         const quint64 module = qtModule(dependentQtLibs.at(m));
         result.directlyUsedQtLibraries |= module;
         if (module == QtCoreModule)
-            qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), isDebug, options.platform);
+            qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
     }
 
     const bool usesQml2 = !(options.disabledLibraries & QtQmlModule)
@@ -1032,7 +1045,8 @@ static DeployResult deploy(const Options &options,
         foreach (const QString &qmlDirectory, qmlDirectories) {
             if (optVerboseLevel >= 1)
                 std::wcout << "Scanning " << QDir::toNativeSeparators(qmlDirectory) << ":\n";
-            const QmlImportScanResult scanResult = runQmlImportScanner(qmlDirectory, qmakeVariables.value(QStringLiteral("QT_INSTALL_QML")), options.platform, isDebug, errorMessage);
+            const QmlImportScanResult scanResult = runQmlImportScanner(qmlDirectory, qmakeVariables.value(QStringLiteral("QT_INSTALL_QML")), options.platform,
+                                                                       debugMatchMode, errorMessage);
             if (!scanResult.ok)
                 return result;
             qmlScanResult.append(scanResult);
@@ -1074,7 +1088,7 @@ static DeployResult deploy(const Options &options,
                       // For non-QML applications, disable QML to prevent it from being pulled in by the qtaccessiblequick plugin.
                       options.disabledLibraries | (usesQml2 ? 0 : (QtQmlModule | QtQuickModule)),
                       qmakeVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")), libraryLocation,
-                      isDebug, options.platform, &platformPlugin);
+                      debugMatchMode, options.platform, &platformPlugin);
 
     // Apply options flags and re-add library names.
     QString qtGuiLibrary;
@@ -1176,7 +1190,7 @@ static DeployResult deploy(const Options &options,
     // Do not be fooled by QtWebKit.dll depending on Quick into always installing Quick imports
     // for WebKit1-applications. Check direct dependency only.
     if (options.quickImports && (usesQuick1 || usesQml2)) {
-        const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, isDebug);
+        const QmlDirectoryFileEntryFunction qmlFileEntryFunction(options.platform, debugMatchMode);
         if (usesQml2) {
             foreach (const QmlImportScanResult::Module &module, qmlScanResult.modules) {
                 const QString installPath = module.installPath(options.directory);
@@ -1188,7 +1202,7 @@ static DeployResult deploy(const Options &options,
                     return result;
                 const bool updateResult = module.sourcePath.contains(QLatin1String("QtQuick/Controls"))
                     || module.sourcePath.contains(QLatin1String("QtQuick/Dialogs")) ?
-                    updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform, isDebug, true),
+                    updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform, debugMatchMode, true),
                                installPath, options.updateFileFlags | RemoveEmptyQmlDirectories,
                                options.json, errorMessage) :
                     updateFile(module.sourcePath, qmlFileEntryFunction, installPath, options.updateFileFlags,
index 244de94..940c424 100644 (file)
@@ -103,19 +103,21 @@ QString findQmlDirectory(int platform, const QString &startDirectoryName)
     return qmlDirectoryRecursion(Platform(platform), startDirectory.path());
 }
 
-static void findFileRecursion(const QDir &directory, Platform platform, bool debug, QStringList *matches)
+static void findFileRecursion(const QDir &directory, Platform platform,
+                              DebugMatchMode debugMatchMode, QStringList *matches)
 {
-    foreach (const QString &dll, findSharedLibraries(directory, platform, debug))
+    foreach (const QString &dll, findSharedLibraries(directory, platform, debugMatchMode))
         matches->append(directory.filePath(dll));
     foreach (const QString &subDir, directory.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks)) {
         QDir subDirectory = directory;
         if (subDirectory.cd(subDir))
-            findFileRecursion(subDirectory, platform, debug, matches);
+            findFileRecursion(subDirectory, platform, debugMatchMode, matches);
     }
 }
 
 QmlImportScanResult runQmlImportScanner(const QString &directory, const QString &qmlImportPath,
-                                        int platform, bool debug, QString *errorMessage)
+                                        int platform, DebugMatchMode debugMatchMode,
+                                        QString *errorMessage)
 {
     QmlImportScanResult result;
     QStringList arguments;
@@ -151,7 +153,7 @@ QmlImportScanResult runQmlImportScanner(const QString &directory, const QString
                 module.className = object.value(QStringLiteral("classname")).toString();
                 module.sourcePath = path;
                 result.modules.append(module);
-                findFileRecursion(QDir(path), Platform(platform), debug, &result.plugins);
+                findFileRecursion(QDir(path), Platform(platform), debugMatchMode, &result.plugins);
             }
         }
     }
index ee914bb..683afb5 100644 (file)
@@ -34,6 +34,8 @@
 #ifndef QMLUTILS_H
 #define QMLUTILS_H
 
+#include "utils.h"
+
 #include <QStringList>
 
 QT_BEGIN_NAMESPACE
@@ -59,7 +61,8 @@ struct QmlImportScanResult {
 };
 
 QmlImportScanResult runQmlImportScanner(const QString &directory, const QString &qmlImportPath,
-                                        int platform, bool debug, QString *errorMessage);
+                                        int platform, DebugMatchMode debugMatchMode,
+                                        QString *errorMessage);
 
 QT_END_NAMESPACE
 
index 57ba71d..2cec4ff 100644 (file)
@@ -108,12 +108,14 @@ bool createDirectory(const QString &directory, QString *errorMessage)
 }
 
 // Find shared libraries matching debug/Platform in a directory, return relative names.
-QStringList findSharedLibraries(const QDir &directory, Platform platform, bool debug, const QString &prefix)
+QStringList findSharedLibraries(const QDir &directory, Platform platform,
+                                DebugMatchMode debugMatchMode,
+                                const QString &prefix)
 {
     QString nameFilter = prefix;
     if (nameFilter.isEmpty())
         nameFilter += QLatin1Char('*');
-    if (debug && (platform & WindowsBased))
+    if (debugMatchMode == MatchDebug && (platform & WindowsBased))
         nameFilter += QLatin1Char('d');
     nameFilter += sharedLibrarySuffix(platform);
     QStringList result;
@@ -121,11 +123,11 @@ QStringList findSharedLibraries(const QDir &directory, Platform platform, bool d
     foreach (const QString &dll, directory.entryList(QStringList(nameFilter), QDir::Files)) {
         const QString dllPath = directory.absoluteFilePath(dll);
         bool matches = true;
-        if (platform & WindowsBased) {
+        if (debugMatchMode != MatchDebugOrRelease && (platform & WindowsBased)) {
             bool debugDll;
             if (readPeExecutable(dllPath, &errorMessage, 0, 0, &debugDll,
                                  (platform == WindowsMinGW))) {
-                matches = debugDll == debug;
+                matches = debugDll == (debugMatchMode == MatchDebug);
             } else {
                 std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(dllPath)
                            << ": " << errorMessage;
index 2133191..0bef65e 100644 (file)
@@ -166,7 +166,16 @@ bool createDirectory(const QString &directory, QString *errorMessage);
 QString findInPath(const QString &file);
 QMap<QString, QString> queryQMakeAll(QString *errorMessage);
 QString queryQMake(const QString &variable, QString *errorMessage);
-QStringList findSharedLibraries(const QDir &directory, Platform platform, bool debug, const QString &prefix = QString());
+
+enum DebugMatchMode {
+    MatchDebug,
+    MatchRelease,
+    MatchDebugOrRelease
+};
+
+QStringList findSharedLibraries(const QDir &directory, Platform platform,
+                                DebugMatchMode debugMatchMode,
+                                const QString &prefix = QString());
 
 bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
                 const QString &targetDirectory, unsigned flags, JsonOutput *json, QString *errorMessage);