windeployqt: Detect -release -force-debug-info MSVC builds as release.
authorFriedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Fri, 12 Jun 2015 12:52:32 +0000 (14:52 +0200)
committerJani Heikkinen <jani.heikkinen@theqtcompany.com>
Sun, 14 Jun 2015 06:17:35 +0000 (06:17 +0000)
Factor out detection logic into a template for 32/64bit.
When a debug entry is detected, detect release if the
library positively uses the release runtime dll.

Task-number: QTBUG-46629
Change-Id: Ic34c2e3850e7f1945086da87867934c502026a2e
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
src/windeployqt/utils.cpp

index 081c9c4..a331bac 100644 (file)
@@ -35,6 +35,8 @@
 #include "elfreader.h"
 
 #include <QtCore/QString>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
 #include <QtCore/QFile>
 #include <QtCore/QFileInfo>
 #include <QtCore/QTemporaryFile>
@@ -723,6 +725,46 @@ inline QStringList readImportSections(const ImageNtHeader *ntHeaders, const void
     return result;
 }
 
+// Check for MSCV runtime (MSVCP120D.dll/MSVCP120.dll).
+enum MsvcDebugRuntimeResult { MsvcDebugRuntime, MsvcReleaseRuntime, NoMsvcRuntime };
+
+static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &dependentLibraries)
+{
+    foreach (const QString &lib, dependentLibraries) {
+        if (lib.startsWith(QLatin1String("MSVCR"), Qt::CaseInsensitive)
+            || lib.startsWith(QLatin1String("MSVCP"), Qt::CaseInsensitive)) {
+            return lib.endsWith(QLatin1String("D.dll"), Qt::CaseInsensitive)
+                ? MsvcDebugRuntime : MsvcReleaseRuntime;
+        }
+    }
+    return NoMsvcRuntime;
+}
+
+template <class ImageNtHeader>
+inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
+                                           bool isMinGW,
+                                           QStringList *dependentLibrariesIn,
+                                           bool *isDebugIn, QString *errorMessage)
+{
+    const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+    QStringList dependentLibraries;
+    if (dependentLibrariesIn || (isDebugIn && hasDebugEntry && !isMinGW))
+        dependentLibraries = readImportSections(nth, fileMemory, errorMessage);
+
+    if (dependentLibrariesIn)
+        *dependentLibrariesIn = dependentLibraries;
+    if (isDebugIn) {
+        if (isMinGW) {
+            // Use logic that's used e.g. in objdump / pfd library
+            *isDebugIn = !(nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
+        } else {
+            // When an MSVC debug entry is present, check whether the debug runtime
+            // is actually used to detect -release / -force-debug-info builds.
+            *isDebugIn = hasDebugEntry && checkMsvcDebugRuntime(dependentLibraries) != MsvcReleaseRuntime;
+        }
+    }
+}
+
 // Read a PE executable and determine dependent libraries, word size
 // and debug flags.
 bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
@@ -769,40 +811,31 @@ bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage
         const unsigned wordSize = ntHeaderWordSize(ntHeaders);
         if (wordSizeIn)
             *wordSizeIn = wordSize;
-        bool debug = false;
         if (wordSize == 32) {
-            const IMAGE_NT_HEADERS32 *ntHeaders32 = reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders);
-
-            if (!isMinGW) {
-                debug = ntHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
-            } else {
-                // Use logic that's used e.g. in objdump / pfd library
-                debug = !(ntHeaders32->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
-            }
-
-            if (dependentLibrariesIn)
-                *dependentLibrariesIn = readImportSections(ntHeaders32, fileMemory, errorMessage);
-
+            determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders),
+                                           fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
         } else {
-            const IMAGE_NT_HEADERS64 *ntHeaders64 = reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders);
-
-            if (!isMinGW) {
-                debug = ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
-            } else {
-                // Use logic that's used e.g. in objdump / pfd library
-                debug = !(ntHeaders64->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
-            }
-
-            if (dependentLibrariesIn)
-                *dependentLibrariesIn = readImportSections(ntHeaders64, fileMemory, errorMessage);
+            determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders),
+                                           fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
         }
 
-        if (isDebugIn)
-            *isDebugIn = debug;
         result = true;
-        if (optVerboseLevel > 1)
-            std::wcout << __FUNCTION__ << ": " << peExecutableFileName
-                       << ' ' << wordSize << " bit, debug: " << debug << '\n';
+        if (optVerboseLevel > 1) {
+            std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName)
+                << ' ' << wordSize << " bit";
+            if (isMinGW)
+                std::wcout << ", MinGW";
+            if (dependentLibrariesIn) {
+                std::wcout << ", dependent libraries: ";
+                if (optVerboseLevel > 2)
+                    std::wcout << dependentLibrariesIn->join(QLatin1Char(' '));
+                else
+                    std::wcout << dependentLibrariesIn->size();
+            }
+            if (isDebugIn)
+                std::wcout << (*isDebugIn ? ", debug" : ", release");
+            std::wcout << '\n';
+        }
     } while (false);
 
     if (fileMemory)