summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Config.h1
-rw-r--r--lld/COFF/Driver.cpp4
-rw-r--r--lld/COFF/DriverUtils.cpp53
-rw-r--r--lld/COFF/Options.td1
-rw-r--r--lld/test/COFF/Inputs/manifestinput.test13
-rw-r--r--lld/test/COFF/manifestinput.test10
6 files changed, 76 insertions, 6 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 9cfccadba5f..4e6064a6a23 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -111,6 +111,7 @@ struct Configuration {
int ManifestID = 1;
StringRef ManifestDependency;
bool ManifestUAC = true;
+ std::vector<std::string> ManifestInput;
StringRef ManifestLevel = "'asInvoker'";
StringRef ManifestUIAccess = "'false'";
StringRef ManifestFile;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 2a71343aa30..8845d415469 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -423,6 +423,10 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_manifestfile))
Config->ManifestFile = Arg->getValue();
+ // Handle /manifestinput
+ for (auto *Arg : Args.filtered(OPT_manifestinput))
+ Config->ManifestInput.push_back(Arg->getValue());
+
// Handle miscellaneous boolean flags.
if (Args.hasArg(OPT_allowbind_no))
Config->AllowBind = false;
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 014fee7fefd..ba83f8691b3 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -240,10 +240,17 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
}
}
-// Create a manifest file contents.
-static std::string createManifestXml() {
- std::string S;
- llvm::raw_string_ostream OS(S);
+// Create the default manifest file as a temporary file.
+static std::string createDefaultXml() {
+ // Create a temporary file.
+ SmallString<128> Path;
+ std::error_code EC = sys::fs::createTemporaryFile("tmp", "manifest", Path);
+ error(EC, "cannot create a temporary file");
+
+ // Open the temporary file for writing.
+ llvm::raw_fd_ostream OS(Path, EC, sys::fs::F_Text);
+ error(EC, Twine("failed to open ") + Path);
+
// Emit the XML. Note that we do *not* verify that the XML attributes are
// syntactically correct. This is intentional for link.exe compatibility.
OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
@@ -267,8 +274,42 @@ static std::string createManifestXml() {
}
}
OS << "</assembly>\n";
- OS.flush();
- return S;
+ OS.close();
+ return StringRef(Path);
+}
+
+static std::string readFile(StringRef Path) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = MemoryBuffer::getFile(Path);
+ error(BufOrErr, "Could not open " + Path);
+ std::unique_ptr<MemoryBuffer> Buf(std::move(*BufOrErr));
+ return Buf->getBuffer();
+}
+
+static std::string createManifestXml() {
+ // Create the default manifest file.
+ std::string Path1 = createDefaultXml();
+ if (Config->ManifestInput.empty())
+ return readFile(Path1);
+
+ // If manifest files are supplied by the user using /MANIFESTINPUT
+ // option, we need to merge them with the default manifest.
+ SmallString<128> Path2;
+ std::error_code EC = sys::fs::createTemporaryFile("tmp", "manifest", Path2);
+ error(EC, "cannot create a temporary file");
+ FileRemover Remover1(Path1);
+ FileRemover Remover2(Path2);
+
+ Executor E("mt.exe");
+ E.add("/manifest");
+ E.add(Path1);
+ for (StringRef Filename : Config->ManifestInput) {
+ E.add("/manifest");
+ E.add(Filename);
+ }
+ E.add("/nologo");
+ E.add("/out:" + StringRef(Path2));
+ E.run();
+ return readFile(Path2);
}
// Create a resource file containing a manifest XML.
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index ceb25ccb5c7..e5c9c5b4635 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -48,6 +48,7 @@ def manifestuac : P<"manifestuac", "User access control">;
def manifestfile : P<"manifestfile", "Manifest file path">;
def manifestdependency : P<"manifestdependency",
"Attributes for <dependency> in manifest file">;
+def manifestinput : P<"manifestinput", "Specify manifest file">;
// We cannot use multiclass P because class name "incl" is different
// from its command line option name. We do this because "include" is
diff --git a/lld/test/COFF/Inputs/manifestinput.test b/lld/test/COFF/Inputs/manifestinput.test
new file mode 100644
index 00000000000..c65739225a5
--- /dev/null
+++ b/lld/test/COFF/Inputs/manifestinput.test
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type='win32'
+ name='Microsoft.Windows.Common-Controls'
+ version='6.0.0.0'
+ processorArchitecture='*'
+ publicKeyToken='6595b64144ccf1df'
+ language='*' />
+ </dependentAssembly>
+ </dependency>
+</assembly>
diff --git a/lld/test/COFF/manifestinput.test b/lld/test/COFF/manifestinput.test
new file mode 100644
index 00000000000..376d404d604
--- /dev/null
+++ b/lld/test/COFF/manifestinput.test
@@ -0,0 +1,10 @@
+# REQUIRES: winres
+
+# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj
+# RUN: lld-link /out:%t.exe /entry:main \
+# RUN: /manifestuac:"level='requireAdministrator'" \
+# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj
+# RUN: FileCheck %s < %t.exe.manifest
+
+CHECK: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+CHECK: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity></dependentAssembly></dependency><trustInfo><security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel></requestedPrivileges></security></trustInfo></assembly>
OpenPOWER on IntegriCloud