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,424 @@ "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 +getAttribute(IXMLDOMNode* Node, const bstr_t& AttributeName) { + // This looks superficially similar to the libxml version, but it handles + // namespaces differently. + Microsoft::WRL::ComPtr attribs; + if (FAILED(Node->get_attributes(attribs.GetAddressOf())) || !attribs) + return nullptr; + Microsoft::WRL::ComPtr Attrib; + if (FAILED(attribs->getNamedItem(AttributeName, Attrib.GetAddressOf()))) + return nullptr; + return Attrib; +} + +static Microsoft::WRL::ComPtr +getChildWithName(IXMLDOMNode *Parent, const bstr_t& ElementName) { + Microsoft::WRL::ComPtr Children; + long Length; + if (FAILED(Parent->get_childNodes(Children.GetAddressOf())) || + FAILED(Children->get_length(&Length))) + return nullptr; + for (long i = 0; i < Length; ++i) { + Microsoft::WRL::ComPtr Child; + bstr_t ChildName; + if (FAILED(Children->get_item(i, Child.GetAddressOf())) || + FAILED(Child->get_nodeName(ChildName.GetAddress()))) + continue; + if (ChildName == ElementName) + return Child; + } + return nullptr; +} + +// Return the corresponding namespace definition for the prefix, defined on the +// given Node. Returns nullptr if there is no such definition. +static bstr_t getNamespaceWithPrefix(const unsigned char *Prefix, + IXMLDOMNode* Node) { + if (Node == nullptr) + return bstr_t(); + + // MSXML models namespace definitions as attributes. + Microsoft::WRL::ComPtr attribs; + if (FAILED(Node->get_attributes(attribs.GetAddressOf()))) + return bstr_t(); + if (attribs) { + long num_attribs; + if (FAILED(attribs->get_length(&num_attribs))) + return bstr_t(); + for (long i = 0; i < num_attribs; ++i) { + Microsoft::WRL::ComPtr attrib; + bstr_t NamespaceURI, AttrName, AttrValue; + if (FAILED((attribs->get_item(i, attrib.GetAddressOf()))) || + FAILED(attrib->get_namespaceURI(NamespaceURI.GetAddress())) || + // Check if this is a namespace attribute or just a regular attribute. + NamespaceURI != bstr_t("http://www.w3.org/2000/xmlns/") || + FAILED(attrib->get_nodeName(AttrName.GetAddress())) || + FAILED(attrib->get_text(AttrValue.GetAddress()))) + continue; + // The bstr_t owns the multibyte-converted string. + const char* Name = (const char*)AttrName; + if (!Prefix) { + if (strcmp(Name, "xmlns") == 0) + return AttrValue; + } else { + if (strncmp(Name, "xmlns:", strlen("xmlns:")) == 0 && + strcmp(Name + strlen("xmlns:"), (const char*)Prefix) == 0) + return AttrValue; + } + } + } + return bstr_t(); +} + +// Search for the closest inheritable default namespace, starting on (and +// including) the Node and traveling upwards through parent nodes. Returns +// nullptr if there are no inheritable default namespaces. +static bstr_t getClosestDefault(IXMLDOMNode* Node) { + bstr_t Ret = getNamespaceWithPrefix(nullptr, Node); + if (Ret.GetBSTR()) + return Ret; + Microsoft::WRL::ComPtr Parent; + if (FAILED(Node->get_parentNode(Parent.GetAddressOf()))) + return bstr_t(); + if (Parent == nullptr) + return bstr_t(); + return getClosestDefault(Parent.Get()); +} + +// Merge the attributes of AdditionalNode into OriginalNode. If attributes +// with identical types are present, they are not duplicated but rather if +// their values are not consistent and error is thrown. In addition, the +// higher priority namespace is used for each attribute, EXCEPT in the case +// of merging two default namespaces and the lower priority namespace +// definition occurs closer than the higher priority one. +static Error mergeAttributes(IXMLDOMNode* OriginalNode, + IXMLDOMNode* AdditionalNode) { + bstr_t ClosestDefault = getClosestDefault(OriginalNode); + Microsoft::WRL::ComPtr attribs; + RET_ON_FAILED(AdditionalNode->get_attributes(attribs.GetAddressOf())); + if (!attribs) + return Error::success(); + long num_attribs; + RET_ON_FAILED(attribs->get_length(&num_attribs)); + for (long i = 0; i < num_attribs; ++i) { + Microsoft::WRL::ComPtr attrib; + RET_ON_FAILED(attribs->get_item(i, attrib.GetAddressOf())); + bstr_t NamespaceURI, AttrName; + RET_ON_FAILED(attrib->get_namespaceURI(NamespaceURI.GetAddress())); + if (NamespaceURI == bstr_t("http://www.w3.org/2000/xmlns/")) + continue; // Skip namespace attributes. (XXX) + RET_ON_FAILED(attrib->get_nodeName(AttrName.GetAddress())); + + if (Microsoft::WRL::ComPtr OriginalAttribute = + getAttribute(OriginalNode, AttrName)) { + bstr_t OriginalAttrContent, AttrContent; + RET_ON_FAILED(attrib->get_text(AttrContent.GetAddress())); + RET_ON_FAILED( + OriginalAttribute->get_text(OriginalAttrContent.GetAddress())); + if (OriginalAttrContent != AttrContent) { + return make_error( + Twine("conflicting attributes for ") + (char*)AttrName); + } + if (!NamespaceURI.GetBSTR()) { + continue; + } + bstr_t OriginalAttrNS; + RET_ON_FAILED( + OriginalAttribute->get_namespaceURI(OriginalAttrNS.GetAddress())); + if (!OriginalAttrNS.GetBSTR()) { +#if 0 + if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, + Attribute)) { + return E; + } +#endif + continue; + } +#if 0 + if (namespaceOverrides(OriginalAttribute->ns->href, + Attribute->ns->href)) { + // In this case, the original attribute has a higher priority namespace + // than the incomiing attribute, however the namespace definition of + // the lower priority namespace occurs first traveling upwards in the + // tree. Therefore the lower priority namespace is applied. + if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix && + ClosestDefault && + xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) { + if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, + Attribute)) { + return E; + } + continue; + } + continue; + // This covers the case where the incoming attribute has the higher + // priority. The higher priority namespace is applied in all cases + // EXCEPT when both of the namespaces are default inherited, and the + // closest inherited default is the lower priority one. + } + if (Attribute->ns->prefix || OriginalAttribute->ns->prefix || + (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href, + ClosestDefault->href))) { + if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, + Attribute)) { + return E; + } + continue; + } +#endif + continue; + } + // If the incoming attribute is not already found on the node, append it + // to the end of the properties list. Also explicitly apply its + // namespace as a prefix because it might be contained in a separate + // namespace that doesn't use the attribute. + Microsoft::WRL::ComPtr NewProp, MovedNewProp; + RET_ON_FAILED( + attrib->cloneNode(/*deep=*/VARIANT_TRUE, NewProp.GetAddressOf())); + Microsoft::WRL::ComPtr attribs; + RET_ON_FAILED(OriginalNode->get_attributes(attribs.GetAddressOf())); + RET_ON_FAILED( + attribs->setNamedItem(NewProp.Get(), MovedNewProp.GetAddressOf())); + // Note that this implicit already sets the right namespace. + // FIXME: check there's a test for that. + } + return Error::success(); +} + +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 (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) + return E; +#if 0 + 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;) { + Microsoft::WRL::ComPtr Child; + RET_ON_FAILED(AdditionalRootChildren->get_item(i, Child.GetAddressOf())); + + Microsoft::WRL::ComPtr OriginalChildWithName; + + bstr_t ChildName; + RET_ON_FAILED(Child->get_nodeName(ChildName.GetAddress())); + if (!isMergeableElement(ChildName) || + !(OriginalChildWithName = + getChildWithName(OriginalRoot, ChildName)) || + !hasRecognizedNamespace(Child.Get())) { + Microsoft::WRL::ComPtr ReparentedChild; + RET_ON_FAILED(OriginalRoot->appendChild(Child.Get(), + ReparentedChild.GetAddressOf())); + // This removes Child from AdditionalRootChildren, so its size + // went down by 1 and i shouldn't increment next time. + Length--; +#if 0 + if (auto E = reconcileNamespaces(Child)) { + return E; + } +#endif + continue; + } + if (auto E = treeMerge(OriginalChildWithName.Get(), Child.Get())) { + return E; + } + i++; + } + return Error::success(); +} + +static void stripComments(IXMLDOMNode* Root) { + Microsoft::WRL::ComPtr Children; + if (FAILED(Root->get_childNodes(Children.GetAddressOf()))) + return; + long Length; + if (FAILED(Children->get_length(&Length))) + return; + for (long i = 0; i < Length;) { + Microsoft::WRL::ComPtr Child, RemovedChild; + if (FAILED(Children->get_item(i, Child.GetAddressOf()))) + return; + DOMNodeType ChildType; + if (FAILED(Child->get_nodeType(&ChildType))) + return; + if (ChildType != NODE_COMMENT) { + stripComments(Child.Get()); + i++; + continue; + } + if (FAILED(Root->removeChild(Child.Get(), RemovedChild.GetAddressOf()))) + return; + Length--; + } +} + +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())); + + stripComments(AdditionalRoot.Get()); + //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. @@ -98,6 +554,7 @@ static xmlAttrPtr getAttribute(xmlNodePtr Node, const unsigned char *AttributeName) { + // FIXME: This ignores namespaces. for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr; Attribute = Attribute->next) { if (xmlStringsEqual(Attribute->name, AttributeName)) { @@ -515,13 +972,13 @@ if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot)) return E; 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)) || !hasRecognizedNamespace(Child)) { + xmlNode StoreNext; StoreNext.next = Child->next; xmlUnlinkNode(Child); if (!xmlAddChild(OriginalRoot, Child)) { 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;