Integrate manifest merging library into LLD.

Summary: Now that the llvm-mt manifest merging libraries are complete, we may use them to merge manifests instead of needing to shell out to mt.exe.

Subscribers: mgorny, llvm-commits

Differential Revision: https://reviews.llvm.org/D36255

llvm-svn: 311424
This commit is contained in:
Eric Beckmann 2017-08-22 03:15:28 +00:00
parent 6683c81af8
commit 87c6acf38a
6 changed files with 80 additions and 35 deletions

View File

@ -39,6 +39,7 @@ add_lld_library(lldCOFF
Target
Option
Support
WindowsManifest
LINK_LIBS
lldCore

View File

@ -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 <memory>
using namespace llvm::COFF;
@ -328,16 +330,9 @@ public:
};
}
// 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.
@ -362,37 +357,83 @@ TemporaryFile createDefaultXml() {
<< " </dependency>\n";
}
OS << "</assembly>\n";
return Ret;
}
static Expected<std::unique_ptr<MemoryBuffer>>
createManifestXmlWithInternalMt(std::string &DefaultXml) {
std::unique_ptr<MemoryBuffer> DefaultXmlCopy =
MemoryBuffer::getMemBufferCopy(DefaultXml);
windows_manifest::WindowsManifestMerger Merger;
if (auto E = Merger.merge(*DefaultXmlCopy.get()))
return std::move(E);
for (StringRef Filename : Config->ManifestInput) {
std::unique_ptr<MemoryBuffer> Manifest =
check(MemoryBuffer::getFile(Filename));
if (auto E = Merger.merge(*Manifest.get())) {
warn("internal manifest tool failed on file " + Filename);
return std::move(E);
}
}
return Merger.getMergedManifest();
}
static std::unique_ptr<MemoryBuffer>
createManifestXmlWithExternalMt(std::string &DefaultXml) {
const Triple HostTriple(Triple::normalize(LLVM_HOST_TRIPLE));
if (!HostTriple.isOSWindows())
fatal("manifest ignored because no external manifest tool available");
// 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();
return File;
}
static std::string readFile(StringRef Path) {
std::unique_ptr<MemoryBuffer> MB =
check(MemoryBuffer::getFile(Path), "could not open " + Path);
return MB->getBuffer();
}
static std::string createManifestXml() {
// Create the default manifest file.
TemporaryFile File1 = createDefaultXml();
if (Config->ManifestInput.empty())
return readFile(File1.Path);
// 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);
return check(MemoryBuffer::getFile(User.Path), "could not open " + User.Path);
}
static std::string createManifestXml() {
std::string DefaultXml = createDefaultXml();
if (Config->ManifestInput.empty())
return DefaultXml;
// 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.
Expected<std::unique_ptr<MemoryBuffer>> OutputBufferOrError =
createManifestXmlWithInternalMt(DefaultXml);
if (OutputBufferOrError)
return OutputBufferOrError.get()->getBuffer();
// Using built-in library failed, possibly because libxml2 is not installed.
// Shell out to mt.exe instead.
handleAllErrors(std::move(OutputBufferOrError.takeError()),
[&](ErrorInfoBase &EIB) {
warn("error with internal manifest tool: " + EIB.message());
});
std::unique_ptr<MemoryBuffer> OutputBuffer;
OutputBuffer = createManifestXmlWithExternalMt(DefaultXml);
return OutputBuffer->getBuffer();
}
static std::unique_ptr<MemoryBuffer>

View File

@ -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 \

View File

@ -265,6 +265,8 @@ llvm_config_cmd.wait()
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')

View File

@ -4,6 +4,7 @@ config.llvm_src_root = "@LLVM_SOURCE_DIR@"
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@"

View File

@ -671,7 +671,7 @@ WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
const MemoryBuffer &Manifest) {
return Error::success();
return make_error<WindowsManifestError>("no libxml2");
}
std::unique_ptr<MemoryBuffer>