Index: llvm/cmake/config-ix.cmake =================================================================== --- llvm/cmake/config-ix.cmake +++ llvm/cmake/config-ix.cmake @@ -600,3 +600,17 @@ endif() string(REPLACE " " ";" LLVM_BINDINGS_LIST "${LLVM_BINDINGS}") + +message ( STATUS "find libxml" ) + +if (NOT LIBXML2_FOUND AND NOT (CMAKE_SYSTEM_NAME MATCHES "Windows")) + find_package(LibXml2) + message( STATUS "Ran find_package lixml2" ) +endif() + +if (LIBXML2_FOUND AND NOT LLVM_DISABLE_LIBXML2) + message( STATUS "found libxml2") + add_definitions( -DLIBXML2_ENABLED ) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBXML2_LIBRARIES}) + include_directories(${LIBXML2_INCLUDE_DIR}) +endif() Index: llvm/include/llvm/Support/WindowsManifestMerger.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/WindowsManifestMerger.h @@ -0,0 +1,74 @@ +//===-- 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 +#endif + +#include "llvm/Support/Error.h" + +#if defined(LIBXML2_ENABLED) +#include +#endif + +namespace llvm { + +class MemoryBuffer; + +#if defined(LIBXML2_ENABLED) +typedef xmlDocPtr XMLDocumentImpl; +typedef xmlNodePtr XMLNodeImpl; +#else +typedef void *XMLDocumentImpl; +typedef void *XMLNodeImpl; +#endif + +class WindowsManifestError : public ErrorInfo { +public: + static char ID; + WindowsManifestError(Twine Msg); + void log(raw_ostream &OS) const override; +private: + std::string Msg; +}; + + +class WindowsManifestMerger { +public: + WindowsManifestMerger() = default; + + Error merge(MemoryBuffer& Manifest); + + std::unique_ptr getMergedManifest(); + +private: + static void errorCallback(void *Ctx, const char *Format, ...); + Error getParseError(); + + XMLNodeImpl CombinedRoot = nullptr; + SmallString<256> ParseErrorMsg; + bool ParseErrorOccurred = false; +}; + +} Index: llvm/lib/Support/CMakeLists.txt =================================================================== --- llvm/lib/Support/CMakeLists.txt +++ llvm/lib/Support/CMakeLists.txt @@ -1,4 +1,7 @@ set(system_libs) + +message(STATUS "hello") + if( MSVC OR MINGW ) # libuuid required for FOLDERID_Profile usage in lib/Support/Windows/Path.inc. set(system_libs ${system_libs} psapi shell32 ole32 uuid) @@ -29,6 +32,13 @@ endif() endif( MSVC OR MINGW ) +message (STATUS "checking libxml2 enabled in support") +message( STATUS "adding libxml2 include") + +include_directories(${LIBXML2_INCLUDE_DIR}) +set(system_libs ${system_libs} ${LIBXML2_LIBRARIES}) +message (STATUS ${LIBXML2_INCLUDE_DIR}) + add_llvm_library(LLVMSupport AMDGPUCodeObjectMetadata.cpp APFloat.cpp @@ -110,6 +120,7 @@ Triple.cpp Twine.cpp Unicode.cpp + WindowsManifestMerger.cpp YAMLParser.cpp YAMLTraits.cpp raw_os_ostream.cpp Index: llvm/lib/Support/WindowsManifestMerger.cpp =================================================================== --- /dev/null +++ llvm/lib/Support/WindowsManifestMerger.cpp @@ -0,0 +1,79 @@ +//===-- 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/MemoryBuffer.h" +#include "llvm/Support/WindowsManifestMerger.h" + +#include + +namespace llvm { + +char WindowsManifestError::ID = 0; + +WindowsManifestError::WindowsManifestError(Twine Msg) : Msg(Msg.str()) {} + +void WindowsManifestError::log(raw_ostream &OS) const { + OS << Msg; +} + +Error WindowsManifestMerger::merge(MemoryBuffer& Manifest) { + #if defined(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 WindowsManifestMerger::getMergedManifest() { + std::unique_ptr OutputBuffer; + unsigned char *XmlBuff; + int BufferSize = 0; + #if defined(LIBXML2_ENABLED) + outs() << "LIBXML2_ENABLED\n"; + if (CombinedRoot) + { + std::unique_ptr OutputDoc(xmlNewDoc((const unsigned char *) "1.0")); + xmlDocSetRootElement(OutputDoc.get(), CombinedRoot); + xmlDocDumpMemory(OutputDoc.get(), &XmlBuff, &BufferSize); + } + #endif + + if (BufferSize > 0) + OutputBuffer = MemoryBuffer::getMemBuffer(StringRef(reinterpret_cast(XmlBuff), (size_t) BufferSize)); + else + OutputBuffer = MemoryBuffer::getNewMemBuffer(0); + + return OutputBuffer; +} + +void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) { + WindowsManifestMerger *Merger = (WindowsManifestMerger *)Ctx; + Merger->ParseErrorOccurred = true; + va_list Args; + va_start(Args, Format); + vsnprintf(Merger->ParseErrorMsg.data(), Merger->ParseErrorMsg.size(), Format, Args); + va_end(Args); +} + +Error WindowsManifestMerger::getParseError() { + if (!ParseErrorOccurred) + return Error::success(); + else + return make_error(ParseErrorMsg); +} + +} Index: llvm/test/CMakeLists.txt =================================================================== --- llvm/test/CMakeLists.txt +++ llvm/test/CMakeLists.txt @@ -58,7 +58,6 @@ llvm-mc llvm-mcmarkup llvm-modextract - llvm-mt llvm-nm llvm-objdump llvm-opt-report @@ -138,6 +137,13 @@ ) endif() +if (LIBXML2_FOUND AND NOT LLVM_DISABLE_LIBXML2) + message (STATUS "enabling llvm-mt tests") + 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") Index: llvm/test/tools/llvm-mt/Inputs/test_manifest.manifest =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mt/Inputs/test_manifest.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + Index: llvm/test/tools/llvm-mt/help.test =================================================================== --- llvm/test/tools/llvm-mt/help.test +++ llvm/test/tools/llvm-mt/help.test @@ -1,6 +1,7 @@ RUN: llvm-mt /? | FileCheck %s -check-prefix=HELP -RUN: llvm-mt /inputresource:foo.res /manifest foo.manifest | FileCheck %s -check-prefix=NOT_SUPPORTED +RUN: llvm-mt /inputresource:foo.res /manifest \ +RUN: %p/Inputs/test_manifest.manifest | FileCheck %s -check-prefix=NOT_SUPPORTED HELP: OVERVIEW: Manifest Tool Index: llvm/test/tools/llvm-mt/single_file.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mt/single_file.test @@ -0,0 +1,18 @@ +RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t +RUN: FileCheck --input-file %t %s + +CHECK: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: +CHECK-NEXT: Index: llvm/tools/llvm-mt/llvm-mt.cpp =================================================================== --- llvm/tools/llvm-mt/llvm-mt.cpp +++ llvm/tools/llvm-mt/llvm-mt.cpp @@ -16,12 +16,14 @@ #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/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/WindowsManifestMerger.h" +#include "llvm/Support/raw_ostream.h" #include @@ -30,7 +32,7 @@ namespace { enum ID { - OPT_INVALID = 0, // This is not an option ID. + OPT_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES) \ OPT_##ID, @@ -60,13 +62,29 @@ }; static ExitOnError ExitOnErr; -} +} // namespace LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { - errs() << "llvm-mt error: " << Msg; + errs() << "llvm-mt error: " << Msg << ".\n"; exit(1); } +static void reportError(StringRef Input, std::error_code EC) { + reportError(Twine(Input) + ": " + EC.message()); +} + +void error(std::error_code EC) { + if (!EC) + return; + reportError(EC.message()); +} + +void error(Error EC) { + if (!EC) + return; + handleAllErrors(std::move(EC), + [&](const ErrorInfoBase &EI) { reportError(EI.message()); }); +} int main(int argc_, const char *argv_[]) { sys::PrintStackTraceOnErrorSignal(argv_[0]); @@ -87,9 +105,10 @@ opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC); for (auto &Arg : InputArgs) { - if (Arg->getOption().matches(OPT_UNSUPPORTED)) { - outs() << "Ignoring " << Arg->getOption().getName() << " option; not supported.\n"; - } + if (Arg->getOption().matches(OPT_UNSUPPORTED)) { + outs() << "Ignoring " << Arg->getOption().getName() + << " option; not supported.\n"; + } } if (InputArgs.hasArg(OPT_HELP)) { @@ -100,7 +119,7 @@ std::vector InputFiles = InputArgs.getAllArgValues(OPT_MANIFEST); if (InputFiles.size() == 0) { - reportError("No input file specified.\n"); + reportError("No input file specified"); } StringRef OutputFile; @@ -108,11 +127,38 @@ if (InputArgs.hasArg(OPT_OUT)) { OutputFile = InputArgs.getLastArgValue(OPT_OUT); } else if (InputFiles.size() == 1) { - OutputFile = InputFiles[0]; + OutputFile = InputFiles[0]; } else { - reportError("No output file specified.\n"); + reportError("No output file specified"); } - return 0; + WindowsManifestMerger Merger; + + for (const auto &File : InputFiles) { + ErrorOr> ManifestOrErr = + MemoryBuffer::getFile(File); + if (!ManifestOrErr) + reportError(File, ManifestOrErr.getError()); + MemoryBuffer &Manifest = *ManifestOrErr.get(); + error(Merger.merge(Manifest)); + } + std::unique_ptr OutputBuffer = Merger.getMergedManifest(); + outs() << "Buffer size " << OutputBuffer->getBufferSize() << "\n"; + if (OutputBuffer->getBufferSize() == 0) { + outs() << "Empty manifest not written.\n"; + } else { + ErrorOr> FileOrErr = + FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize()); + outs() << "about to check file or err\n"; + if (!FileOrErr) + reportError(OutputFile, FileOrErr.getError()); + outs() << "created good\n"; + std::unique_ptr FileBuffer = std::move(*FileOrErr); + std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(), + FileBuffer->getBufferStart()); + error(FileBuffer->commit()); + } + + return 0; }