diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-06-29 20:12:41 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-06-29 20:12:41 +0200 |
commit | eeeaf56e1ed300dd86040b976d278434387070c1 (patch) | |
tree | ddfb5aaf66351fd5b224cca5da72475b6a7f1714 | |
parent | d56636976643498b9fa688eb9b3029ed9669a8a2 (diff) | |
parent | e863246ebd58192d202933a9f32b57fd811dc9ea (diff) | |
download | qttools-eeeaf56e1ed300dd86040b976d278434387070c1.tar.gz |
Merge remote-tracking branch 'origin/5.5' into dev
Conflicts:
.qmake.conf
Change-Id: I2424cf97743b3f998bf7b10a21f8075ed76b613f
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/StdHeader.h | 5 | ||||
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/config/CompilerGcc.h | 2 | ||||
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h | 16 | ||||
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/debug/condition.cpp | 2 | ||||
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/util/VoidList.h | 4 | ||||
-rw-r--r-- | src/assistant/3rdparty/clucene/src/CLucene/util/VoidMap.h | 24 | ||||
-rw-r--r-- | src/assistant/help/qclucenefieldnames_p.h | 11 | ||||
-rw-r--r-- | src/macdeployqt/shared/shared.cpp | 17 | ||||
-rw-r--r-- | src/qtdiag/qtdiag.cpp | 9 | ||||
-rw-r--r-- | src/windeployqt/main.cpp | 20 | ||||
-rw-r--r-- | src/windeployqt/utils.cpp | 97 | ||||
-rw-r--r-- | src/windeployqt/utils.h | 3 | ||||
-rw-r--r-- | tests/auto/auto.pro | 4 | ||||
-rw-r--r-- | tests/auto/windeployqt/test/test.pro | 5 | ||||
-rw-r--r-- | tests/auto/windeployqt/testapp/main.cpp | 51 | ||||
-rw-r--r-- | tests/auto/windeployqt/testapp/testapp.pro | 2 | ||||
-rw-r--r-- | tests/auto/windeployqt/tst_windeployqt.cpp | 190 | ||||
-rw-r--r-- | tests/auto/windeployqt/windeployqt.pro | 3 |
18 files changed, 404 insertions, 61 deletions
diff --git a/src/assistant/3rdparty/clucene/src/CLucene/StdHeader.h b/src/assistant/3rdparty/clucene/src/CLucene/StdHeader.h index 439bc948a..97799142b 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/StdHeader.h +++ b/src/assistant/3rdparty/clucene/src/CLucene/StdHeader.h @@ -122,7 +122,10 @@ extern int _lucene_counter_break; //can set a watch on this #error "CLucene can't compile without the vector header" #endif -#if !defined(LUCENE_DISABLE_HASHING) && defined(_CL_HAVE_HASH_MAP) && defined(_CL_HAVE_HASH_SET) +#if !defined(LUCENE_DISABLE_HASHING) && defined(_CL_HAVE_STD_UNORDERED_MAP) && defined(_CL_HAVE_STD_UNORDERED_SET) + #include <unordered_map> + #include <unordered_set> +#elif !defined(LUCENE_DISABLE_HASHING) && defined(_CL_HAVE_HASH_MAP) && defined(_CL_HAVE_HASH_SET) //hashing is all or nothing! #include <hash_map> #include <hash_set> diff --git a/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerGcc.h b/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerGcc.h index 3bf91b369..6aac690e2 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerGcc.h +++ b/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerGcc.h @@ -45,6 +45,8 @@ #define CL_NS_HASHING(func) __gnu_cxx::func #define LUCENE_DISABLE_HASHING //we could enable this, but so far test show that the hashing is slower :( +#define CL_HASH_MAP hash_map +#define CL_HASH_SET hash_set //define the file functions #define fileSeek lseek diff --git a/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h b/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h index 8578859f0..6b3f7683e 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h +++ b/src/assistant/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h @@ -27,8 +27,22 @@ #if (_MSC_VER < 1310) || defined(_STLPORT_VERSION) #define CL_NS_HASHING(func) std::func //the namespace is different on VC 7.0 #else - #define CL_NS_HASHING(func) stdext::func + #if _MSC_VER >= 1900 + #undef _CL_HAVE_EXT_HASH_MAP + #undef _CL_HAVE_EXT_HASH_SET + + #define CL_HASH_MAP unordered_map + #define CL_HASH_SET unordered_set + #define _CL_HAVE_STD_UNORDERED_MAP 1 + #define _CL_HAVE_STD_UNORDERED_SET 1 + #define CL_NS_HASHING(func) std::func + #else + #define CL_HASH_MAP hash_map + #define CL_HASH_SET hash_set + #define CL_NS_HASHING(func) stdext::func + #endif #endif + #define LUCENE_STATIC_CONSTANT_SYNTAX 1 #if _MSC_FULL_VER >= 140050320 diff --git a/src/assistant/3rdparty/clucene/src/CLucene/debug/condition.cpp b/src/assistant/3rdparty/clucene/src/CLucene/debug/condition.cpp index 855419451..7fab8d71d 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/debug/condition.cpp +++ b/src/assistant/3rdparty/clucene/src/CLucene/debug/condition.cpp @@ -37,7 +37,7 @@ void _Cnd_OutDebug( const char* FormattedMsg, const char* StrTitle, const char* void __cnd_FormatDebug( const char* File, int32_t Line, int32_t Title, const char* Mes2, int32_t fatal ) { char M[512]; - char* StrTitle = NULL; + const char* StrTitle = NULL; if( Mes2 ) _snprintf(M,512,"file:%s line:%d\n%s",File,Line,Mes2); diff --git a/src/assistant/3rdparty/clucene/src/CLucene/util/VoidList.h b/src/assistant/3rdparty/clucene/src/CLucene/util/VoidList.h index b31baba8a..5deb69dae 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/util/VoidList.h +++ b/src/assistant/3rdparty/clucene/src/CLucene/util/VoidList.h @@ -139,11 +139,11 @@ public: template<typename _kt, typename _Comparator=CL_NS(util)::Compare::TChar, typename _valueDeletor=CL_NS(util)::Deletor::Dummy> -class CLHashList:public __CLList<_kt, CL_NS_HASHING(hash_set)<_kt,_Comparator> , _valueDeletor> +class CLHashList:public __CLList<_kt, CL_NS_HASHING(CL_HASH_SET)<_kt,_Comparator> , _valueDeletor> { public: CLHashList ( const bool deleteValue=true ): - __CLList<_kt, CL_NS_HASHING(hash_set)<_kt,_Comparator> , _valueDeletor>(deleteValue) + __CLList<_kt, CL_NS_HASHING(CL_HASH_SET)<_kt,_Comparator> , _valueDeletor>(deleteValue) { } }; diff --git a/src/assistant/3rdparty/clucene/src/CLucene/util/VoidMap.h b/src/assistant/3rdparty/clucene/src/CLucene/util/VoidMap.h index 1153a0160..223670204 100644 --- a/src/assistant/3rdparty/clucene/src/CLucene/util/VoidMap.h +++ b/src/assistant/3rdparty/clucene/src/CLucene/util/VoidMap.h @@ -153,16 +153,16 @@ public: //a CLSet with CLHashMap traits template<typename _kt, typename _vt, - typename _Compare, + typename CL_Compare, typename _EqualDummy, typename _KeyDeletor=CL_NS(util)::Deletor::Dummy, typename _ValueDeletor=CL_NS(util)::Deletor::Dummy> class CLHashMap:public __CLMap<_kt,_vt, - CL_NS_STD(map)<_kt,_vt, _Compare>, + CL_NS_STD(map)<_kt,_vt, CL_Compare>, _KeyDeletor,_ValueDeletor> { - typedef typename CL_NS_STD(map)<_kt,_vt,_Compare> _base; - typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, _Compare>, + typedef typename CL_NS_STD(map)<_kt,_vt,CL_Compare> _base; + typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, CL_Compare>, _KeyDeletor,_ValueDeletor> _this; public: CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) @@ -180,10 +180,10 @@ template<typename _kt, typename _vt, typename _KeyDeletor=CL_NS(util)::Deletor::Dummy, typename _ValueDeletor=CL_NS(util)::Deletor::Dummy> class CLHashMap:public __CLMap<_kt,_vt, - CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher,_Equals>, + CL_NS_HASHING(CL_HASH_MAP)<_kt,_vt, _Hasher,_Equals>, _KeyDeletor,_ValueDeletor> { - typedef __CLMap<_kt,_vt, CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher,_Equals>, + typedef __CLMap<_kt,_vt, CL_NS_HASHING(CL_HASH_MAP)<_kt,_vt, _Hasher,_Equals>, _KeyDeletor,_ValueDeletor> _this; public: CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) @@ -201,10 +201,10 @@ template<typename _kt, typename _vt, typename _KeyDeletor=CL_NS(util)::Deletor::Dummy, typename _ValueDeletor=CL_NS(util)::Deletor::Dummy> class CLHashMap:public __CLMap<_kt,_vt, - CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher>, + CL_NS_HASHING(CL_HASH_MAP)<_kt,_vt, _Hasher>, _KeyDeletor,_ValueDeletor> { - typedef __CLMap<_kt,_vt, CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher>, + typedef __CLMap<_kt,_vt, CL_NS_HASHING(CL_HASH_MAP)<_kt,_vt, _Hasher>, _KeyDeletor,_ValueDeletor> _this; public: CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) @@ -218,15 +218,15 @@ public: //A collection that contains no duplicates //does not guarantee that the order will remain constant over time template<typename _kt, typename _vt, - typename _Compare, + typename CL_Compare, typename _KeyDeletor=CL_NS(util)::Deletor::Dummy, typename _ValueDeletor=CL_NS(util)::Deletor::Dummy> class CLSet:public __CLMap<_kt,_vt, - CL_NS_STD(map)<_kt,_vt, _Compare>, + CL_NS_STD(map)<_kt,_vt, CL_Compare>, _KeyDeletor,_ValueDeletor> { - typedef typename CL_NS_STD(map)<_kt,_vt,_Compare> _base; - typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, _Compare>, + typedef typename CL_NS_STD(map)<_kt,_vt,CL_Compare> _base; + typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, CL_Compare>, _KeyDeletor,_ValueDeletor> _this; public: CLSet ( const bool deleteKey=false, const bool deleteValue=false ) diff --git a/src/assistant/help/qclucenefieldnames_p.h b/src/assistant/help/qclucenefieldnames_p.h index d72ce3c89..7d2a64e48 100644 --- a/src/assistant/help/qclucenefieldnames_p.h +++ b/src/assistant/help/qclucenefieldnames_p.h @@ -34,6 +34,17 @@ #ifndef QCLUCENEFIELDNAMES_P_H #define QCLUCENEFIELDNAMES_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QtGlobal> #include <QtCore/QString> diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp index 1c9b319ad..e2c4a19bc 100644 --- a/src/macdeployqt/shared/shared.cpp +++ b/src/macdeployqt/shared/shared.cpp @@ -739,13 +739,17 @@ void changeInstallName(const QString &bundlePath, const FrameworkInfo &framework } } -void deployRPaths(const QSet<QString> &rpaths, const QString &binaryPath, bool useLoaderPath) +void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const QString &binaryPath, bool useLoaderPath) { + const QString absFrameworksPath = QFileInfo(bundlePath).absoluteFilePath() + + QLatin1String("/Contents/Frameworks"); + const QString relativeFrameworkPath = QFileInfo(binaryPath).absoluteDir().relativeFilePath(absFrameworksPath); + const QString loaderPathToFrameworks = QLatin1String("@loader_path/") + relativeFrameworkPath; bool rpathToFrameworksFound = false; QStringList args; foreach (const QString &rpath, getBinaryRPaths(binaryPath, false)) { if (rpath == "@executable_path/../Frameworks" || - rpath == "@loader_path/../Frameworks") { + rpath == loaderPathToFrameworks) { rpathToFrameworksFound = true; continue; } @@ -760,7 +764,7 @@ void deployRPaths(const QSet<QString> &rpaths, const QString &binaryPath, bool u if (!useLoaderPath) { args << "-add_rpath" << "@executable_path/../Frameworks"; } else { - args << "-add_rpath" << "@loader_path/../Frameworks"; + args << "-add_rpath" << loaderPathToFrameworks; } } LogDebug() << "Using install_name_tool:"; @@ -769,10 +773,10 @@ void deployRPaths(const QSet<QString> &rpaths, const QString &binaryPath, bool u runInstallNameTool(QStringList() << args << binaryPath); } -void deployRPaths(const QSet<QString> &rpaths, const QStringList &binaryPaths, bool useLoaderPath) +void deployRPaths(const QString &bundlePath, const QSet<QString> &rpaths, const QStringList &binaryPaths, bool useLoaderPath) { foreach (const QString &binary, binaryPaths) { - deployRPaths(rpaths, binary, useLoaderPath); + deployRPaths(bundlePath, rpaths, binary, useLoaderPath); } } @@ -873,7 +877,8 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, } } } - deployRPaths(rpathsUsed, binaryPaths, useLoaderPath); + deploymentInfo.deployedFrameworks = copiedFrameworks; + deployRPaths(bundlePath, rpathsUsed, binaryPaths, useLoaderPath); deploymentInfo.rpathsUsed += rpathsUsed; return deploymentInfo; } diff --git a/src/qtdiag/qtdiag.cpp b/src/qtdiag/qtdiag.cpp index 6af3eccd7..d4e25759d 100644 --- a/src/qtdiag/qtdiag.cpp +++ b/src/qtdiag/qtdiag.cpp @@ -313,6 +313,7 @@ QString qtDiag(unsigned flags) DUMP_CAPABILITY(str, platformIntegration, SyncState) DUMP_CAPABILITY(str, platformIntegration, RasterGLSurface) DUMP_CAPABILITY(str, platformIntegration, AllGLFunctionsQueryable) + DUMP_CAPABILITY(str, platformIntegration, ApplicationIcon) str << '\n'; const QStyleHints *styleHints = QGuiApplication::styleHints(); @@ -336,7 +337,13 @@ QString qtDiag(unsigned flags) << " fontSmoothingGamma: " << styleHints->fontSmoothingGamma() << '\n' << " useRtlExtensions: " << styleHints->useRtlExtensions() << '\n' << " setFocusOnTouchRelease: " << styleHints->setFocusOnTouchRelease() << '\n' - << " tabFocusBehavior: " << formatQDebug(styleHints->tabFocusBehavior()) << '\n'; + << " tabFocusBehavior: " << formatQDebug(styleHints->tabFocusBehavior()) << '\n' + << " singleClickActivation: " << styleHints->singleClickActivation() << '\n'; + str << "\nAdditional style hints (QPlatformIntegration):\n" + << " ShowIsMaximized: " + << platformIntegration->styleHint(QPlatformIntegration::ShowIsMaximized).toBool() << '\n' + << " ReplayMousePressOutsidePopup: " + << platformIntegration->styleHint(QPlatformIntegration::ReplayMousePressOutsidePopup).toBool() << '\n'; const QPlatformTheme *platformTheme = QGuiApplicationPrivate::platformTheme(); str << "\nTheme:\n Styles: " << platformTheme->themeHint(QPlatformTheme::StyleNames).toStringList(); diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp index f1b4b39e2..8414a9afe 100644 --- a/src/windeployqt/main.cpp +++ b/src/windeployqt/main.cpp @@ -196,8 +196,12 @@ static Platform platformFromMkSpec(const QString &xSpec) return WinPhoneIntel; if (xSpec.startsWith(QLatin1String("winphone-arm"))) return WinPhoneArm; - if (xSpec.startsWith(QLatin1String("wince"))) - return WinCE; + if (xSpec.startsWith(QLatin1String("wince"))) { + if (xSpec.contains(QLatin1String("-x86-"))) + return WinCEIntel; + if (xSpec.contains(QLatin1String("-arm"))) + return WinCEArm; + } return UnknownPlatform; } @@ -789,7 +793,8 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules, switch (platform) { case Windows: case WindowsMinGW: - case WinCE: + case WinCEIntel: + case WinCEArm: filter = QStringLiteral("qwindows"); break; case WinRtIntel: @@ -928,8 +933,10 @@ static QStringList compilerRunTimeLibs(Platform platform, unsigned wordSize) case WindowsMinGW: { // MinGW: Add runtime libraries static const char *minGwRuntimes[] = {"*gcc_", "*stdc++", "*winpthread"}; const QString gcc = findInPath(QStringLiteral("g++.exe")); - if (gcc.isEmpty()) + if (gcc.isEmpty()) { + std::wcerr << "Warning: Cannot find GCC installation directory. g++.exe must be in the path.\n"; break; + } const QString binPath = QFileInfo(gcc).absolutePath(); QDir dir(binPath); QStringList filters; @@ -1179,13 +1186,14 @@ static DeployResult deploy(const Options &options, } // Check for ANGLE on the Qt5Gui library. - if ((options.platform & WindowsBased) && !qtGuiLibrary.isEmpty()) { + if ((options.platform & WindowsBased) && options.platform != WinCEIntel + && options.platform != WinCEArm && !qtGuiLibrary.isEmpty()) { QString libGlesName = QStringLiteral("libGLESV2"); if (isDebug) libGlesName += QLatin1Char('d'); libGlesName += QLatin1String(windowsSharedLibrarySuffix); const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage); - const bool dependsOnAngle = !guiLibraries.filter(libGlesName, Qt::CaseInsensitive).isEmpty() && !(options.platform & WinCE); + const bool dependsOnAngle = !guiLibraries.filter(libGlesName, Qt::CaseInsensitive).isEmpty(); const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty(); if (options.angleDetection != Options::AngleDetectionForceOff && (dependsOnAngle || !dependsOnOpenGl || options.angleDetection == Options::AngleDetectionForceOn)) { diff --git a/src/windeployqt/utils.cpp b/src/windeployqt/utils.cpp index 081c9c475..e7a755500 100644 --- a/src/windeployqt/utils.cpp +++ b/src/windeployqt/utils.cpp @@ -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,52 @@ inline QStringList readImportSections(const ImageNtHeader *ntHeaders, const void return result; } +// Check for MSCV runtime (MSVCP90D.dll/MSVCP90.dll, MSVCP120D.dll/MSVCP120.dll +// or msvcp120d_app.dll/msvcp120_app.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)) { + int pos = 5; + if (lib.at(pos).isDigit()) { + for (++pos; lib.at(pos).isDigit(); ++pos) + ; + return lib.at(pos).toLower() == QLatin1Char('d') + ? 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 +817,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) diff --git a/src/windeployqt/utils.h b/src/windeployqt/utils.h index 76e003abc..e7c2776a9 100644 --- a/src/windeployqt/utils.h +++ b/src/windeployqt/utils.h @@ -62,7 +62,8 @@ enum Platform { WinRtArm = WindowsBased + ArmBased + 2, WinPhoneIntel = WindowsBased + IntelBased + 3, WinPhoneArm = WindowsBased + ArmBased + 4, - WinCE = WindowsBased + ArmBased + 5, + WinCEIntel = WindowsBased + IntelBased + 5, + WinCEArm = WindowsBased + ArmBased + 6, Unix = UnixBased, UnknownPlatform }; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index a703a0609..20b5fec90 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -8,7 +8,8 @@ SUBDIRS=\ qhelpprojectdata \ cmake \ installed_cmake \ - qtdiag + qtdiag \ + windeployqt installed_cmake.depends = cmake @@ -24,3 +25,4 @@ cross_compile:SUBDIRS -= linguist qhelpprojectdata \ android|ios|qnx|wince*|winrt*:SUBDIRS -= qtdiag +!win32|wince*|winrt*:SUBDIRS -= windeployqt diff --git a/tests/auto/windeployqt/test/test.pro b/tests/auto/windeployqt/test/test.pro new file mode 100644 index 000000000..7aac19a0d --- /dev/null +++ b/tests/auto/windeployqt/test/test.pro @@ -0,0 +1,5 @@ +CONFIG += testcase +QT = core testlib +DESTDIR = .. +TARGET = tst_windeployqt +SOURCES += ../tst_windeployqt.cpp diff --git a/tests/auto/windeployqt/testapp/main.cpp b/tests/auto/windeployqt/testapp/main.cpp new file mode 100644 index 000000000..4655408ba --- /dev/null +++ b/tests/auto/windeployqt/testapp/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QRasterWindow> +#include <QScreen> +#include <QTimer> + +// Simple test application just to verify that it comes up properly + +int main(int argc, char ** argv) +{ + QGuiApplication app(argc, argv); + QRasterWindow w; + w.setTitle("windeployqt test application"); + const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); + w.resize(availableGeometry.size() / 4); + w.show(); + QTimer::singleShot(200, &w, &QCoreApplication::quit); + return app.exec(); +} diff --git a/tests/auto/windeployqt/testapp/testapp.pro b/tests/auto/windeployqt/testapp/testapp.pro new file mode 100644 index 000000000..7bd2fba0e --- /dev/null +++ b/tests/auto/windeployqt/testapp/testapp.pro @@ -0,0 +1,2 @@ +SOURCES = main.cpp +DESTDIR = ./ diff --git a/tests/auto/windeployqt/tst_windeployqt.cpp b/tests/auto/windeployqt/tst_windeployqt.cpp new file mode 100644 index 000000000..4acea454f --- /dev/null +++ b/tests/auto/windeployqt/tst_windeployqt.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QLibraryInfo> +#include <QtCore/QProcess> +#include <QtCore/QProcessEnvironment> +#include <QtCore/QStandardPaths> +#include <QtCore/QTextStream> +#include <QtTest/QtTest> + +#ifndef QT_NO_PROCESS +static const QString msgProcessError(const QProcess &process, const QString &what) +{ + QString result; + QTextStream(&result) << what << ": \"" << process.program() << ' ' + << process.arguments().join(QLatin1Char(' ')) << "\": " << process.errorString(); + return result; +} + +static bool runProcess(const QString &binary, + const QStringList &arguments, + QString *errorMessage, + const QString &workingDir = QString(), + const QProcessEnvironment &env = QProcessEnvironment(), + int timeOut = 5000, + QByteArray *stdOut = Q_NULLPTR, QByteArray *stdErr = Q_NULLPTR) +{ + QProcess process; + if (!env.isEmpty()) + process.setProcessEnvironment(env); + if (!workingDir.isEmpty()) + process.setWorkingDirectory(workingDir); + qDebug().noquote().nospace() << "Running: " << QDir::toNativeSeparators(binary) + << ' ' << arguments.join(QLatin1Char(' ')); + process.start(binary, arguments, QIODevice::ReadOnly); + if (!process.waitForStarted()) { + *errorMessage = msgProcessError(process, "Failed to start"); + return false; + } + if (!process.waitForFinished(timeOut)) { + *errorMessage = msgProcessError(process, "Timed out"); + process.terminate(); + if (!process.waitForFinished(300)) + process.kill(); + return false; + } + if (stdOut) + *stdOut = process.readAllStandardOutput(); + if (stdErr) + *stdErr= process.readAllStandardError(); + if (process.exitStatus() != QProcess::NormalExit) { + *errorMessage = msgProcessError(process, "Crashed"); + return false; + } + if (process.exitCode() != QProcess::NormalExit) { + *errorMessage = msgProcessError(process, "Exit code " + QString::number(process.exitCode())); + return false; + } + return true; +} + +#endif // !QT_NO_PROCESS + +class tst_windeployqt : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void help(); + void deploy(); + +private: + QString m_windeployqtBinary; + QString m_testApp; + QString m_testAppBinary; +}; + +void tst_windeployqt::initTestCase() +{ +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else + m_windeployqtBinary = QStandardPaths::findExecutable("windeployqt"); + QVERIFY(!m_windeployqtBinary.isEmpty()); + m_testApp = QFINDTESTDATA("testapp"); + QVERIFY(!m_testApp.isEmpty()); + const QFileInfo testAppBinary(m_testApp + QLatin1String("/testapp.exe")); + QVERIFY2(testAppBinary.isFile(), qPrintable(testAppBinary.absoluteFilePath())); + m_testAppBinary = testAppBinary.absoluteFilePath(); +#endif // QT_NO_PROCESS +} + +void tst_windeployqt::help() +{ +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else + QString errorMessage; + QByteArray stdOut; + QByteArray stdErr; + QVERIFY2(runProcess(m_windeployqtBinary, QStringList("--help"), &errorMessage, + QString(), QProcessEnvironment(), 5000, &stdOut, &stdErr), + qPrintable(errorMessage)); + QVERIFY2(!stdOut.isEmpty(), stdErr); +#endif // QT_NO_PROCESS +} + +// deploy(): Deploys the test application and launches it with Qt removed from the environment +// to verify it runs stand-alone. + +void tst_windeployqt::deploy() +{ +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else + QString errorMessage; + // Deploy application + QStringList deployArguments; + deployArguments << QLatin1String("--no-translations") << QDir::toNativeSeparators(m_testAppBinary); + QVERIFY2(runProcess(m_windeployqtBinary, deployArguments, &errorMessage, QString(), QProcessEnvironment(), 20000), + qPrintable(errorMessage)); + + // Create environment with Qt and all "lib" paths removed. + const QString qtBinDir = QDir::toNativeSeparators(QLibraryInfo::location(QLibraryInfo::BinariesPath)); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + const QString pathKey = QLatin1String("PATH"); + const QChar pathSeparator(QLatin1Char(';')); // ### fixme: Qt 5.6: QDir::listSeparator() + const QString origPath = env.value(pathKey); + QString newPath; + foreach (const QString &pathElement, origPath.split(pathSeparator, QString::SkipEmptyParts)) { + if (pathElement.compare(qtBinDir, Qt::CaseInsensitive) + && !pathElement.contains(QLatin1String("\\lib"), Qt::CaseInsensitive)) { + if (!newPath.isEmpty()) + newPath.append(pathSeparator); + newPath.append(pathElement); + } + } + if (newPath == origPath) + qWarning() << "Unable to remove Qt from PATH"; + env.insert(pathKey, newPath); + + // Create qt.conf to enforce usage of local plugins + QFile qtConf(QFileInfo(m_testAppBinary).absolutePath() + QLatin1String("/qt.conf")); + QVERIFY2(qtConf.open(QIODevice::WriteOnly | QIODevice::Text), + qPrintable(qtConf.fileName() + QLatin1String(": ") + qtConf.errorString())); + QVERIFY(qtConf.write("[Paths]\nPrefix = .\n")); + qtConf.close(); + + // Verify that application still runs + QVERIFY2(runProcess(m_testAppBinary, QStringList(), &errorMessage, QString(), env, 10000), + qPrintable(errorMessage)); +#endif // QT_NO_PROCESS +} + +QTEST_MAIN(tst_windeployqt) +#include "tst_windeployqt.moc" diff --git a/tests/auto/windeployqt/windeployqt.pro b/tests/auto/windeployqt/windeployqt.pro new file mode 100644 index 000000000..0ae9b2bab --- /dev/null +++ b/tests/auto/windeployqt/windeployqt.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = testapp test +CONFIG += ordered |