# This python script parses the spec files from MSBuild to create # mappings from compiler options to IDE XML specifications. For # more information see here: # http://blogs.msdn.com/vcblog/archive/2008/12/16/msbuild-task.aspx # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/cl.xml" # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/lib.xml" # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/link.xml" # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/cl.xml" # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/lib.xml" # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/link.xml" # # BoolProperty true|false # simple example: # # # # true # # # argument means it might be this: /MP3 # example with argument: # # # Multi-processor Compilation # # # Multi-processor Compilation # # # # # true # 4 # # IntProperty # not used AFIT # # per config options example # true # # EnumProperty # # # Optimization # # # Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox) # # # # Maximize Speed # # # Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy # # # # # Minimize Size # # # Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy # # # example for O2 would be this: # MaxSpeed # example for O1 would be this: # MinSpace # # StringListProperty # # # Preprocessor Definitions # # # Defines a preprocessing symbols for your source file. # # # # # Additional Include Directories # # # Specifies one or more directories to add to the include path; separate with semi-colons if more than one. (/I[path]) # # # StringProperty # Example add bill include: # ..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories) import sys from xml.dom.minidom import parse, parseString def getText(node): nodelist = node.childNodes rc = "" for child in nodelist: if child.nodeType == child.TEXT_NODE: rc = rc + child.data return rc def print_tree(document, spaces=""): for i in range(len(document.childNodes)): if document.childNodes[i].nodeType == document.childNodes[i].ELEMENT_NODE: print spaces+str(document.childNodes[i].nodeName ) print_tree(document.childNodes[i],spaces+"----") pass ########################################################################################### #Data structure that stores a property of MSBuild class Property: #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum") #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"]) #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like def __init__(self,type,attributeNames,document=None): self.suffix_type = "Property" self.prefix_type = type self.attributeNames = attributeNames self.attributes = {} self.DisplayName = "" self.Description = "" self.argumentProperty = "" self.argumentIsRequired = "" self.values = [] if document is not None: self.populate(document) pass #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like #spaces = do not use def populate(self,document, spaces = ""): if document.nodeName == self.prefix_type+self.suffix_type: for i in self.attributeNames: self.attributes[i] = document.getAttribute(i) for i in range(len(document.childNodes)): child = document.childNodes[i] if child.nodeType == child.ELEMENT_NODE: if child.nodeName == self.prefix_type+self.suffix_type+".DisplayName": self.DisplayName = getText(child.childNodes[1]) if child.nodeName == self.prefix_type+self.suffix_type+".Description": self.Description = getText(child.childNodes[1]) if child.nodeName == "Argument": self.argumentProperty = child.getAttribute("Property") self.argumentIsRequired = child.getAttribute("IsRequired") if child.nodeName == self.prefix_type+"Value": va = Property(self.prefix_type,["Name","DisplayName","Switch"]) va.suffix_type = "Value" va.populate(child) self.values.append(va) self.populate(child,spaces+"----") pass #toString function def __str__(self): toReturn = self.prefix_type+self.suffix_type+":" for i in self.attributeNames: toReturn += "\n "+i+": "+self.attributes[i] if self.argumentProperty != "": toReturn += "\n Argument:\n Property: "+self.argumentProperty+"\n IsRequired: "+self.argumentIsRequired for i in self.values: toReturn+="\n "+str(i).replace("\n","\n ") return toReturn ########################################################################################### ########################################################################################### #Class that populates itself from an MSBuild file and outputs it in CMake #format class MSBuildToCMake: #document = the entire MSBuild xml file def __init__(self,document=None): self.enumProperties = [] self.stringProperties = [] self.stringListProperties = [] self.boolProperties = [] self.intProperties = [] if document!=None : self.populate(document) pass #document = the entire MSBuild xml file #spaces = don't use #To add a new property (if they exist) copy and paste this code and fill in appropriate places # #if child.nodeName == "Property": # self.Properties.append(Property("",[],child)) # #Replace with the name of the new property (ex. if property is StringProperty replace with String) #Replace with a list of attributes in your property's root node #in the __init__ function add the line self.Properties = [] # #That is all that is required to add new properties # def populate(self,document, spaces=""): for i in range(len(document.childNodes)): child = document.childNodes[i] if child.nodeType == child.ELEMENT_NODE: if child.nodeName == "EnumProperty": self.enumProperties.append(Property("Enum",["Name","Category"],child)) if child.nodeName == "StringProperty": self.stringProperties.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","DisplayName","ReadOnly"],child)) if child.nodeName == "StringListProperty": self.stringListProperties.append(Property("StringList",["Name","Category","Switch","DisplayName","Subtype"],child)) if child.nodeName == "BoolProperty": self.boolProperties.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","DisplayName","SwitchPrefix","IncludeInCommandLine"],child)) if child.nodeName == "IntProperty": self.intProperties.append(Property("Int",["Name","Category","Visible"],child)) self.populate(child,spaces+"----") pass #outputs information that CMake needs to know about MSBuild xml files def toCMake(self): toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n" toReturn += "\n //Enum Properties\n" lastProp = {} for i in self.enumProperties: if i.attributes["Name"] == "CompileAsManaged": #write these out after the rest of the enumProperties lastProp = i continue for j in i.values: #hardcore Brad King's manual fixes for cmVS10CLFlagTable.h if i.attributes["Name"] == "PrecompiledHeader" and j.attributes["Switch"] != "": toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n" else: #default (normal, non-hardcoded) case toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n" toReturn += "\n" if lastProp != {}: for j in lastProp.values: toReturn+=" {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n" toReturn += "\n" toReturn += "\n //Bool Properties\n" for i in self.boolProperties: if i.argumentProperty == "": if i.attributes["ReverseSwitch"] != "": toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\", 0},\n" if i.attributes["Switch"] != "": toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\", 0},\n" toReturn += "\n //Bool Properties With Argument\n" for i in self.boolProperties: if i.argumentProperty != "": if i.attributes["ReverseSwitch"] != "": toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n" toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n" if i.attributes["Switch"] != "": toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n" toReturn += " {\""+i.argumentProperty+"\", \""+i.attributes["Switch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n" toReturn += "\n //String List Properties\n" for i in self.stringListProperties: if i.attributes["Switch"] == "": toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n"; else: toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n" toReturn += "\n //String Properties\n" for i in self.stringProperties: if i.attributes["Switch"] == "": if i.attributes["Name"] == "PrecompiledHeaderFile": #more hardcoding toReturn += " {\"PrecompiledHeaderFile\", \"Yc\",\n" toReturn += " \"Precompiled Header Name\",\n" toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n" toReturn += " {\"PrecompiledHeaderFile\", \"Yu\",\n" toReturn += " \"Precompiled Header Name\",\n" toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n" else: toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n"; else: toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue},\n" toReturn += " {0,0,0,0,0}\n};" return toReturn pass #toString function def __str__(self): toReturn = "" allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties] for p in allList: for i in p: toReturn += "==================================================\n"+str(i).replace("\n","\n ")+"\n==================================================\n" return toReturn ########################################################################################### ########################################################################################### # main function def main(argv): xml_file = None help = """ Please specify an input xml file with -x Exiting... Have a nice day :)""" for i in range(0,len(argv)): if argv[i] == "-x": xml_file = argv[i+1] if argv[i] == "-h": print help sys.exit(0) pass if xml_file == None: print help sys.exit(1) f = open(xml_file,"r") xml_str = f.read() xml_dom = parseString(xml_str) convertor = MSBuildToCMake(xml_dom) print convertor.toCMake() xml_dom.unlink() ########################################################################################### # main entry point if __name__ == "__main__": main(sys.argv) sys.exit(0)