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 @@ -20,6 +20,7 @@ #include "Symbols.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include "llvm/Object/WindowsResource.h" @@ -32,6 +33,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 +314,9 @@ }; } -// Create the default manifest file as a temporary file. -TemporaryFile createDefaultXml() { - // Create a temporary file. - TemporaryFile File("defaultxml", "manifest"); - - // 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); +static std::string createDefaultXml() { + std::string Ret; + raw_string_ostream OS(Ret); // 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 +341,81 @@ << " \n"; } OS << "\n"; - OS.close(); - return File; + return Ret; } -static std::string readFile(StringRef Path) { - std::unique_ptr MB = - check(MemoryBuffer::getFile(Path), "could not open " + Path); - return MB->getBuffer(); +static void +createManifestXmlWithInternalMt(std::unique_ptr &OutputBuffer, + std::string &DefaultXml) { + 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); + } + + OutputBuffer = Merger.getMergedManifest(); } -static std::string createManifestXml() { - // Create the default manifest file. - TemporaryFile File1 = createDefaultXml(); - if (Config->ManifestInput.empty()) - return readFile(File1.Path); +static void +createManifestXmlWithExternalMt(std::unique_ptr &OutputBuffer, + std::string &DefaultXml) { + const Triple HostTriple(Triple::normalize(LLVM_HOST_TRIPLE)); + if (!HostTriple.isOSWindows()) { + warn("manifest ignored because no manifest merging tool available"); + OutputBuffer = MemoryBuffer::getMemBufferCopy(std::string()); + } + // 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(); - // If manifest files are supplied by the user using /MANIFESTINPUT - // option, we need to merge them with the default manifest. - TemporaryFile File2("user", "manifest"); + // 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); + + OutputBuffer = + check(MemoryBuffer::getFile(User.Path), "could not open " + User.Path); +} + +static std::string createManifestXml() { + std::string DefaultXml = createDefaultXml(); + if (Config->ManifestInput.empty()) + return DefaultXml; + + std::unique_ptr OutputBuffer; + // If manifest files are supplied by the user using /MANIFESTINPUT + // option, we need to merge them with the default manifest. If libxml2 + // is enabled, we may merge them with LLVM's own library. + createManifestXmlWithInternalMt(OutputBuffer, DefaultXml); + if (OutputBuffer) + return OutputBuffer->getBuffer(); + // Using built-in library failed, possibly because libxml2 is not installed. + // Shell out to mt.exe instead. + createManifestXmlWithExternalMt(OutputBuffer, DefaultXml); + return OutputBuffer->getBuffer(); } 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 @@ -265,6 +265,7 @@ config.environment['LLD_VERSION'] = 'LLD 1.0' # 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') +# cvtres, which always accompanies it. Alternatively, check if we can use +# libxml2 to merge manifests. +if (lit.util.which('cvtres', config.environment['PATH'])) or (config.llvm_libxml2_enabled == "1"): + config.available_features.add('manifest_tool') 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@"