1 # This python script parses the spec files from MSBuild to create
2 # mappings from compiler options to IDE XML specifications. For
3 # more information see here:
5 # http://blogs.msdn.com/vcblog/archive/2008/12/16/msbuild-task.aspx
6 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/cl.xml"
7 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/lib.xml"
8 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/link.xml"
10 # BoolProperty <Name>true|false</Name>
12 # <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
13 # Category="Optimization" Switch="Oy">
14 # <BoolProperty.DisplayName> <BoolProperty.Description>
16 # <OmitFramePointers>true</OmitFramePointers>
19 # argument means it might be this: /MP3
20 # example with argument:
21 # <BoolProperty Name="MultiProcessorCompilation" Category="General" Switch="MP">
22 # <BoolProperty.DisplayName>
23 # <sys:String>Multi-processor Compilation</sys:String>
24 # </BoolProperty.DisplayName>
25 # <BoolProperty.Description>
26 # <sys:String>Multi-processor Compilation</sys:String>
27 # </BoolProperty.Description>
28 # <Argument Property="ProcessorNumber" IsRequired="false" />
31 # <MultiProcessorCompilation>true</MultiProcessorCompilation>
32 # <ProcessorNumber>4</ProcessorNumber>
36 # <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
39 # per config options example
40 # <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
43 # <EnumProperty Name="Optimization" Category="Optimization">
44 # <EnumProperty.DisplayName>
45 # <sys:String>Optimization</sys:String>
46 # </EnumProperty.DisplayName>
47 # <EnumProperty.Description>
48 # <sys:String>Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)</sys:String>
49 # </EnumProperty.Description>
50 # <EnumValue Name="MaxSpeed" Switch="O2">
51 # <EnumValue.DisplayName>
52 # <sys:String>Maximize Speed</sys:String>
53 # </EnumValue.DisplayName>
54 # <EnumValue.Description>
55 # <sys:String>Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy</sys:String>
56 # </EnumValue.Description>
58 # <EnumValue Name="MinSpace" Switch="O1">
59 # <EnumValue.DisplayName>
60 # <sys:String>Minimize Size</sys:String>
61 # </EnumValue.DisplayName>
62 # <EnumValue.Description>
63 # <sys:String>Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy</sys:String>
64 # </EnumValue.Description>
66 # example for O2 would be this:
67 # <Optimization>MaxSpeed</Optimization>
68 # example for O1 would be this:
69 # <Optimization>MinSpace</Optimization>
72 # <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" Switch="D ">
73 # <StringListProperty.DisplayName>
74 # <sys:String>Preprocessor Definitions</sys:String>
75 # </StringListProperty.DisplayName>
76 # <StringListProperty.Description>
77 # <sys:String>Defines a preprocessing symbols for your source file.</sys:String>
78 # </StringListProperty.Description>
79 # </StringListProperty>
81 # <StringListProperty Subtype="folder" Name="AdditionalIncludeDirectories" Category="General" Switch="I">
82 # <StringListProperty.DisplayName>
83 # <sys:String>Additional Include Directories</sys:String>
84 # </StringListProperty.DisplayName>
85 # <StringListProperty.Description>
86 # <sys:String>Specifies one or more directories to add to the include path; separate with semi-colons if more than one. (/I[path])</sys:String>
87 # </StringListProperty.Description>
88 # </StringListProperty>
91 # Example add bill include:
93 # <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
97 from xml.dom.minidom import parse, parseString
100 nodelist = node.childNodes
102 for child in nodelist:
103 if child.nodeType == child.TEXT_NODE:
107 def print_tree(document, spaces=""):
108 for i in range(len(document.childNodes)):
109 if document.childNodes[i].nodeType == document.childNodes[i].ELEMENT_NODE:
110 print spaces+str(document.childNodes[i].nodeName )
111 print_tree(document.childNodes[i],spaces+"----")
114 ###########################################################################################
115 #Data structure that stores a property of MSBuild
117 #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum")
118 #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"])
119 #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 <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
120 def __init__(self,type,attributeNames,document=None):
121 self.suffix_type = "Property"
122 self.prefix_type = type
123 self.attributeNames = attributeNames
125 self.DisplayName = ""
126 self.Description = ""
127 self.argumentProperty = ""
128 self.argumentIsRequired = ""
130 if document is not None:
131 self.populate(document)
134 #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 <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
136 def populate(self,document, spaces = ""):
137 if document.nodeName == self.prefix_type+self.suffix_type:
138 for i in self.attributeNames:
139 self.attributes[i] = document.getAttribute(i)
140 for i in range(len(document.childNodes)):
141 child = document.childNodes[i]
142 if child.nodeType == child.ELEMENT_NODE:
143 if child.nodeName == self.prefix_type+self.suffix_type+".DisplayName":
144 self.DisplayName = getText(child.childNodes[1])
145 if child.nodeName == self.prefix_type+self.suffix_type+".Description":
146 self.Description = getText(child.childNodes[1])
147 if child.nodeName == "Argument":
148 self.argumentProperty = child.getAttribute("Property")
149 self.argumentIsRequired = child.getAttribute("IsRequired")
150 if child.nodeName == self.prefix_type+"Value":
151 va = Property(self.prefix_type,["Name","Switch"])
152 va.suffix_type = "Value"
154 self.values.append(va)
155 self.populate(child,spaces+"----")
160 toReturn = self.prefix_type+self.suffix_type+":"
161 for i in self.attributeNames:
162 toReturn += "\n "+i+": "+self.attributes[i]
163 if self.argumentProperty != "":
164 toReturn += "\n Argument:\n Property: "+self.argumentProperty+"\n IsRequired: "+self.argumentIsRequired
165 for i in self.values:
166 toReturn+="\n "+str(i).replace("\n","\n ")
168 ###########################################################################################
170 ###########################################################################################
171 #Class that populates itself from an MSBuild file and outputs it in CMake
174 class MSBuildToCMake:
175 #document = the entire MSBuild xml file
176 def __init__(self,document=None):
177 self.enumProperties = []
178 self.stringProperties = []
179 self.stringListProperties = []
180 self.boolProperties = []
181 self.intProperties = []
183 self.populate(document)
186 #document = the entire MSBuild xml file
188 #To add a new property (if they exist) copy and paste this code and fill in appropriate places
190 #if child.nodeName == "<Name>Property":
191 # self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
193 #Replace <Name> with the name of the new property (ex. if property is StringProperty replace <Name> with String)
194 #Replace <List of attributes> with a list of attributes in your property's root node
195 #in the __init__ function add the line self.<Name>Properties = []
197 #That is all that is required to add new properties
199 def populate(self,document, spaces=""):
200 for i in range(len(document.childNodes)):
201 child = document.childNodes[i]
202 if child.nodeType == child.ELEMENT_NODE:
203 if child.nodeName == "EnumProperty":
204 self.enumProperties.append(Property("Enum",["Name","Category"],child))
205 if child.nodeName == "StringProperty":
206 self.stringProperties.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","ReadOnly"],child))
207 if child.nodeName == "StringListProperty":
208 self.stringListProperties.append(Property("StringList",["Name","Category","Switch","Subtype"],child))
209 if child.nodeName == "BoolProperty":
210 self.boolProperties.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","SwitchPrefix","IncludeInCommandLine"],child))
211 if child.nodeName == "IntProperty":
212 self.intProperties.append(Property("Int",["Name","Category","Visible"],child))
213 self.populate(child,spaces+"----")
216 #outputs information that CMake needs to know about MSBuild xml files
218 toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
219 toReturn += "\n //Enum Properties\n"
221 for i in self.enumProperties:
222 if i.attributes["Name"] == "CompileAsManaged":
223 #write these out after the rest of the enumProperties
227 #hardcore Brad King's manual fixes for cmVS10CLFlagTable.h
228 if i.attributes["Name"] == "PrecompiledHeader" and j.attributes["Switch"] != "":
229 toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.DisplayName+"\", \""+j.attributes["Name"]+"\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
231 #default (normal, non-hardcoded) case
232 toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.DisplayName+"\", \""+j.attributes["Name"]+"\", 0},\n"
236 for j in lastProp.values:
237 toReturn+=" {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.DisplayName+"\", \""+j.attributes["Name"]+"\", 0},\n"
240 toReturn += "\n //Bool Properties\n"
241 for i in self.boolProperties:
242 if i.argumentProperty == "":
243 if i.attributes["ReverseSwitch"] != "":
244 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\", 0},\n"
245 if i.attributes["Switch"] != "":
246 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\", 0},\n"
248 toReturn += "\n //Bool Properties With Argument\n"
249 for i in self.boolProperties:
250 if i.argumentProperty != "":
251 if i.attributes["ReverseSwitch"] != "":
252 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
253 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \""+i.DisplayName+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
254 if i.attributes["Switch"] != "":
255 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
256 toReturn += " {\""+i.argumentProperty+"\", \""+i.attributes["Switch"]+"\", \""+i.DisplayName+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
258 toReturn += "\n //String List Properties\n"
259 for i in self.stringListProperties:
260 if i.attributes["Switch"] == "":
261 toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
263 toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n \""+i.DisplayName+"\",\n \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
265 toReturn += "\n //String Properties\n"
266 for i in self.stringProperties:
267 if i.attributes["Switch"] == "":
268 if i.attributes["Name"] == "PrecompiledHeaderFile":
270 toReturn += " {\"PrecompiledHeaderFile\", \"Yc\",\n"
271 toReturn += " \"Precompiled Header Name\",\n"
272 toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
273 toReturn += " {\"PrecompiledHeaderFile\", \"Yu\",\n"
274 toReturn += " \"Precompiled Header Name\",\n"
275 toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
277 toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
279 toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n \""+i.DisplayName+"\",\n \"\", cmVS7FlagTable::UserValue},\n"
281 toReturn += " {0,0,0,0,0}\n};"
288 allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties]
291 toReturn += "==================================================\n"+str(i).replace("\n","\n ")+"\n==================================================\n"
294 ###########################################################################################
296 ###########################################################################################
301 Please specify an input xml file with -x
304 Have a nice day :)"""
305 for i in range(0,len(argv)):
316 f = open(xml_file,"r")
318 xml_dom = parseString(xml_str)
320 convertor = MSBuildToCMake(xml_dom)
321 print convertor.toCMake()
324 ###########################################################################################
326 if __name__ == "__main__":