Index: llvm/include/llvm/Support/WindowsManifestMerger.h =================================================================== --- llvm/include/llvm/Support/WindowsManifestMerger.h +++ llvm/include/llvm/Support/WindowsManifestMerger.h @@ -35,6 +35,19 @@ namespace llvm { +static const char * const MT_Strings[] { + "application", + "assemblyIdentity", + "compatibility", + "noInherit", + "requestedExecutionLevel", + "requestedPrivileges", + "security", + "trustInfo", +}; + +static const std::vector MTMergeableElements(MT_Strings, std::end(MT_Strings)); + class MemoryBuffer; #if LLVM_LIBXML2_ENABLED @@ -49,6 +62,7 @@ public: static char ID; WindowsManifestError(const Twine &Msg); + WindowsManifestError(const Twine &Prefix, const Twine &Message); void log(raw_ostream &OS) const override; private: Index: llvm/lib/Support/WindowsManifestMerger.cpp =================================================================== --- llvm/lib/Support/WindowsManifestMerger.cpp +++ llvm/lib/Support/WindowsManifestMerger.cpp @@ -16,27 +16,107 @@ #include +using namespace llvm; + namespace llvm { -char WindowsManifestError::ID = 0; + char WindowsManifestError::ID = 0; + + WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} + + WindowsManifestError::WindowsManifestError(const Twine &Prefix, const Twine &Message) : Msg((Prefix.concat(Message)).str()) {} -WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} + void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } + + bool isMergeableElement(const unsigned char* ElementName) { + //outs() << "Check if " << std::string(reinterpret_cast(ElementName)) << " is mergeable\n"; + bool result = std::find(MTMergeableElements.begin(), MTMergeableElements.end(), std::string(reinterpret_cast(ElementName))) != MTMergeableElements.end(); + //outs() << "result = " << result << "\n"; + return result; + } + + XMLNodeImpl hasChildWithName(XMLNodeImpl Parent, const unsigned char* ElementName) { + #if defined(LIBXML2_ENABLED) + for (XMLNodeImpl Child = Parent->children ; Child; Child = Child->next) + if (strcmp(reinterpret_cast(Child->name), reinterpret_cast(ElementName)) == 0) { + outs() << "found child with name " << std::string(reinterpret_cast(ElementName)) << "\n"; + return Child; + } + #endif + return nullptr; + } + + const unsigned char* hasAttribute(XMLNodeImpl Node, const unsigned char* AttributeName) { + #if defined(LIBXML2_ENABLED) + for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr; Attribute = Attribute->next) { + if (strcmp(reinterpret_cast(Attribute->name), reinterpret_cast(AttributeName)) == 0) return Attribute->children->content; + } + #endif + return nullptr; + } + + Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) { + #if defined(LIBXML2_ENABLED) + for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr; Attribute = Attribute->next) { + if (const unsigned char* OriginalValue = hasAttribute(OriginalNode, Attribute->name)) { + if (strcmp(reinterpret_cast(OriginalValue), reinterpret_cast(Attribute->children->content)) != 0) + return make_error("conflicting attributes for ", reinterpret_cast(OriginalNode->name)); + } else + xmlSetProp(OriginalNode, Attribute->name, Attribute->children->content); + } + #endif + return Error::success(); + } -void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } + Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) { + #if defined(LIBXML2_ENABLED) + outs() << "treeMerging " << std::string(reinterpret_cast(OriginalRoot->name)) << "\n"; + XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children; + if (AdditionalFirstChild != nullptr) { + xmlNode Temp; + for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) { + XMLNodeImpl OriginalChildWithName; + if((strcmp(reinterpret_cast(Child->name), "text") != 0) && (strcmp(reinterpret_cast(Child->name), "comment") != 0)) { + outs() << "analyzing " << std::string(reinterpret_cast(Child->name)) << "\n"; + if (!(OriginalChildWithName = hasChildWithName(OriginalRoot, Child->name)) || !isMergeableElement(Child->name)) { + outs() << "about to add " << std::string(reinterpret_cast(Child->name)) << "\n"; + xmlAddChild(OriginalRoot, Child); + Temp.next = Child->next; + Child->next = nullptr; + Child = &Temp; + //xmlNewTextChild(OriginalRoot, nullptr, reinterpret_cast("text"), reinterpret_cast("\n")); + } else { + if(auto E = treeMerge(OriginalChildWithName, Child)) + return E; + } + } + } + } + if(auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) + return E; + xmlTextMerge(OriginalRoot, AdditionalRoot); + #endif + outs() << "pop " << std::string(reinterpret_cast(OriginalRoot->name)) << "\n"; + return Error::success(); + } 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); + "manifest.xml", nullptr, XML_PARSE_NOBLANKS); xmlSetGenericErrorFunc(nullptr, nullptr); if (auto E = getParseError()) return E; + if (CombinedRoot == nullptr) CombinedRoot = xmlDocGetRootElement(ManifestXML); + else { + return (treeMerge(CombinedRoot, xmlDocGetRootElement(ManifestXML))); + } #endif - return Error::success(); -} + return Error::success(); + } std::unique_ptr WindowsManifestMerger::getMergedManifest() { #if LLVM_LIBXML2_ENABLED @@ -45,7 +125,8 @@ if (CombinedRoot) { std::unique_ptr OutputDoc(xmlNewDoc((const unsigned char *)"1.0")); xmlDocSetRootElement(OutputDoc.get(), CombinedRoot); - xmlDocDumpMemory(OutputDoc.get(), &XmlBuff, &BufferSize); + xmlKeepBlanksDefault(0); + xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1); } if (BufferSize == 0) return nullptr; @@ -56,10 +137,10 @@ #endif } -void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) { - auto *Merger = (WindowsManifestMerger *)Ctx; - Merger->ParseErrorOccurred = true; -} + void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) { + auto *Merger = (WindowsManifestMerger *)Ctx; + Merger->ParseErrorOccurred = true; + } Error WindowsManifestMerger::getParseError() { if (!ParseErrorOccurred) Index: llvm/test/tools/llvm-mt/Inputs/additional.manifest =================================================================== --- llvm/test/tools/llvm-mt/Inputs/additional.manifest +++ llvm/test/tools/llvm-mt/Inputs/additional.manifest @@ -3,13 +3,13 @@ - + - + Index: llvm/test/tools/llvm-mt/Inputs/conflicting.manifest =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mt/Inputs/conflicting.manifest @@ -0,0 +1,10 @@ + + + + + + + + + + Index: llvm/test/tools/llvm-mt/Inputs/test_manifest.manifest =================================================================== --- llvm/test/tools/llvm-mt/Inputs/test_manifest.manifest +++ llvm/test/tools/llvm-mt/Inputs/test_manifest.manifest @@ -1,9 +1,9 @@ - + - + Index: llvm/test/tools/llvm-mt/conflicting.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mt/conflicting.test @@ -0,0 +1,7 @@ +REQUIRES: libxml2 +UNSUPPORTED: windows + +RUN: not llvm-mt /manifest %p/Inputs/test_manifest.manifest /manifest \ +RUN: %p/Inputs/conflicting.manifest /out:%t 2>&1 >/dev/null | FileCheck %s + +CHECK: llvm-mt error: conflicting attributes for requestedExecutionLevel Index: llvm/test/tools/llvm-mt/simple_merge.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-mt/simple_merge.test @@ -0,0 +1,27 @@ +REQUIRES: libxml2 +UNSUPPORTED: windows + +RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /manifest \ +RUN: %p/Inputs/additional.manifest /out:%t +RUN: FileCheck %s -input-file=%t + +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: +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 @@ -95,7 +95,6 @@ SpecificBumpPtrAllocator ArgAllocator; ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( argv_buf, makeArrayRef(argv, argc), ArgAllocator))); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. CvtResOptTable T; @@ -133,6 +132,7 @@ WindowsManifestMerger Merger; for (const auto &File : InputFiles) { + outs() << "FOUND NEW INPUT\n"; ErrorOr> ManifestOrErr = MemoryBuffer::getFile(File); if (!ManifestOrErr)