[llvm] r311215 - llvm-mt: Merge manifest namespaces.
Eric Beckmann via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 18 17:37:42 PDT 2017
Author: ecbeckmann
Date: Fri Aug 18 17:37:41 2017
New Revision: 311215
URL: http://llvm.org/viewvc/llvm-project?rev=311215&view=rev
Log:
llvm-mt: Merge manifest namespaces.
mt.exe performs a tree merge where certain element nodes are combined
into one. This introduces the possibility of xml namespaces conflicting
with each other. The original mt.exe has a hierarchy whereby certain
namespace names can override others, and nodes that would then end up in
ambigious namespaces have their namespaces explicitly defined. This
namespace handles this merging process.
Added:
llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest
llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest
llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest
llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest
llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest
llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest
llvm/trunk/test/tools/llvm-mt/big_merge.test
Modified:
llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h
llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp
llvm/trunk/test/tools/llvm-mt/help.test
llvm/trunk/test/tools/llvm-mt/simple_merge.test
llvm/trunk/test/tools/llvm-mt/single_file.test
llvm/trunk/test/tools/llvm-mt/xml_error.test
llvm/trunk/tools/llvm-mt/llvm-mt.cpp
Modified: llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h (original)
+++ llvm/trunk/include/llvm/WindowsManifest/WindowsManifestMerger.h Fri Aug 18 17:37:41 2017
@@ -29,21 +29,11 @@
#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
+namespace windows_manifest {
class WindowsManifestError : public ErrorInfo<WindowsManifestError, ECError> {
public:
@@ -57,8 +47,8 @@ private:
class WindowsManifestMerger {
public:
+ WindowsManifestMerger();
~WindowsManifestMerger();
-
Error merge(const MemoryBuffer &Manifest);
// Returns vector containing merged xml manifest, or uninitialized vector for
@@ -66,15 +56,10 @@ public:
std::unique_ptr<MemoryBuffer> getMergedManifest();
private:
- static void errorCallback(void *Ctx, const char *Format, ...);
- Error getParseError();
-
-#if LLVM_LIBXML2_ENABLED
- XMLDocumentImpl CombinedDoc = nullptr;
- std::vector<XMLDocumentImpl> MergedDocs;
-#endif
- bool ParseErrorOccurred = false;
+ class WindowsManifestMergerImpl;
+ std::unique_ptr<WindowsManifestMergerImpl> Impl;
};
+} // namespace windows_manifest
} // namespace llvm
#endif
Modified: llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp (original)
+++ llvm/trunk/lib/WindowsManifest/WindowsManifestMerger.cpp Fri Aug 18 17:37:41 2017
@@ -14,14 +14,17 @@
#include "llvm/WindowsManifest/WindowsManifestMerger.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <stdarg.h>
+#include <map>
+
+#if LLVM_LIBXML2_ENABLED
+#include <libxml/xmlreader.h>
+#endif
#define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
#define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
using namespace llvm;
-
-namespace llvm {
+using namespace windows_manifest;
char WindowsManifestError::ID = 0;
@@ -29,177 +32,676 @@ WindowsManifestError::WindowsManifestErr
void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
+class WindowsManifestMerger::WindowsManifestMergerImpl {
+public:
+ ~WindowsManifestMergerImpl();
+ Error merge(const MemoryBuffer &Manifest);
+ std::unique_ptr<MemoryBuffer> getMergedManifest();
+
+private:
+ static void errorCallback(void *Ctx, const char *Format, ...);
+ Error getParseError();
+#if LLVM_LIBXML2_ENABLED
+ xmlDocPtr CombinedDoc = nullptr;
+ std::vector<xmlDocPtr> MergedDocs;
+#endif
+ bool ParseErrorOccurred = false;
+};
+
#if LLVM_LIBXML2_ENABLED
+
+static const std::pair<StringRef, StringRef> 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.
+ if (!A || !B)
+ return A == B;
return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
}
-#endif
-bool isMergeableElement(const unsigned char *ElementName) {
+static bool isMergeableElement(const unsigned char *ElementName) {
for (StringRef S : {"application", "assembly", "assemblyIdentity",
"compatibility", "noInherit", "requestedExecutionLevel",
"requestedPrivileges", "security", "trustInfo"}) {
- if (S == FROM_XML_CHAR(ElementName))
+ if (S == FROM_XML_CHAR(ElementName)) {
return true;
+ }
}
return false;
}
-XMLNodeImpl getChildWithName(XMLNodeImpl Parent,
- const unsigned char *ElementName) {
-#if LLVM_LIBXML2_ENABLED
- for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next)
+static xmlNodePtr getChildWithName(xmlNodePtr Parent,
+ const unsigned char *ElementName) {
+ for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
if (xmlStringsEqual(Child->name, ElementName)) {
return Child;
}
-#endif
+ }
return nullptr;
}
-const unsigned char *getAttribute(XMLNodeImpl Node,
- const unsigned char *AttributeName) {
-#if LLVM_LIBXML2_ENABLED
+static xmlAttrPtr getAttribute(xmlNodePtr Node,
+ const unsigned char *AttributeName) {
for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
Attribute = Attribute->next) {
- if (xmlStringsEqual(Attribute->name, AttributeName))
- return Attribute->children->content;
+ if (xmlStringsEqual(Attribute->name, AttributeName)) {
+ return Attribute;
+ }
}
-#endif
return nullptr;
}
-Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) {
-#if LLVM_LIBXML2_ENABLED
- for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr;
+// Check if namespace specified by HRef1 overrides that of HRef2.
+static bool namespaceOverrides(const unsigned char *HRef1,
+ const unsigned char *HRef2) {
+ auto HRef1Position = llvm::find_if(
+ MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
+ return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
+ });
+ auto HRef2Position = llvm::find_if(
+ MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
+ return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
+ });
+ return HRef1Position < HRef2Position;
+}
+
+// Search for prefix-defined namespace specified by HRef, starting on Node and
+// continuing recursively upwards. Returns the namespace or nullptr if not
+// found.
+static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
+ for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+ if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
+ return Def;
+ }
+ }
+ if (Node->parent) {
+ return search(HRef, Node->parent);
+ }
+ return nullptr;
+}
+
+// Return the prefix that corresponds to the HRef. If HRef is not a recognized
+// URI, then just return the HRef itself to use as the prefix.
+static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
+ for (auto &Ns : MtNsHrefsPrefixes) {
+ if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
+ return TO_XML_CHAR(Ns.second.data());
+ }
+ }
+ return HRef;
+}
+
+// Search for prefix-defined namespace specified by HRef, starting on Node and
+// continuing recursively upwards. If it is found, then return it. If it is
+// not found, then prefix-define that namespace on the node and return a
+// reference to it.
+static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
+ xmlNodePtr Node) {
+ if (xmlNsPtr Def = search(HRef, Node))
+ return Def;
+ if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
+ return Def;
+ return make_error<WindowsManifestError>("failed to create new namespace");
+}
+
+// Set the namespace of OrigionalAttribute on OriginalNode to be that of
+// AdditionalAttribute's.
+static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
+ xmlNodePtr OriginalNode,
+ xmlAttrPtr AdditionalAttribute) {
+
+ Expected<xmlNsPtr> ExplicitOrError =
+ searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
+ if (!ExplicitOrError)
+ return ExplicitOrError.takeError();
+ OriginalAttribute->ns = std::move(ExplicitOrError.get());
+ return Error::success();
+}
+
+// Return the corresponding namespace definition for the prefix, defined on the
+// given Node. Returns nullptr if there is no such definition.
+static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
+ xmlNodePtr Node) {
+ if (Node == nullptr)
+ return nullptr;
+ for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+ if (xmlStringsEqual(Def->prefix, Prefix)) {
+ return Def;
+ }
+ }
+ return nullptr;
+}
+
+// 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 xmlNsPtr getClosestDefault(xmlNodePtr Node) {
+ if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
+ return Ret;
+ if (Node->parent == nullptr)
+ return nullptr;
+ return getClosestDefault(Node->parent);
+}
+
+// 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(xmlNodePtr OriginalNode,
+ xmlNodePtr AdditionalNode) {
+ xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
+ for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
Attribute = Attribute->next) {
- if (const unsigned char *OriginalValue =
+ if (xmlAttrPtr OriginalAttribute =
getAttribute(OriginalNode, Attribute->name)) {
- // Attributes of the same name must also have the same value. Otherwise
- // an error is thrown.
- if (!xmlStringsEqual(OriginalValue, Attribute->children->content))
+ if (!xmlStringsEqual(OriginalAttribute->children->content,
+ Attribute->children->content)) {
return make_error<WindowsManifestError>(
Twine("conflicting attributes for ") +
FROM_XML_CHAR(OriginalNode->name));
+ }
+ if (!Attribute->ns) {
+ continue;
+ }
+ if (!OriginalAttribute->ns) {
+ if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
+ Attribute)) {
+ return E;
+ }
+ continue;
+ }
+ 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;
+ }
+ 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.
+ xmlAttrPtr NewProp =
+ xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
+ Expected<xmlNsPtr> ExplicitOrError =
+ searchOrDefine(Attribute->ns->href, OriginalNode);
+ if (!ExplicitOrError)
+ return ExplicitOrError.takeError();
+ NewProp->ns = std::move(ExplicitOrError.get());
+ }
+ return Error::success();
+}
+
+// Given two nodes, return the one with the higher priority namespace.
+static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
+
+ if (!Node1 || !Node1->ns)
+ return Node2;
+ if (!Node2 || !Node2->ns)
+ return Node1;
+ if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
+ return Node1;
+ return Node2;
+}
+
+// Checks if this Node's namespace is inherited or one it defined itself.
+static bool hasInheritedNs(xmlNodePtr Node) {
+ return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
+}
+
+// Check if this Node's namespace is a default namespace that it inherited, as
+// opposed to defining itself.
+static bool hasInheritedDefaultNs(xmlNodePtr Node) {
+ return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
+}
+
+// Check if this Node's namespace is a default namespace it defined itself.
+static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
+ return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
+}
+
+// For the given explicit prefix-definition of a namespace, travel downwards
+// from a node recursively, and for every implicit, inherited default usage of
+// that namespace replace it with that explicit prefix use. This is important
+// when namespace overriding occurs when merging, so that elements unique to a
+// namespace will still stay in that namespace.
+static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
+ // If a node as its own default namespace definition it clearly cannot have
+ // inherited the given default namespace, and neither will any of its
+ // children.
+ if (hasDefinedDefaultNamespace(Node))
+ return;
+ if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
+ hasInheritedDefaultNs(Node))
+ Node->ns = PrefixDef;
+ for (xmlAttrPtr Attribute = Node->properties; Attribute;
+ Attribute = Attribute->next) {
+ if (Attribute->ns &&
+ xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
+ Attribute->ns = PrefixDef;
+ }
+ }
+ for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+ explicateNamespace(PrefixDef, Child);
+ }
+}
+
+// Perform the namespace merge between two nodes.
+static Error mergeNamespaces(xmlNodePtr OriginalNode,
+ xmlNodePtr AdditionalNode) {
+ // Save the original default namespace definition in case the incoming node
+ // overrides it.
+ const unsigned char *OriginalDefinedDefaultHref = nullptr;
+ if (xmlNsPtr OriginalDefinedDefaultNs =
+ getNamespaceWithPrefix(nullptr, OriginalNode)) {
+ OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
+ }
+ const unsigned char *NewDefinedDefaultHref = nullptr;
+ // Copy all namespace definitions. There can only be one default namespace
+ // definition per node, so the higher priority one takes precedence in the
+ // case of collision.
+ for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
+ if (xmlNsPtr OriginalNsDef =
+ getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
+ if (!Def->prefix) {
+ if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
+ NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
+ }
+ } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
+ return make_error<WindowsManifestError>(
+ Twine("conflicting namespace definitions for ") +
+ FROM_XML_CHAR(Def->prefix));
+ }
} else {
- char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name));
- char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content));
- xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy));
+ xmlNsPtr NewDef = xmlCopyNamespace(Def);
+ NewDef->next = OriginalNode->nsDef;
+ OriginalNode->nsDef = NewDef;
}
}
-#endif
+
+ // Check whether the original node or the incoming node has the higher
+ // priority namespace. Depending on which one is dominant, we will have
+ // to recursively apply namespace changes down to children of the original
+ // node.
+ xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
+ xmlNodePtr NonDominantNode =
+ DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
+ if (DominantNode == OriginalNode) {
+ if (OriginalDefinedDefaultHref) {
+ xmlNsPtr NonDominantDefinedDefault =
+ getNamespaceWithPrefix(nullptr, NonDominantNode);
+ // In this case, both the nodes defined a default namespace. However
+ // the lower priority node ended up having a higher priority default
+ // definition. This can occur if the higher priority node is prefix
+ // namespace defined. In this case we have to define an explicit
+ // prefix for the overridden definition and apply it to all children
+ // who relied on that definition.
+ if (NonDominantDefinedDefault &&
+ namespaceOverrides(NonDominantDefinedDefault->href,
+ OriginalDefinedDefaultHref)) {
+ Expected<xmlNsPtr> EC =
+ searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
+ if (!EC) {
+ return EC.takeError();
+ }
+ xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
+ explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
+ }
+ // In this case the node with a higher priority namespace did not have a
+ // default namespace definition, but the lower priority node did. In this
+ // case the new default namespace definition is copied. A side effect of
+ // this is that all children will suddenly find themselves in a different
+ // default namespace. To maintain correctness we need to ensure that all
+ // children now explicitly refer to the namespace that they had previously
+ // implicitly inherited.
+ } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
+ if (DominantNode->parent) {
+ xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
+ Expected<xmlNsPtr> EC =
+ searchOrDefine(ClosestDefault->href, DominantNode);
+ if (!EC) {
+ return EC.takeError();
+ }
+ xmlNsPtr ExplicitDefault = std::move(EC.get());
+ explicateNamespace(ExplicitDefault, DominantNode);
+ }
+ }
+ } else {
+ // Covers case where the incoming node has a default namespace definition
+ // that overrides the original node's namespace. This always leads to
+ // the original node receiving that new default namespace.
+ if (hasDefinedDefaultNamespace(DominantNode)) {
+ NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
+ } else {
+ // This covers the case where the incoming node either has a prefix
+ // namespace, or an inherited default namespace. Since the namespace
+ // may not yet be defined in the original tree we do a searchOrDefine
+ // for it, and then set the namespace equal to it.
+ Expected<xmlNsPtr> EC =
+ searchOrDefine(DominantNode->ns->href, NonDominantNode);
+ if (!EC) {
+ return EC.takeError();
+ }
+ xmlNsPtr Explicit = std::move(EC.get());
+ NonDominantNode->ns = Explicit;
+ }
+ // This covers cases where the incoming dominant node HAS a default
+ // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
+ if (xmlNsPtr DominantDefaultDefined =
+ getNamespaceWithPrefix(nullptr, DominantNode)) {
+ if (OriginalDefinedDefaultHref) {
+ if (namespaceOverrides(DominantDefaultDefined->href,
+ OriginalDefinedDefaultHref)) {
+ // In this case, the incoming node's default definition overrides
+ // the original default definition, all children who relied on that
+ // definition must be updated accordingly.
+ Expected<xmlNsPtr> EC =
+ searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
+ if (!EC) {
+ return EC.takeError();
+ }
+ xmlNsPtr ExplicitDefault = std::move(EC.get());
+ explicateNamespace(ExplicitDefault, NonDominantNode);
+ }
+ } else {
+ // The original did not define a default definition, however the new
+ // default definition still applies to all children, so they must be
+ // updated to explicitly refer to the namespace they had previously
+ // been inheriting implicitly.
+ xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
+ Expected<xmlNsPtr> EC =
+ searchOrDefine(ClosestDefault->href, NonDominantNode);
+ if (!EC) {
+ return EC.takeError();
+ }
+ xmlNsPtr ExplicitDefault = std::move(EC.get());
+ explicateNamespace(ExplicitDefault, NonDominantNode);
+ }
+ }
+ }
+ if (NewDefinedDefaultHref) {
+ xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
+ xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
+ OriginalNsDef->href = NewDefinedDefaultHref;
+ }
+ xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
return Error::success();
}
-Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) {
-#if LLVM_LIBXML2_ENABLED
- XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children;
+static bool isRecognizedNamespace(const unsigned char *NsHref) {
+ for (auto &Ns : MtNsHrefsPrefixes) {
+ if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool hasRecognizedNamespace(xmlNodePtr Node) {
+ return isRecognizedNamespace(Node->ns->href);
+}
+
+// Ensure a node's inherited namespace is actually defined in the tree it
+// resides in.
+static Error reconcileNamespaces(xmlNodePtr Node) {
+ if (!Node) {
+ return Error::success();
+ }
+ if (hasInheritedNs(Node)) {
+ Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
+ if (!ExplicitOrError) {
+ return ExplicitOrError.takeError();
+ }
+ xmlNsPtr Explicit = std::move(ExplicitOrError.get());
+ Node->ns = Explicit;
+ }
+ for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+ if (auto E = reconcileNamespaces(Child)) {
+ return E;
+ }
+ }
+ return Error::success();
+}
+
+// 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(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
+ if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
+ return E;
+ if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
+ return E;
+ xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
xmlNode StoreNext;
- for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) {
- XMLNodeImpl OriginalChildWithName;
+ for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
+ xmlNodePtr OriginalChildWithName;
if (!isMergeableElement(Child->name) ||
!(OriginalChildWithName =
- getChildWithName(OriginalRoot, Child->name))) {
+ getChildWithName(OriginalRoot, Child->name)) ||
+ !hasRecognizedNamespace(Child)) {
StoreNext.next = Child->next;
xmlUnlinkNode(Child);
- if (!xmlAddChild(OriginalRoot, Child))
+ if (!xmlAddChild(OriginalRoot, Child)) {
return make_error<WindowsManifestError>(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;
}
}
- if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
- return E;
-#endif
return Error::success();
}
-void stripCommentsAndText(XMLNodeImpl Root) {
-#if LLVM_LIBXML2_ENABLED
+static void stripComments(xmlNodePtr Root) {
xmlNode StoreNext;
- for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) {
- if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) &&
- !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
- stripCommentsAndText(Child);
+ for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
+ if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
+ stripComments(Child);
+ continue;
+ }
+ StoreNext.next = Child->next;
+ xmlNodePtr Remove = Child;
+ Child = &StoreNext;
+ xmlUnlinkNode(Remove);
+ xmlFreeNode(Remove);
+ }
+}
+
+// libxml2 assumes that attributes do not inherit default namespaces, whereas
+// the original mt.exe does make this assumption. This function reconciles
+// this by setting all attributes to have the inherited default namespace.
+static void setAttributeNamespaces(xmlNodePtr Node) {
+ for (xmlAttrPtr Attribute = Node->properties; Attribute;
+ Attribute = Attribute->next) {
+ if (!Attribute->ns) {
+ Attribute->ns = getClosestDefault(Node);
+ }
+ }
+ for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+ setAttributeNamespaces(Child);
+ }
+}
+
+// The merging process may create too many prefix defined namespaces. This
+// function removes all unnecessary ones from the tree.
+static void checkAndStripPrefixes(xmlNodePtr Node,
+ std::vector<xmlNsPtr> &RequiredPrefixes) {
+ for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
+ checkAndStripPrefixes(Child, RequiredPrefixes);
+ }
+ if (Node->ns && Node->ns->prefix != nullptr) {
+ xmlNsPtr ClosestDefault = getClosestDefault(Node);
+ if (ClosestDefault &&
+ xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
+ Node->ns = ClosestDefault;
+ } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
+ RequiredPrefixes.push_back(Node->ns);
+ }
+ }
+ for (xmlAttrPtr Attribute = Node->properties; Attribute;
+ Attribute = Attribute->next) {
+ if (Attribute->ns && Attribute->ns->prefix != nullptr) {
+ xmlNsPtr ClosestDefault = getClosestDefault(Node);
+ if (ClosestDefault &&
+ xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
+ Attribute->ns = ClosestDefault;
+ } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
+ RequiredPrefixes.push_back(Attribute->ns);
+ }
+ }
+ }
+ xmlNsPtr Prev;
+ xmlNs Temp;
+ for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
+ if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
+ Prev = Def;
+ continue;
+ }
+ if (Def == Node->nsDef) {
+ Node->nsDef = Def->next;
} else {
- StoreNext.next = Child->next;
- XMLNodeImpl Remove = Child;
- Child = &StoreNext;
- xmlUnlinkNode(Remove);
- xmlFreeNode(Remove);
+ Prev->next = Def->next;
}
+ Temp.next = Def->next;
+ xmlFreeNs(Def);
+ Def = &Temp;
}
-#endif
}
-WindowsManifestMerger::~WindowsManifestMerger() {
-#if LLVM_LIBXML2_ENABLED
+WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
for (auto &Doc : MergedDocs)
xmlFreeDoc(Doc);
-#endif
}
-Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
-#if LLVM_LIBXML2_ENABLED
+Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
+ const MemoryBuffer &Manifest) {
if (Manifest.getBufferSize() == 0)
return make_error<WindowsManifestError>(
"attempted to merge empty manifest");
- xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
- XMLDocumentImpl ManifestXML =
+ xmlSetGenericErrorFunc((void *)this,
+ WindowsManifestMergerImpl::errorCallback);
+ xmlDocPtr ManifestXML =
xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
"manifest.xml", nullptr, XML_PARSE_NOBLANKS);
xmlSetGenericErrorFunc(nullptr, nullptr);
if (auto E = getParseError())
return E;
- XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML);
- stripCommentsAndText(AdditionalRoot);
+ xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
+ stripComments(AdditionalRoot);
+ setAttributeNamespaces(AdditionalRoot);
if (CombinedDoc == nullptr) {
CombinedDoc = ManifestXML;
} else {
- XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc);
- if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) &&
- isMergeableElement(AdditionalRoot->name)) {
- if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
- return E;
- }
- } else {
+ xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
+ if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
+ !isMergeableElement(AdditionalRoot->name) ||
+ !hasRecognizedNamespace(AdditionalRoot)) {
return make_error<WindowsManifestError>("multiple root nodes");
}
+ if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
+ return E;
+ }
}
MergedDocs.push_back(ManifestXML);
-#endif
return Error::success();
}
-std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
-#if LLVM_LIBXML2_ENABLED
+std::unique_ptr<MemoryBuffer>
+WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
unsigned char *XmlBuff;
int BufferSize = 0;
if (CombinedDoc) {
+ xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
+ std::vector<xmlNsPtr> RequiredPrefixes;
+ checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
std::unique_ptr<xmlDoc> OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
- xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc));
+ xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
xmlKeepBlanksDefault(0);
- xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1);
+ xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &XmlBuff, &BufferSize, "UTF-8",
+ 1);
}
if (BufferSize == 0)
return nullptr;
return MemoryBuffer::getMemBuffer(
StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize));
+}
+
#else
+
+WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
+}
+
+Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
+ const MemoryBuffer &Manifest) {
+ return Error::success();
+}
+
+std::unique_ptr<MemoryBuffer>
+WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
return nullptr;
+}
+
#endif
+
+WindowsManifestMerger::WindowsManifestMerger()
+ : Impl(make_unique<WindowsManifestMergerImpl>()) {}
+
+WindowsManifestMerger::~WindowsManifestMerger() {}
+
+Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
+ return Impl->merge(Manifest);
}
-void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) {
- auto *Merger = (WindowsManifestMerger *)Ctx;
+std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
+ return Impl->getMergedManifest();
+}
+
+void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
+ void *Ctx, const char *Format, ...) {
+ auto *Merger = (WindowsManifestMergerImpl *)Ctx;
Merger->ParseErrorOccurred = true;
}
-Error WindowsManifestMerger::getParseError() {
+Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
if (!ParseErrorOccurred)
return Error::success();
return make_error<WindowsManifestError>("invalid xml document");
}
-
-} // namespace llvm
Added: llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/assembly_identity.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v2" manifestVersion="1.0">
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+</assembly>
Added: llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/compatibility.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+ <application>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <supportedOS Id="FooOS"/>
+ <supportedOS Id="BarOS"/>
+ </compatibility>
+ </application>
+</assembly>
Added: llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/expected_big.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<ms_asmv1:trustInfo xmlns="urn:schemas-microsoft-com:asm.v3" xmlns:ms_asmv1="urn:schemas-microsoft-com:asm.v1">
+ <ms_asmv1:security>
+ <ms_asmv1:requestedPrivileges>
+ <ms_asmv1:requestedExecutionLevel level="trust1" ms_asmv1:access="false"></ms_asmv1:requestedExecutionLevel>
+ </ms_asmv1:requestedPrivileges>
+ </ms_asmv1:security>
+</ms_asmv1:trustInfo>
+<ms_asmv2:dependency xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+ <ms_asmv2:dependentAssembly>
+ <ms_asmv2:assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"></assemblyIdentity>
+ </ms_asmv2:dependentAssembly>
+</ms_asmv2:dependency>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity bar="foo" name="my assembly" version="5"></assemblyIdentity>
+ </dependentAssembly>
+</dependency>
+<application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <supportedOS Id="FooOS"/>
+ <supportedOS Id="BarOS"/>
+ </compatibility>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true/pm</dpiAware>
+ </asmv3:windowsSettings>
+</application>
+</assembly>
Added: llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/trust_and_identity.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+ <!--random comment -->
+
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity bar="foo" name="my assembly" version="5"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+
+ <trustInfo>
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="trust1" access="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+</assembly>
Added: llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/trust_info.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="trust1"></requestedExecutionLevel>
+ </requestedPrivileges>
+ </security>
+</trustInfo></assembly>
Added: llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest (added)
+++ llvm/trunk/test/tools/llvm-mt/Inputs/windows_settings.manifest Fri Aug 18 17:37:41 2017
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings" manifestVersion="1.0">
+ <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true/pm</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly>
Added: llvm/trunk/test/tools/llvm-mt/big_merge.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/big_merge.test?rev=311215&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/big_merge.test (added)
+++ llvm/trunk/test/tools/llvm-mt/big_merge.test Fri Aug 18 17:37:41 2017
@@ -0,0 +1,39 @@
+REQUIRES: libxml2
+UNSUPPORTED: windows
+
+RUN: llvm-mt /manifest %p/Inputs/trust_info.manifest \
+RUN: /manifest %p/Inputs/assembly_identity.manifest \
+RUN: /manifest %p/Inputs/trust_and_identity.manifest \
+RUN: /manifest %p/Inputs/compatibility.manifest \
+RUN: /manifest %p/Inputs/windows_settings.manifest /out:%t
+RUN: FileCheck %s -input-file=%t
+
+CHECK: <?xml version="1.0" encoding="UTF-8"?>
+CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+CHECK-NEXT: <ms_asmv1:trustInfo xmlns="urn:schemas-microsoft-com:asm.v3" xmlns:ms_asmv1="urn:schemas-microsoft-com:asm.v1">
+CHECK-NEXT: <ms_asmv1:security>
+CHECK-NEXT: <ms_asmv1:requestedPrivileges>
+CHECK-NEXT: <ms_asmv1:requestedExecutionLevel level="trust1" ms_asmv1:access="false"/>
+CHECK-NEXT: </ms_asmv1:requestedPrivileges>
+CHECK-NEXT: </ms_asmv1:security>
+CHECK-NEXT: </ms_asmv1:trustInfo>
+CHECK-NEXT: <ms_asmv2:dependency xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+CHECK-NEXT: <ms_asmv2:dependentAssembly>
+CHECK-NEXT: <ms_asmv2:assemblyIdentity foo="bar" name="identity1" version="1.2.3.4"/>
+CHECK-NEXT: </ms_asmv2:dependentAssembly>
+CHECK-NEXT: </ms_asmv2:dependency>
+CHECK-NEXT: <dependency>
+CHECK-NEXT: <dependentAssembly>
+CHECK-NEXT: <assemblyIdentity bar="foo" name="my assembly" version="5"/>
+CHECK-NEXT: </dependentAssembly>
+CHECK-NEXT: </dependency>
+CHECK-NEXT: <application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+CHECK-NEXT: <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+CHECK-NEXT: <supportedOS Id="FooOS"/>
+CHECK-NEXT: <supportedOS Id="BarOS"/>
+CHECK-NEXT: </compatibility>
+CHECK-NEXT: <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+CHECK-NEXT: <dpiAware>true/pm</dpiAware>
+CHECK-NEXT: </asmv3:windowsSettings>
+CHECK-NEXT: </application>
+CHECK-NEXT: </assembly>
Modified: llvm/trunk/test/tools/llvm-mt/help.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/help.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/help.test (original)
+++ llvm/trunk/test/tools/llvm-mt/help.test Fri Aug 18 17:37:41 2017
@@ -1,3 +1,7 @@
RUN: llvm-mt /h | FileCheck %s -check-prefix=HELP
HELP: OVERVIEW: Manifest Tool
+
+RUN: not llvm-mt /foo 2>&1 >/dev/null | FileCheck %s -check-prefix=INVALID
+
+INVALID: llvm-mt error: invalid option /foo
Modified: llvm/trunk/test/tools/llvm-mt/simple_merge.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/simple_merge.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/simple_merge.test (original)
+++ llvm/trunk/test/tools/llvm-mt/simple_merge.test Fri Aug 18 17:37:41 2017
@@ -5,7 +5,7 @@ RUN: llvm-mt /manifest %p/Inputs/test_ma
RUN: %p/Inputs/additional.manifest /out:%t
RUN: FileCheck %s -input-file=%t
-CHECK: <?xml version="1.0"?>
+CHECK: <?xml version="1.0" encoding="UTF-8"?>
CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
CHECK-NEXT: <trustInfo>
CHECK-NEXT: <security>
Modified: llvm/trunk/test/tools/llvm-mt/single_file.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/single_file.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/single_file.test (original)
+++ llvm/trunk/test/tools/llvm-mt/single_file.test Fri Aug 18 17:37:41 2017
@@ -4,7 +4,7 @@ UNSUPPORTED: windows
RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t
RUN: FileCheck %s --input-file=%t
-CHECK: <?xml version="1.0"?>
+CHECK: <?xml version="1.0" encoding="UTF-8"?>
CHECK-NEXT: <assembly xmlns="urn:schemas-microsoft-com:asm.v1">
CHECK-NEXT: <trustInfo>
CHECK-NEXT: <security>
Modified: llvm/trunk/test/tools/llvm-mt/xml_error.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mt/xml_error.test?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-mt/xml_error.test (original)
+++ llvm/trunk/test/tools/llvm-mt/xml_error.test Fri Aug 18 17:37:41 2017
@@ -11,8 +11,8 @@ RUN: FileCheck %s -check-prefix=EMPTY
EMPTY: llvm-mt error: attempted to merge empty manifest
-RUN: llvm-mt /inputresource:foo.res /manifest \
-RUN: %p/Inputs/test_manifest.manifest | FileCheck %s \
-RUN: -check-prefix=NOT_SUPPORTED
+RUN: llvm-mt /inputresource:foo.res \
+RUN: /manifest %p/Inputs/test_manifest.manifest \
+RUN: /out:%t | FileCheck %s -check-prefix=NOT_SUPPORTED
NOT_SUPPORTED: llvm-mt: ignoring unsupported 'inputresource:' option
Modified: llvm/trunk/tools/llvm-mt/llvm-mt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mt/llvm-mt.cpp?rev=311215&r1=311214&r2=311215&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mt/llvm-mt.cpp (original)
+++ llvm/trunk/tools/llvm-mt/llvm-mt.cpp Fri Aug 18 17:37:41 2017
@@ -102,6 +102,9 @@ int main(int argc, const char **argv) {
ArrayRef<const char *> ArgsArr = makeArrayRef(argv + 1, argc);
opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
+ for (auto *Arg : InputArgs.filtered(OPT_INPUT))
+ reportError(Twine("invalid option ") + Arg->getSpelling());
+
for (auto &Arg : InputArgs) {
if (Arg->getOption().matches(OPT_unsupported)) {
outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
@@ -129,7 +132,7 @@ int main(int argc, const char **argv) {
reportError("no output file specified");
}
- WindowsManifestMerger Merger;
+ windows_manifest::WindowsManifestMerger Merger;
for (const auto &File : InputFiles) {
ErrorOr<std::unique_ptr<MemoryBuffer>> ManifestOrErr =
More information about the llvm-commits
mailing list