Index: cmake/modules/HandleLLVMOptions.cmake =================================================================== --- cmake/modules/HandleLLVMOptions.cmake +++ cmake/modules/HandleLLVMOptions.cmake @@ -394,7 +394,7 @@ if (${linker_flag_idx} GREATER -1) message(WARNING "/Brepro not compatible with /INCREMENTAL linking - builds will be non-deterministic") else() - append("/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + #append("/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() endif() endif() Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -1052,10 +1052,11 @@ // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. +// XXX uuuuh this looks like a problem? fairly common for header search if (LastError != ERROR_ACCESS_DENIED) return EC; - if (is_directory(Name)) - return make_error_code(errc::is_a_directory); + //if (is_directory(Name)) + //return make_error_code(errc::is_a_directory); return EC; } Index: lib/WindowsManifest/WindowsManifestMerger.cpp =================================================================== --- lib/WindowsManifest/WindowsManifestMerger.cpp +++ lib/WindowsManifest/WindowsManifestMerger.cpp @@ -17,7 +17,13 @@ #include -#if LLVM_LIBXML2_ENABLED +#if defined(_WIN32) +#include +#include +#include +#pragma comment(lib, "shlwapi.lib") +#include +#elif LLVM_LIBXML2_ENABLED #include #endif @@ -42,7 +48,14 @@ private: static void errorCallback(void *Ctx, const char *Format, ...); Error getParseError(); -#if LLVM_LIBXML2_ENABLED +#if defined(_WIN32) + IXMLDOMDocument* CombinedDoc = nullptr; + std::vector> MergedDocs; + + bool Merged = false; + int BufferSize = 0; + std::unique_ptr Buffer; +#elif LLVM_LIBXML2_ENABLED xmlDocPtr CombinedDoc = nullptr; std::vector MergedDocs; @@ -57,8 +70,209 @@ bool ParseErrorOccurred = false; }; -#if LLVM_LIBXML2_ENABLED +#if defined(_WIN32) +static bool isMergeableElement(const bstr_t &ElementName) { + for (const char* S : {"application", "assembly", "assemblyIdentity", + "compatibility", "noInherit", "requestedExecutionLevel", + "requestedPrivileges", "security", "trustInfo"}) { + if (S == ElementName) + return true; + } + return false; +} + +// Recursively merge the two given manifest trees, depending on which elements +// are of a mergeable type, and choose namespaces according to which have +// higher priority. +static Error treeMerge( + IXMLDOMElement* OriginalRoot, IXMLDOMElement* AdditionalRoot) { +#if 0 + if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) + return E; + if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot)) + return E; + xmlNodePtr AdditionalFirstChild = AdditionalRoot->children; + xmlNode StoreNext; + for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) { + xmlNodePtr OriginalChildWithName; + if (!isMergeableElement(Child->name) || + !(OriginalChildWithName = + getChildWithName(OriginalRoot, Child->name)) || + !hasRecognizedNamespace(Child)) { + StoreNext.next = Child->next; + xmlUnlinkNode(Child); + if (!xmlAddChild(OriginalRoot, Child)) { + return make_error(Twine("could not merge ") + + FROM_XML_CHAR(Child->name)); + } + if (auto E = reconcileNamespaces(Child)) { + return E; + } + Child = &StoreNext; + } else if (auto E = treeMerge(OriginalChildWithName, Child)) { + return E; + } + } +#endif + return Error::success(); +} + +WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { +} + +Error hr_error(HRESULT hr) { + char buffer[4096]; + if (!::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, + nullptr, + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + buffer, + _countof(buffer), + nullptr)) + return make_error("unknown error"); + return make_error(Twine(buffer)); +} + +Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( + const MemoryBuffer &Manifest) { + if (Merged) + return make_error( + "merge after getMergedManifest is not supported"); + if (Manifest.getBufferSize() == 0) + return make_error( + "attempted to merge empty manifest"); + Microsoft::WRL::ComPtr ManifestXML; + HRESULT hr = CoCreateInstance( + __uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(ManifestXML.GetAddressOf())); + if (FAILED(hr)) + return hr_error(hr); + // these methods should not fail so don't inspect result + ManifestXML->put_async(VARIANT_FALSE); + ManifestXML->put_validateOnParse(VARIANT_FALSE); // FIXME: ?? + ManifestXML->put_resolveExternals(VARIANT_FALSE); + + int UTF16Len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + Manifest.getBufferStart(), Manifest.getBufferSize(), 0, 0); + if (UTF16Len == 0 && ::GetLastError() == ERROR_NO_UNICODE_TRANSLATION) + return make_error("input invalid utf-8"); + if (UTF16Len == 0) + return make_error("failed to convert input utf-8"); + bstr_t ManifestUTF16(SysAllocStringLen(nullptr, UTF16Len)); + MultiByteToWideChar(CP_UTF8, 0, + Manifest.getBufferStart(), Manifest.getBufferSize(), + ManifestUTF16.GetBSTR(), UTF16Len); + // Use bstr here + VARIANT_BOOL Status; + hr = ManifestXML->loadXML(ManifestUTF16.GetBSTR(), &Status); + if (FAILED(hr)) + return hr_error(hr); + if (Status == VARIANT_FALSE) { + IXMLDOMParseError *XMLErr = nullptr; + hr = ManifestXML->get_parseError(&XMLErr); + if (FAILED(hr)) + return hr_error(hr); + bstr_t Reason; + hr = XMLErr->get_reason(Reason.GetAddress()); + if (FAILED(hr)) + return hr_error(hr); + int UTF8Len = WideCharToMultiByte(CP_UTF8, /*flags=*/0, + Reason.GetBSTR(), Reason.length(), 0, 0, nullptr, nullptr); + SmallString<128> UTF8Reason; + UTF8Reason.reserve(UTF8Len); + UTF8Reason.set_size(UTF8Len); + WideCharToMultiByte(CP_UTF8, /*flags=*/0, Reason.GetBSTR(), Reason.length(), + UTF8Reason.data(), UTF8Reason.size(), nullptr, nullptr); + // FIXME: 0-term? + return make_error(UTF8Reason); + } + + IXMLDOMElement *AdditionalRoot; + hr = ManifestXML->get_documentElement(&AdditionalRoot); + if (FAILED(hr)) + return hr_error(hr); + + // No need to explicitly strip comments with MSXML, it does that at + // parse time already -- no call to stripComments() here. + //setAttributeNamespaces(AdditionalRoot); // FIXME + if (CombinedDoc == nullptr) { + CombinedDoc = ManifestXML.Get(); + } else { + IXMLDOMElement *CombinedRoot; + hr = CombinedDoc->get_documentElement(&CombinedRoot); + if (FAILED(hr)) + return hr_error(hr); + + bstr_t CombinedRootName, AdditionalRootName; + hr = CombinedRoot->get_tagName(CombinedRootName.GetAddress()); + if (FAILED(hr)) + return hr_error(hr); + hr = AdditionalRoot->get_tagName(AdditionalRootName.GetAddress()); + if (FAILED(hr)) + return hr_error(hr); + + if (CombinedRootName != AdditionalRootName || + !isMergeableElement(AdditionalRootName) /*|| FIXME + !hasRecognizedNamespace(AdditionalRoot)*/) { + return make_error("multiple root nodes"); + } + if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) { + return E; + } + } + MergedDocs.push_back(std::move(ManifestXML)); // FIXME + return Error::success(); +} + +std::unique_ptr +WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { + if (!Merged) { + Merged = true; + + if (!CombinedDoc) + return nullptr; + + //xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc); + //std::vector RequiredPrefixes; + //checkAndStripPrefixes(CombinedRoot, RequiredPrefixes); + +#if 0 + // This preserves encoding set on the xml doc + Microsoft::WRL::ComPtr OutStream = SHCreateMemStream(nullptr, 0); + HRESULT hr = CombinedDoc->save(_variant_t(OutStream.Get())); + if (FAILED(hr)) + return nullptr; + + STATSTG Stat; + OutStream->Stat(&Stat, STATFLAG_NONAME); + fprintf(stderr, "size %d\n", Stat.cbSize.LowPart); +#else + // FIXME: createProcessingInstruction() to set encoding and + // standalone? + bstr_t XML; + HRESULT hr = CombinedDoc->get_xml(XML.GetAddress()); + if (FAILED(hr)) + return nullptr; + + BufferSize = WideCharToMultiByte(CP_UTF8, /*flags=*/0, + XML.GetBSTR(), XML.length(), 0, 0, nullptr, nullptr); + std::unique_ptr UTF8(new char[BufferSize]); + WideCharToMultiByte(CP_UTF8, /*flags=*/0, XML.GetBSTR(), XML.length(), + UTF8.get(), BufferSize, nullptr, nullptr); + Buffer = std::move(UTF8); +#endif + } + + // FIXME: why copy? + return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef( + Buffer.get(), (size_t)BufferSize)) + : nullptr; +} + +bool windows_manifest::isAvailable() { return false; } +#elif LLVM_LIBXML2_ENABLED + static const std::pair MtNsHrefsPrefixes[] = { {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"}, {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"}, Index: tools/llvm-mt/llvm-mt.cpp =================================================================== --- tools/llvm-mt/llvm-mt.cpp +++ tools/llvm-mt/llvm-mt.cpp @@ -15,6 +15,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/COM.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/ManagedStatic.h" @@ -90,6 +91,8 @@ sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::SingleThreaded); + ExitOnErr.setBanner("llvm-mt: "); SmallVector argv_buf;