diff options
-rw-r--r-- | lld/COFF/Config.h | 1 | ||||
-rw-r--r-- | lld/COFF/Driver.cpp | 4 | ||||
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 53 | ||||
-rw-r--r-- | lld/COFF/Options.td | 1 | ||||
-rw-r--r-- | lld/test/COFF/Inputs/manifestinput.test | 13 | ||||
-rw-r--r-- | lld/test/COFF/manifestinput.test | 10 |
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> |