mirror of https://github.com/qt/qtbase.git
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>
This commit is contained in:
parent
15b5b28425
commit
c9406bcffe
|
@ -1,12 +0,0 @@
|
||||||
!if(plugin:no_plugin_manifest):if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*|win32-msvc2012*):!static:equals(TEMPLATE, "lib") {
|
|
||||||
MANIFEST_DIR = $$OBJECTS_DIR
|
|
||||||
isEmpty(MANIFEST_DIR):MANIFEST_DIR = .
|
|
||||||
NOPATH_TARGET = $$TARGET
|
|
||||||
NOPATH_TARGET ~= s,\\\\ , ,q # Remove space escaping (NOPATH_TARGET is quoted)
|
|
||||||
NOPATH_TARGET ~= s,\\\\,/,g # Change to single type separators
|
|
||||||
NOPATH_TARGET ~= s,^(.*/)+,, # Remove all paths
|
|
||||||
QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\")
|
|
||||||
!isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
|
|
||||||
QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$shell_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);2)$$QMAKE_POST_LINK
|
|
||||||
QMAKE_CLEAN += $$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*|win32-msvc2012*):equals(TEMPLATE, "app") {
|
|
||||||
MANIFEST_DIR = $$OBJECTS_DIR
|
|
||||||
isEmpty(MANIFEST_DIR):MANIFEST_DIR = .
|
|
||||||
NOPATH_TARGET = $$TARGET
|
|
||||||
NOPATH_TARGET ~= s,\\\\ , ,q # Remove space escaping (NOPATH_TARGET is quoted)
|
|
||||||
NOPATH_TARGET ~= s,\\\\,/,g # Change to single type separators
|
|
||||||
NOPATH_TARGET ~= s,^(.*/)+,, # Remove all paths
|
|
||||||
QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\")
|
|
||||||
!isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK
|
|
||||||
QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest $$shell_quote($$shell_path($$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest)) -outputresource:$(DESTDIR_TARGET);1)$$QMAKE_POST_LINK
|
|
||||||
QMAKE_CLEAN += $$MANIFEST_DIR/$${NOPATH_TARGET}.intermediate.manifest
|
|
||||||
}
|
|
|
@ -357,7 +357,8 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
|
||||||
|
|
||||||
void NmakeMakefileGenerator::writeBuildRulesPart(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 << "first:" << endl;
|
||||||
t << "all:" << endl;
|
t << "all:" << endl;
|
||||||
return;
|
return;
|
||||||
|
@ -371,12 +372,65 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
|
||||||
t << "\n\t" <<var("QMAKE_PRE_LINK");
|
t << "\n\t" <<var("QMAKE_PRE_LINK");
|
||||||
if(project->isActiveConfig("staticlib")) {
|
if(project->isActiveConfig("staticlib")) {
|
||||||
t << "\n\t" << "$(LIBAPP) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) @<<" << "\n\t "
|
t << "\n\t" << "$(LIBAPP) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) @<<" << "\n\t "
|
||||||
<< "$(OBJECTS)";
|
<< "$(OBJECTS)"
|
||||||
|
<< "\n<<";
|
||||||
} else {
|
} else {
|
||||||
t << "\n\t" << "$(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<< " << "\n\t "
|
const bool embedManifest = ((templateName == "app" && project->isActiveConfig("embed_manifest_exe"))
|
||||||
<< "$(OBJECTS) $(LIBS)";
|
|| (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");
|
QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
|
||||||
bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
|
bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
|
||||||
!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
|
!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
|
||||||
|
@ -389,4 +443,16 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
|
||||||
t << endl;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -53,6 +53,7 @@ class NmakeMakefileGenerator : public Win32MakefileGenerator
|
||||||
bool writeMakefile(QTextStream &);
|
bool writeMakefile(QTextStream &);
|
||||||
void writeImplicitRulesPart(QTextStream &t);
|
void writeImplicitRulesPart(QTextStream &t);
|
||||||
void writeBuildRulesPart(QTextStream &t);
|
void writeBuildRulesPart(QTextStream &t);
|
||||||
|
void writeLinkCommand(QTextStream &t, const QString &extraFlags = QString(), const QString &extraInlineFileContent = QString());
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue