mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Implement parsing and writing of a single xml manifest file.
Summary: Implement parsing and writing of a single xml manifest file. Subscribers: mgorny, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D35425 llvm-svn: 308679
This commit is contained in:
parent
8ff7545177
commit
2a72bb6108
@ -363,6 +363,8 @@ set(LLVM_TARGET_ARCH "host"
|
||||
|
||||
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)
|
||||
|
@ -155,6 +155,17 @@ if( NOT PURE_WINDOWS AND NOT LLVM_USE_SANITIZER MATCHES "Memory.*")
|
||||
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)
|
||||
|
@ -383,6 +383,9 @@
|
||||
/* 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}"
|
||||
|
||||
|
75
include/llvm/Support/WindowsManifestMerger.h
Normal file
75
include/llvm/Support/WindowsManifestMerger.h
Normal file
@ -0,0 +1,75 @@
|
||||
//===-- 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
|
@ -27,6 +27,9 @@ elseif( CMAKE_HOST_UNIX )
|
||||
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
|
||||
@ -110,6 +113,7 @@ add_llvm_library(LLVMSupport
|
||||
Triple.cpp
|
||||
Twine.cpp
|
||||
Unicode.cpp
|
||||
WindowsManifestMerger.cpp
|
||||
YAMLParser.cpp
|
||||
YAMLTraits.cpp
|
||||
raw_os_ostream.cpp
|
||||
|
70
lib/Support/WindowsManifestMerger.cpp
Normal file
70
lib/Support/WindowsManifestMerger.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
//===-- 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
|
@ -59,7 +59,6 @@ set(LLVM_TEST_DEPENDS
|
||||
llvm-mc
|
||||
llvm-mcmarkup
|
||||
llvm-modextract
|
||||
llvm-mt
|
||||
llvm-nm
|
||||
llvm-objdump
|
||||
llvm-opt-report
|
||||
@ -140,6 +139,12 @@ if(TARGET ocaml_llvm)
|
||||
)
|
||||
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")
|
||||
|
||||
|
@ -288,6 +288,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
|
||||
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",
|
||||
@ -337,6 +338,7 @@ for pattern in [r"\bbugpoint\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",
|
||||
@ -550,3 +552,7 @@ if config.have_libxar:
|
||||
|
||||
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')
|
||||
|
@ -40,6 +40,8 @@ config.have_libxar = @HAVE_LIBXAR@
|
||||
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.
|
||||
|
BIN
test/tools/llvm-mt/Inputs/bad.manifest
Normal file
BIN
test/tools/llvm-mt/Inputs/bad.manifest
Normal file
Binary file not shown.
15
test/tools/llvm-mt/Inputs/test_manifest.manifest
Normal file
15
test/tools/llvm-mt/Inputs/test_manifest.manifest
Normal file
@ -0,0 +1,15 @@
|
||||
<?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>
|
@ -1,7 +1,3 @@
|
||||
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
|
||||
|
5
test/tools/llvm-mt/single_file.test
Normal file
5
test/tools/llvm-mt/single_file.test
Normal file
@ -0,0 +1,5 @@
|
||||
REQUIRES: libxml2
|
||||
UNSUPPORTED: windows
|
||||
|
||||
RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t
|
||||
RUN: diff %p/Inputs/test_manifest.manifest %t
|
11
test/tools/llvm-mt/xml_error.test
Normal file
11
test/tools/llvm-mt/xml_error.test
Normal file
@ -0,0 +1,11 @@
|
||||
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
|
@ -38,6 +38,7 @@ subdirectories =
|
||||
llvm-mc
|
||||
llvm-mcmarkup
|
||||
llvm-modextract
|
||||
llvm-mt
|
||||
llvm-nm
|
||||
llvm-objdump
|
||||
llvm-pdbutil
|
||||
|
@ -16,11 +16,13 @@
|
||||
#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>
|
||||
@ -67,6 +69,22 @@ LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
|
||||
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);
|
||||
@ -104,7 +122,6 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
|
||||
StringRef OutputFile;
|
||||
|
||||
if (InputArgs.hasArg(OPT_out)) {
|
||||
OutputFile = InputArgs.getLastArgValue(OPT_out);
|
||||
} else if (InputFiles.size() == 1) {
|
||||
@ -113,5 +130,27 @@ int main(int argc, const char **argv) {
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user