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"
9 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/cl.xml"
10 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/lib.xml"
11 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/link.xml"
12 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/cl.xml"
13 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/lib.xml"
14 # "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/link.xml"
16 # BoolProperty <Name>true|false</Name>
18 # <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
19 # Category="Optimization" Switch="Oy">
20 # <BoolProperty.DisplayName> <BoolProperty.Description>
22 # <OmitFramePointers>true</OmitFramePointers>
25 # argument means it might be this: /MP3
26 # example with argument:
27 # <BoolProperty Name="MultiProcessorCompilation" Category="General" Switch="MP">
28 # <BoolProperty.DisplayName>
29 # <sys:String>Multi-processor Compilation</sys:String>
30 # </BoolProperty.DisplayName>
31 # <BoolProperty.Description>
32 # <sys:String>Multi-processor Compilation</sys:String>
33 # </BoolProperty.Description>
34 # <Argument Property="ProcessorNumber" IsRequired="false" />
37 # <MultiProcessorCompilation>true</MultiProcessorCompilation>
38 # <ProcessorNumber>4</ProcessorNumber>
42 # <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
45 # per config options example
46 # <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
49 # <EnumProperty Name="Optimization" Category="Optimization">
50 # <EnumProperty.DisplayName>
51 # <sys:String>Optimization</sys:String>
52 # </EnumProperty.DisplayName>
53 # <EnumProperty.Description>
54 # <sys:String>Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)</sys:String>
55 # </EnumProperty.Description>
56 # <EnumValue Name="MaxSpeed" Switch="O2">
57 # <EnumValue.DisplayName>
58 # <sys:String>Maximize Speed</sys:String>
59 # </EnumValue.DisplayName>
60 # <EnumValue.Description>
61 # <sys:String>Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy</sys:String>
62 # </EnumValue.Description>
64 # <EnumValue Name="MinSpace" Switch="O1">
65 # <EnumValue.DisplayName>
66 # <sys:String>Minimize Size</sys:String>
67 # </EnumValue.DisplayName>
68 # <EnumValue.Description>
69 # <sys:String>Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy</sys:String>
70 # </EnumValue.Description>
72 # example for O2 would be this:
73 # <Optimization>MaxSpeed</Optimization>
74 # example for O1 would be this:
75 # <Optimization>MinSpace</Optimization>
78 # <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" Switch="D ">
79 # <StringListProperty.DisplayName>
80 # <sys:String>Preprocessor Definitions</sys:String>
81 # </StringListProperty.DisplayName>
82 # <StringListProperty.Description>
83 # <sys:String>Defines a preprocessing symbols for your source file.</sys:String>
84 # </StringListProperty.Description>
85 # </StringListProperty>
87 # <StringListProperty Subtype="folder" Name="AdditionalIncludeDirectories" Category="General" Switch="I">
88 # <StringListProperty.DisplayName>
89 # <sys:String>Additional Include Directories</sys:String>
90 # </StringListProperty.DisplayName>
91 # <StringListProperty.Description>
92 # <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>
93 # </StringListProperty.Description>
94 # </StringListProperty>
97 # Example add bill include:
99 # <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
103 from xml.dom.minidom import parse, parseString
106 nodelist = node.childNodes
108 for child in nodelist:
109 if child.nodeType == child.TEXT_NODE:
113 def print_tree(document, spaces=""):
114 for i in range(len(document.childNodes)):
115 if document.childNodes[i].nodeType == document.childNodes[i].ELEMENT_NODE:
116 print spaces+str(document.childNodes[i].nodeName )
117 print_tree(document.childNodes[i],spaces+"----")
120 ###########################################################################################
121 #Data structure that stores a property of MSBuild
123 #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum")
124 #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"])
125 #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">
126 def __init__(self,type,attributeNames,document=None):
127 self.suffix_type = "Property"
128 self.prefix_type = type
129 self.attributeNames = attributeNames
131 self.DisplayName = ""
132 self.Description = ""
133 self.argumentProperty = ""
134 self.argumentIsRequired = ""
136 if document is not None:
137 self.populate(document)
140 #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">
142 def populate(self,document, spaces = ""):
143 if document.nodeName == self.prefix_type+self.suffix_type:
144 for i in self.attributeNames:
145 self.attributes[i] = document.getAttribute(i)
146 for i in range(len(document.childNodes)):
147 child = document.childNodes[i]
148 if child.nodeType == child.ELEMENT_NODE:
149 if child.nodeName == self.prefix_type+self.suffix_type+".DisplayName":
150 self.DisplayName = getText(child.childNodes[1])
151 if child.nodeName == self.prefix_type+self.suffix_type+".Description":
152 self.Description = getText(child.childNodes[1])
153 if child.nodeName == "Argument":
154 self.argumentProperty = child.getAttribute("Property")
155 self.argumentIsRequired = child.getAttribute("IsRequired")
156 if child.nodeName == self.prefix_type+"Value":
157 va = Property(self.prefix_type,["Name","DisplayName","Switch"])
158 va.suffix_type = "Value"
160 self.values.append(va)
161 self.populate(child,spaces+"----")
166 toReturn = self.prefix_type+self.suffix_type+":"
167 for i in self.attributeNames:
168 toReturn += "\n "+i+": "+self.attributes[i]
169 if self.argumentProperty != "":
170 toReturn += "\n Argument:\n Property: "+self.argumentProperty+"\n IsRequired: "+self.argumentIsRequired
171 for i in self.values:
172 toReturn+="\n "+str(i).replace("\n","\n ")
174 ###########################################################################################
176 ###########################################################################################
177 #Class that populates itself from an MSBuild file and outputs it in CMake
180 class MSBuildToCMake:
181 #document = the entire MSBuild xml file
182 def __init__(self,document=None):
183 self.enumProperties = []
184 self.stringProperties = []
185 self.stringListProperties = []
186 self.boolProperties = []
187 self.intProperties = []
189 self.populate(document)
192 #document = the entire MSBuild xml file
194 #To add a new property (if they exist) copy and paste this code and fill in appropriate places
196 #if child.nodeName == "<Name>Property":
197 # self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
199 #Replace <Name> with the name of the new property (ex. if property is StringProperty replace <Name> with String)
200 #Replace <List of attributes> with a list of attributes in your property's root node
201 #in the __init__ function add the line self.<Name>Properties = []
203 #That is all that is required to add new properties
205 def populate(self,document, spaces=""):
206 for i in range(len(document.childNodes)):
207 child = document.childNodes[i]
208 if child.nodeType == child.ELEMENT_NODE:
209 if child.nodeName == "EnumProperty":
210 self.enumProperties.append(Property("Enum",["Name","Category"],child))
211 if child.nodeName == "StringProperty":
212 self.stringProperties.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","DisplayName","ReadOnly"],child))
213 if child.nodeName == "StringListProperty":
214 self.stringListProperties.append(Property("StringList",["Name","Category","Switch","DisplayName","Subtype"],child))
215 if child.nodeName == "BoolProperty":
216 self.boolProperties.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","DisplayName","SwitchPrefix","IncludeInCommandLine"],child))
217 if child.nodeName == "IntProperty":
218 self.intProperties.append(Property("Int",["Name","Category","Visible"],child))
219 self.populate(child,spaces+"----")
222 #outputs information that CMake needs to know about MSBuild xml files
224 toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
225 toReturn += "\n //Enum Properties\n"
227 for i in self.enumProperties:
228 if i.attributes["Name"] == "CompileAsManaged":
229 #write these out after the rest of the enumProperties
233 #hardcore Brad King's manual fixes for cmVS10CLFlagTable.h
234 if i.attributes["Name"] == "PrecompiledHeader" and j.attributes["Switch"] != "":
235 toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
237 #default (normal, non-hardcoded) case
238 toReturn+=" {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
242 for j in lastProp.values:
243 toReturn+=" {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
246 toReturn += "\n //Bool Properties\n"
247 for i in self.boolProperties:
248 if i.argumentProperty == "":
249 if i.attributes["ReverseSwitch"] != "":
250 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\", 0},\n"
251 if i.attributes["Switch"] != "":
252 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\", 0},\n"
254 toReturn += "\n //Bool Properties With Argument\n"
255 for i in self.boolProperties:
256 if i.argumentProperty != "":
257 if i.attributes["ReverseSwitch"] != "":
258 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
259 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
260 if i.attributes["Switch"] != "":
261 toReturn += " {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\",\n cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
262 toReturn += " {\""+i.argumentProperty+"\", \""+i.attributes["Switch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
264 toReturn += "\n //String List Properties\n"
265 for i in self.stringListProperties:
266 if i.attributes["Switch"] == "":
267 toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
269 toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
271 toReturn += "\n //String Properties\n"
272 for i in self.stringProperties:
273 if i.attributes["Switch"] == "":
274 if i.attributes["Name"] == "PrecompiledHeaderFile":
276 toReturn += " {\"PrecompiledHeaderFile\", \"Yc\",\n"
277 toReturn += " \"Precompiled Header Name\",\n"
278 toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
279 toReturn += " {\"PrecompiledHeaderFile\", \"Yu\",\n"
280 toReturn += " \"Precompiled Header Name\",\n"
281 toReturn += " \"\", cmVS7FlagTable::UserValueRequired},\n"
283 toReturn += " // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
285 toReturn +=" {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n \""+i.attributes["DisplayName"]+"\",\n \"\", cmVS7FlagTable::UserValue},\n"
287 toReturn += " {0,0,0,0,0}\n};"
294 allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties]
297 toReturn += "==================================================\n"+str(i).replace("\n","\n ")+"\n==================================================\n"
300 ###########################################################################################
302 ###########################################################################################
307 Please specify an input xml file with -x
310 Have a nice day :)"""
311 for i in range(0,len(argv)):
322 f = open(xml_file,"r")
324 xml_dom = parseString(xml_str)
326 convertor = MSBuildToCMake(xml_dom)
327 print convertor.toCMake()
330 ###########################################################################################
332 if __name__ == "__main__":