diff options
author | Joerg Bornemann <joerg.bornemann@nokia.com> | 2012-08-15 12:18:49 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-16 08:26:24 +0200 |
commit | c9406bcffe63f1ce232ce91b00be294e0135282a (patch) | |
tree | 74aa70ca0ba7911c37c1d7b423db9bfc7c11c524 /qmake | |
parent | 15b5b28425f52fcbb2b85c94ec485af841adb4b5 (diff) |
qmake: support incremental linking when embedding manifests
When embedding manifests we modified the EXE/DLL after linking using
the manifest tool. This breaks the incremental linking feature of MSVC.
The MS way to embed a manifest without breaking incremental linking is:
- let the linker create the manifest file,
- create a resource that contains the manifest file,
- invoke the linker again to embed the resource.
The embed_manifest_{exe|dll}.prf files have been removed.
All manifest logic is now in qmake's nmake makefile generator.
With QMAKE_MANIFEST one can specify a custom manifest file that gets
embedded without disturbing incremental linking.
Task-number: QTBUG-22718
Change-Id: Idb9d2644a0577b2002cbdd2d62b695b9171b1bd5
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Diffstat (limited to 'qmake')
-rw-r--r-- | qmake/generators/win32/msvc_nmake.cpp | 76 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_nmake.h | 1 |
2 files changed, 72 insertions, 5 deletions
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index ff73ef7e79..a5c215a653 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -357,7 +357,8 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t) void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) { - if (project->first("TEMPLATE") == "aux") { + const QString templateName = project->first("TEMPLATE"); + if (templateName == "aux") { t << "first:" << endl; t << "all:" << endl; return; @@ -371,12 +372,65 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) t << "\n\t" <<var("QMAKE_PRE_LINK"); if(project->isActiveConfig("staticlib")) { t << "\n\t" << "$(LIBAPP) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) @<<" << "\n\t " - << "$(OBJECTS)"; + << "$(OBJECTS)" + << "\n<<"; } else { - t << "\n\t" << "$(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<< " << "\n\t " - << "$(OBJECTS) $(LIBS)"; + const bool embedManifest = ((templateName == "app" && project->isActiveConfig("embed_manifest_exe")) + || (templateName == "lib" && project->isActiveConfig("embed_manifest_dll") + && !(project->isActiveConfig("plugin") && project->isActiveConfig("no_plugin_manifest")) + )); + if (embedManifest) { + bool generateManifest = false; + const QString target = var("DEST_TARGET"); + QString manifest = project->first("QMAKE_MANIFEST"); + QString extraLFlags; + if (manifest.isEmpty()) { + generateManifest = true; + manifest = escapeFilePath(target + ".embed.manifest"); + extraLFlags = "/MANIFEST /MANIFESTFILE:" + manifest; + project->values("QMAKE_CLEAN") << manifest; + } + + const bool incrementalLinking = project->values("QMAKE_LFLAGS").filter(QRegExp("(/|-)INCREMENTAL:NO")).isEmpty(); + if (incrementalLinking) { + // Link a resource that contains the manifest without modifying the exe/dll after linking. + + QString manifest_rc = escapeFilePath(target + "_manifest.rc"); + QString manifest_res = escapeFilePath(target + "_manifest.res"); + QString manifest_bak = escapeFilePath(target + "_manifest.bak"); + project->values("QMAKE_CLEAN") << manifest_rc << manifest_res; + + t << "\n\t" << "@if not exist " << manifest_rc << " echo 1 /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ " << manifest + << ">" << manifest_rc; + + if (generateManifest) { + t << "\n\tif not exist $(DESTDIR_TARGET) del " << manifest << ">NUL 2>&1"; + t << "\n\tif exist " << manifest << " copy /Y " << manifest << ' ' << manifest_bak; + const QString extraInlineFileContent = "\n!IF EXIST(" + manifest_res + ")\n" + manifest_res + "\n!ENDIF"; + t << "\n\t"; + writeLinkCommand(t, extraLFlags, extraInlineFileContent); + const QString check_manifest_bak_existence = "\n\tif exist " + manifest_bak + ' '; + t << check_manifest_bak_existence << "fc " << manifest << ' ' << manifest_bak << " && del " << manifest_bak; + t << check_manifest_bak_existence << "rc.exe /fo" << manifest_res << ' ' << manifest_rc; + t << check_manifest_bak_existence; + writeLinkCommand(t, extraLFlags, manifest_res); + t << check_manifest_bak_existence << "del " << manifest_bak; + } else { + t << "\n\t" << "rc.exe /fo" << manifest_res << " " << manifest_rc; + t << "\n\t"; + writeLinkCommand(t, extraLFlags, manifest_res); + } + } else { + // directly embed the manifest in the executable after linking + t << "\n\t"; + writeLinkCommand(t, extraLFlags); + t << "\n\t" << "mt.exe /nologo /manifest " << manifest << " /outputresource:$(DESTDIR_TARGET);1"; + } + } else { + t << "\n\t"; + writeLinkCommand(t); + } } - t << endl << "<<"; QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE"); bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") && !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"); @@ -389,4 +443,16 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) t << endl; } +void NmakeMakefileGenerator::writeLinkCommand(QTextStream &t, const QString &extraFlags, const QString &extraInlineFileContent) +{ + t << "$(LINK) $(LFLAGS)"; + if (!extraFlags.isEmpty()) + t << ' ' << extraFlags; + t << " /OUT:$(DESTDIR_TARGET) @<<\n" + << "$(OBJECTS) $(LIBS)"; + if (!extraInlineFileContent.isEmpty()) + t << ' ' << extraInlineFileContent; + t << "\n<<"; +} + QT_END_NAMESPACE diff --git a/qmake/generators/win32/msvc_nmake.h b/qmake/generators/win32/msvc_nmake.h index 7812902d95..ce8c866adb 100644 --- a/qmake/generators/win32/msvc_nmake.h +++ b/qmake/generators/win32/msvc_nmake.h @@ -53,6 +53,7 @@ class NmakeMakefileGenerator : public Win32MakefileGenerator bool writeMakefile(QTextStream &); void writeImplicitRulesPart(QTextStream &t); void writeBuildRulesPart(QTextStream &t); + void writeLinkCommand(QTextStream &t, const QString &extraFlags = QString(), const QString &extraInlineFileContent = QString()); void init(); protected: |