summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@nokia.com>2012-08-15 12:18:49 +0200
committerQt by Nokia <qt-info@nokia.com>2012-08-16 08:26:24 +0200
commitc9406bcffe63f1ce232ce91b00be294e0135282a (patch)
tree74aa70ca0ba7911c37c1d7b423db9bfc7c11c524 /qmake
parent15b5b28425f52fcbb2b85c94ec485af841adb4b5 (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.cpp76
-rw-r--r--qmake/generators/win32/msvc_nmake.h1
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: