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,33 @@ bool ParseErrorOccurred = false; }; -#if LLVM_LIBXML2_ENABLED +#if defined(_WIN32) +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)); +} +#define RET_ON_FAILED(x) \ + do { HRESULT hr = x; if (FAILED(hr)) return hr_error(hr); } while (0) + +static void UTF16ToUTF8(const bstr_t& bs, SmallVectorImpl *s) { + int UTF8Len = WideCharToMultiByte(CP_UTF8, /*flags=*/0, + (wchar_t*)bs, bs.length(), 0, 0, nullptr, nullptr); + s->reserve(UTF8Len); + s->set_size(UTF8Len); + WideCharToMultiByte(CP_UTF8, /*flags=*/0, (wchar_t*)bs, bs.length(), + s->data(), s->size(), nullptr, nullptr); + // FIXME: 0-term? +} + static const std::pair MtNsHrefsPrefixes[] = { {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"}, {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"}, @@ -67,6 +105,247 @@ "ms_windowsSettings"}, {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}}; +static bool isMergeableElement(const bstr_t &ElementName) { + for (const char* S : {"application", "assembly", "assemblyIdentity", + "compatibility", "noInherit", "requestedExecutionLevel", + "requestedPrivileges", "security", "trustInfo"}) { + // bstr_t(char*) does multibyte to wide, based on the system's current + // ANSI codepage setting. Since these are all 7-bit ASCII, that's ok. + if (bstr_t(S) == ElementName) + return true; + } + return false; +} + +static Microsoft::WRL::ComPtr +getChildWithName(IXMLDOMNode *Parent, const bstr_t& ElementName) { + IXMLDOMNodeList *Children; + long Length; + if (FAILED(Parent->get_childNodes(&Children)) || + FAILED(Children->get_length(&Length))) + return nullptr; + for (long i = 0; i < Length; ++i) { + Microsoft::WRL::ComPtr Child; + DOMNodeType ChildType; + if (FAILED(Children->get_item(i, Child.GetAddressOf())) || + FAILED(Child->get_nodeType(&ChildType))) + return nullptr; + if (ChildType != NODE_ELEMENT) + continue; + // Note: Can't just upcast COM object, need to QueryInterface(). + Microsoft::WRL::ComPtr ChildElt; + if (FAILED(Child->QueryInterface(ChildElt.GetAddressOf()))) + return nullptr; + bstr_t ChildName; + if (FAILED(ChildElt->get_tagName(ChildName.GetAddress()))) + return nullptr; + if (ChildName == ElementName) + return Child; + } + return nullptr; +} + + +static bool isRecognizedNamespace(StringRef NsHref) { + for (auto &Ns : MtNsHrefsPrefixes) + if (NsHref == Ns.first.data()) + return true; + return false; +} + +static bool hasRecognizedNamespace(IXMLDOMNode *Node) { + bstr_t ns; + if (FAILED(Node->get_namespaceURI(ns.GetAddress()))) + return false; + SmallString<64> UTF8NS; + UTF16ToUTF8(ns, &UTF8NS); + return isRecognizedNamespace(UTF8NS); +} + +// 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( + IXMLDOMNode* OriginalRoot, IXMLDOMNode* AdditionalRoot) { +#if 0 + if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) + return E; + if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot)) + return E; +#endif + Microsoft::WRL::ComPtr AdditionalRootChildren; + RET_ON_FAILED( + AdditionalRoot->get_childNodes(AdditionalRootChildren.GetAddressOf())); + long Length; + RET_ON_FAILED(AdditionalRootChildren->get_length(&Length)); + for (long i = 0; i < Length; ++i) { + Microsoft::WRL::ComPtr Child; + RET_ON_FAILED(AdditionalRootChildren->get_item(i, Child.GetAddressOf())); + + Microsoft::WRL::ComPtr OriginalChildWithName; + + bstr_t ChildName; + DOMNodeType ChildType; + RET_ON_FAILED(Child->get_nodeType(&ChildType)); + if (ChildType == NODE_ELEMENT) { + // Note: Can't just upcast COM object, need to QueryInterface(). + Microsoft::WRL::ComPtr ChildElt; + RET_ON_FAILED(Child->QueryInterface(ChildElt.GetAddressOf())); + RET_ON_FAILED(ChildElt->get_tagName(ChildName.GetAddress())); + } + if (!isMergeableElement(ChildName) || + !(OriginalChildWithName = + getChildWithName(OriginalRoot, ChildName)) || + !hasRecognizedNamespace(Child.Get())) { +#if 0 + 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; +#endif + } else if (auto E = treeMerge(OriginalChildWithName.Get(), Child.Get())) { + return E; + } + } + return Error::success(); +} + +WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { +} + +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; + RET_ON_FAILED(CoCreateInstance( + __uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(ManifestXML.GetAddressOf()))); + 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); + VARIANT_BOOL Status; + RET_ON_FAILED(ManifestXML->loadXML(ManifestUTF16.GetBSTR(), &Status)); + if (Status == VARIANT_FALSE) { + Microsoft::WRL::ComPtr XMLErr; + RET_ON_FAILED(ManifestXML->get_parseError(XMLErr.GetAddressOf())); + bstr_t Reason; + RET_ON_FAILED(XMLErr->get_reason(Reason.GetAddress())); + SmallString<64> UTF8Reason; + UTF16ToUTF8(Reason, &UTF8Reason); + return make_error(UTF8Reason); + } + + Microsoft::WRL::ComPtr AdditionalRoot; + RET_ON_FAILED( + ManifestXML->get_documentElement(AdditionalRoot.GetAddressOf())); + + // 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 { + Microsoft::WRL::ComPtr CombinedRoot; + RET_ON_FAILED( + CombinedDoc->get_documentElement(CombinedRoot.GetAddressOf())); + + bstr_t CombinedRootName, AdditionalRootName; + RET_ON_FAILED(CombinedRoot->get_tagName(CombinedRootName.GetAddress())); + RET_ON_FAILED(AdditionalRoot->get_tagName(AdditionalRootName.GetAddress())); + + if (CombinedRootName != AdditionalRootName || + !isMergeableElement(AdditionalRootName) || + !hasRecognizedNamespace(AdditionalRoot.Get())) { + return make_error("multiple root nodes"); + } + if (auto E = treeMerge(CombinedRoot.Get(), AdditionalRoot.Get())) { + return E; + } + } + MergedDocs.push_back(std::move(ManifestXML)); + return Error::success(); +} + +std::unique_ptr +WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { +fprintf(stderr, "try merge\n"); + 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); +fprintf(stderr, "merged\n"); +#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"}, + {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"}, + {"http://schemas.microsoft.com/SMI/2005/WindowsSettings", + "ms_windowsSettings"}, + {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}}; + static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) { // Handle null pointers. Comparison of 2 null pointers returns true because // this indicates the prefix of a default namespace. @@ -517,7 +796,7 @@ xmlNodePtr AdditionalFirstChild = AdditionalRoot->children; xmlNode StoreNext; for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) { - xmlNodePtr OriginalChildWithName; + xmlNodePtr OriginalChildWithName; // uninit if isMergeableElement false? if (!isMergeableElement(Child->name) || !(OriginalChildWithName = getChildWithName(OriginalRoot, Child->name)) || 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;