Index: lld/COFF/CMakeLists.txt =================================================================== --- lld/COFF/CMakeLists.txt +++ lld/COFF/CMakeLists.txt @@ -39,6 +39,7 @@ Target Option Support + WindowsManifest LINK_LIBS lldCore Index: lld/COFF/DriverUtils.cpp =================================================================== --- lld/COFF/DriverUtils.cpp +++ lld/COFF/DriverUtils.cpp @@ -32,6 +32,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/WindowsManifest/WindowsManifestMerger.h" #include using namespace llvm::COFF; @@ -312,16 +313,12 @@ }; } -// Create the default manifest file as a temporary file. -TemporaryFile createDefaultXml() { +std::string createDefaultXml() { // Create a temporary file. - TemporaryFile File("defaultxml", "manifest"); + std::string DefaultXml; // Open the temporary file for writing. - std::error_code EC; - raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text); - if (EC) - fatal(EC, "failed to open " + File.Path); + raw_string_ostream OS(DefaultXml); // Emit the XML. Note that we do *not* verify that the XML attributes are // syntactically correct. This is intentional for link.exe compatibility. @@ -346,37 +343,65 @@ << " \n"; } OS << "\n"; - OS.close(); - return File; -} - -static std::string readFile(StringRef Path) { - std::unique_ptr MB = - check(MemoryBuffer::getFile(Path), "could not open " + Path); - return MB->getBuffer(); + OS.flush(); + return DefaultXml; } static std::string createManifestXml() { - // Create the default manifest file. - TemporaryFile File1 = createDefaultXml(); + std::string DefaultXml = createDefaultXml(); if (Config->ManifestInput.empty()) - return readFile(File1.Path); - + return DefaultXml; +#if LLVM_LIBXML2_ENABLED // If manifest files are supplied by the user using /MANIFESTINPUT - // option, we need to merge them with the default manifest. - TemporaryFile File2("user", "manifest"); + // option, we need to merge them with the default manifest. If libxml2 + // is enabled, we may merge them with LLVM's own library. + + std::unique_ptr DefaultXmlCopy = + MemoryBuffer::getMemBufferCopy(DefaultXml); + + windows_manifest::WindowsManifestMerger Merger; + if (auto E = Merger.merge(*DefaultXmlCopy.get())) { + fatal(E, "failed to merge default manifest"); + } + + for (StringRef Filename : Config->ManifestInput) { + std::unique_ptr Manifest = + check(MemoryBuffer::getFile(Filename)); + if (auto E = Merger.merge(*Manifest.get())) + fatal(E, "failed to merge " + Filename); + } + + std::unique_ptr OutputBuffer = Merger.getMergedManifest(); + return OutputBuffer->getBuffer().str(); +#else + // Create the default manifest file as a temporary file. + TemporaryFile Default("defaultxml", "manifest"); + std::error_code EC; + raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); + if (EC) + fatal(EC, "failed to open " + Default.Path); + OS << DefaultXml; + OS.close(); + + // Merge user-supplied manifests if they are given. Since libxml2 is not + // enabled, we must shell out to Microsoft's mt.exe tool. + TemporaryFile User("user", "manifest"); Executor E("mt.exe"); E.add("/manifest"); - E.add(File1.Path); + E.add(Default.Path); for (StringRef Filename : Config->ManifestInput) { E.add("/manifest"); E.add(Filename); } E.add("/nologo"); - E.add("/out:" + StringRef(File2.Path)); + E.add("/out:" + StringRef(User.Path)); E.run(); - return readFile(File2.Path); + + std::unique_ptr MB = + check(MemoryBuffer::getFile(User.Path), "could not open " + User.Path); + return MB->getBuffer(); +#endif } static std::unique_ptr Index: lld/test/COFF/manifestinput.test =================================================================== --- lld/test/COFF/manifestinput.test +++ lld/test/COFF/manifestinput.test @@ -1,4 +1,4 @@ -# REQUIRES: win_mt +# REQUIRES: manifest_tool # RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj # RUN: lld-link /out:%t.exe /entry:main \ Index: lld/test/lit.cfg =================================================================== --- lld/test/lit.cfg +++ lld/test/lit.cfg @@ -266,5 +266,5 @@ # Indirectly check if the mt.exe Microsoft utility exists by searching for # cvtres, which always accompanies it. -if lit.util.which('cvtres', config.environment['PATH']): - config.available_features.add('win_mt') +if (lit.util.which('cvtres', config.environment['PATH'])) or (config.llvm_libxml2_enabled == "1"): + config.available_features.add('manifest_tool') \ No newline at end of file Index: lld/test/lit.site.cfg.in =================================================================== --- lld/test/lit.site.cfg.in +++ lld/test/lit.site.cfg.in @@ -4,6 +4,7 @@ config.llvm_obj_root = "@LLVM_BINARY_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" config.llvm_libs_dir = "@LLVM_LIBS_DIR@" +config.llvm_libxml2_enabled = "@LLVM_LIBXML2_ENABLED@" config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@" config.lld_obj_root = "@LLD_BINARY_DIR@" config.lld_libs_dir = "@LLVM_LIBRARY_OUTPUT_INTDIR@"