option(LLVM_ENABLE_TERMINFO "Use terminfo database if available." ON)
+option(LLVM_ENABLE_LIBXML2 "Use libxml2 if available." ON)
+
option(LLVM_ENABLE_LIBEDIT "Use libedit if available." ON)
option(LLVM_ENABLE_THREADS "Use threads if available." ON)
else()
set(HAVE_TERMINFO 0)
endif()
+
+ set(LLVM_LIBXML2_ENABLED 0)
+ set(LIBXML2_FOUND 0)
+ if(LLVM_ENABLE_LIBXML2)
+ find_package(LibXml2)
+ if (LIBXML2_FOUND)
+ set(LLVM_LIBXML2_ENABLED 1)
+ include_directories(${LIBXML2_INCLUDE_DIR})
+ set(LIBXML2_LIBS "xml2")
+ endif()
+ endif()
endif()
check_library_exists(xar xar_open "" HAVE_LIBXAR)
/* LLVM version string */
#define LLVM_VERSION_STRING "${PACKAGE_VERSION}"
+/* Define if libxml2 is supported on this platform. */
+#cmakedefine LLVM_LIBXML2_ENABLED ${LLVM_LIBXML2_ENABLED}
+
/* Define to the extension used for shared libraries, say, ".so". */
#cmakedefine LTDL_SHLIB_EXT "${LTDL_SHLIB_EXT}"
--- /dev/null
+//===-- WindowsManifestMerger.h ---------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file provides a utility for merging Microsoft .manifest files. These
+// files are xml documents which contain meta-information about applications,
+// such as whether or not admin access is required, system compatibility,
+// versions, etc. Part of the linking process of an executable may require
+// merging several of these .manifest files using a tree-merge following
+// specific rules. Unfortunately, these rules are not documented well
+// anywhere. However, a careful investigation of the behavior of the original
+// Microsoft Manifest Tool (mt.exe) revealed the rules of this merge. As the
+// saying goes, code is the best documentation, so please look below if you are
+// interested in the exact merging requirements.
+//
+// Ref:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa374191(v=vs.85).aspx
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_INCLUDE_LLVM_SUPPORT_WINDOWS_MANIFEST_MERGER_H
+#define LLVM_INCLUDE_LLVM_SUPPORT_WINDOWS_MANIFEST_MERGER_H
+
+#include "llvm/Config/config.h"
+#include "llvm/Support/Error.h"
+
+#if LLVM_LIBXML2_ENABLED
+#include <libxml/xmlreader.h>
+#endif
+
+namespace llvm {
+
+class MemoryBuffer;
+
+#if LLVM_LIBXML2_ENABLED
+typedef xmlDocPtr XMLDocumentImpl;
+typedef xmlNodePtr XMLNodeImpl;
+#else
+typedef void *XMLDocumentImpl;
+typedef void *XMLNodeImpl;
+#endif
+
+class WindowsManifestError : public ErrorInfo<WindowsManifestError, ECError> {
+public:
+ static char ID;
+ WindowsManifestError(const Twine &Msg);
+ void log(raw_ostream &OS) const override;
+
+private:
+ std::string Msg;
+};
+
+class WindowsManifestMerger {
+public:
+ Error merge(const MemoryBuffer &Manifest);
+
+ // Returns vector containing merged xml manifest, or uninitialized vector for
+ // empty manifest.
+ std::unique_ptr<MemoryBuffer> getMergedManifest();
+
+private:
+ static void errorCallback(void *Ctx, const char *Format, ...);
+ Error getParseError();
+
+ XMLNodeImpl CombinedRoot = nullptr;
+ bool ParseErrorOccurred = false;
+};
+
+} // namespace llvm
+#endif
if( UNIX AND NOT (BEOS OR HAIKU) )
set(system_libs ${system_libs} m)
endif()
+ if( LLVM_LIBXML2_ENABLED )
+ set(system_libs ${system_libs} ${LIBXML2_LIBS})
+ endif()
endif( MSVC OR MINGW )
add_llvm_library(LLVMSupport
Triple.cpp
Twine.cpp
Unicode.cpp
+ WindowsManifestMerger.cpp
YAMLParser.cpp
YAMLTraits.cpp
raw_os_ostream.cpp
--- /dev/null
+//===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file implements the .manifest merger class.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/WindowsManifestMerger.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <stdarg.h>
+
+namespace llvm {
+
+char WindowsManifestError::ID = 0;
+
+WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
+
+void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
+
+Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
+#if LLVM_LIBXML2_ENABLED
+ xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
+ XMLDocumentImpl ManifestXML =
+ xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
+ "manifest.xml", nullptr, 0);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+ if (auto E = getParseError())
+ return E;
+ CombinedRoot = xmlDocGetRootElement(ManifestXML);
+#endif
+ return Error::success();
+}
+
+std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
+#if LLVM_LIBXML2_ENABLED
+ unsigned char *XmlBuff;
+ int BufferSize = 0;
+ if (CombinedRoot) {
+ std::unique_ptr<xmlDoc> OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
+ xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
+ xmlDocDumpMemory(OutputDoc.get(), &XmlBuff, &BufferSize);
+ }
+ if (BufferSize == 0)
+ return nullptr;
+ return MemoryBuffer::getMemBuffer(
+ StringRef(reinterpret_cast<const char *>(XmlBuff), (size_t)BufferSize));
+#else
+ return nullptr;
+#endif
+}
+
+void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) {
+ auto *Merger = (WindowsManifestMerger *)Ctx;
+ Merger->ParseErrorOccurred = true;
+}
+
+Error WindowsManifestMerger::getParseError() {
+ if (!ParseErrorOccurred)
+ return Error::success();
+ return make_error<WindowsManifestError>("invalid xml document");
+}
+
+} // namespace llvm
llvm-mc
llvm-mcmarkup
llvm-modextract
- llvm-mt
llvm-nm
llvm-objdump
llvm-opt-report
)
endif()
+if (LLVM_LIBXML2_ENABLED)
+ set(LLVM_TEST_DEPENDS ${LLVM_TEST_DEPENDS}
+ llvm-mt
+ )
+endif()
+
add_custom_target(llvm-test-depends DEPENDS ${LLVM_TEST_DEPENDS})
set_target_properties(llvm-test-depends PROPERTIES FOLDER "Tests")
r"\bllvm-config\b",
r"\bllvm-cov\b",
r"\bllvm-cxxdump\b",
+ r"\bllvm-cvtres\b",
r"\bllvm-diff\b",
r"\bllvm-dis\b",
r"\bllvm-dsymutil\b",
# For tools that are optional depending on the config, we won't warn
# if they're missing.
for pattern in [r"\bllvm-go\b",
+ r"\bllvm-mt\b",
r"\bKaleidoscope-Ch3\b",
r"\bKaleidoscope-Ch4\b",
r"\bKaleidoscope-Ch5\b",
if config.enable_abi_breaking_checks == "1":
config.available_features.add('abi-breaking-checks')
+
+if config.llvm_disable_libxml2 == "OFF" and config.have_libxml2 == "TRUE":
+ config.available_features.add('libxml2')
+
\ No newline at end of file
config.have_dia_sdk = @LLVM_ENABLE_DIA_SDK@
config.enable_ffi = @LLVM_ENABLE_FFI@
config.build_shared_libs = @BUILD_SHARED_LIBS@
+config.llvm_disable_libxml2 = "@LLVM_DISABLE_LIBXML2@"
+config.have_libxml2 = "@LIBXML2_FOUND@"
# Support substitution of the tools_dir with user parameters. This is
# used when we can't determine the tool dir at configuration time.
--- /dev/null
+<?xml version="1.0"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <trustInfo>
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="3" uiAccess="1"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity program="displayDriver"/>
+ </dependentAssembly>
+ </dependency>
+</assembly>
RUN: llvm-mt /h | FileCheck %s -check-prefix=HELP
-RUN: llvm-mt /inputresource:foo.res /manifest foo.manifest | FileCheck %s -check-prefix=NOT_SUPPORTED
-
HELP: OVERVIEW: Manifest Tool
-
-NOT_SUPPORTED: llvm-mt: ignoring unsupported 'inputresource:' option
--- /dev/null
+REQUIRES: libxml2
+UNSUPPORTED: windows
+
+RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t
+RUN: diff %p/Inputs/test_manifest.manifest %t
--- /dev/null
+REQUIRES: libxml2
+UNSUPPORTED: windows
+
+RUN: not llvm-mt /manifest %p/Inputs/bad.manifest 2>&1 >/dev/null | FileCheck %s
+
+CHECK: llvm-mt error: invalid xml document
+
+RUN: llvm-mt /inputresource:foo.res /manifest \
+RUN: %p/Inputs/test_manifest.manifest | FileCheck %s -check-prefix=NOT_SUPPORTED
+
+NOT_SUPPORTED: llvm-mt: ignoring unsupported 'inputresource:' option
llvm-mc
llvm-mcmarkup
llvm-modextract
+ llvm-mt
llvm-nm
llvm-objdump
llvm-pdbutil
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/WindowsManifestMerger.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
exit(1);
}
+static void reportError(StringRef Input, std::error_code EC) {
+ reportError(Twine(Input) + ": " + EC.message());
+}
+
+void error(std::error_code EC) {
+ if (EC)
+ reportError(EC.message());
+}
+
+void error(Error EC) {
+ if (EC)
+ handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
+ reportError(EI.message());
+ });
+}
+
int main(int argc, const char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
}
StringRef OutputFile;
-
if (InputArgs.hasArg(OPT_out)) {
OutputFile = InputArgs.getLastArgValue(OPT_out);
} else if (InputFiles.size() == 1) {
reportError("no output file specified");
}
+ WindowsManifestMerger Merger;
+
+ for (const auto &File : InputFiles) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
+ MemoryBuffer::getFile(File);
+ if (!ManifestOrErr)
+ reportError(File, ManifestOrErr.getError());
+ MemoryBuffer &Manifest = *ManifestOrErr.get();
+ error(Merger.merge(Manifest));
+ }
+
+ std::unique_ptr<MemoryBuffer> OutputBuffer = Merger.getMergedManifest();
+ if (!OutputBuffer)
+ reportError("empty manifest not written");
+ ErrorOr<std::unique_ptr<FileOutputBuffer>> FileOrErr =
+ FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
+ if (!FileOrErr)
+ reportError(OutputFile, FileOrErr.getError());
+ std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
+ std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
+ FileBuffer->getBufferStart());
+ error(FileBuffer->commit());
return 0;
}