Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmparseMSBuildXML.py
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:
4
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"
15 #
16 #  BoolProperty  <Name>true|false</Name>
17 #   simple example:
18 #     <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
19 #      Category="Optimization" Switch="Oy">
20 #   <BoolProperty.DisplayName>  <BoolProperty.Description>
21 # <CLCompile>
22 #     <OmitFramePointers>true</OmitFramePointers>
23 #  </ClCompile>
24 #
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" />
35 #    </BoolProperty>
36 # <CLCompile>
37 #   <MultiProcessorCompilation>true</MultiProcessorCompilation>
38 #   <ProcessorNumber>4</ProcessorNumber>
39 #  </ClCompile>
40 #  IntProperty
41 #     not used AFIT
42 #  <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
43
44
45 #  per config options example
46 #    <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
47 #
48 #  EnumProperty
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>
63 #     </EnumValue>
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>
71 #     </EnumValue>
72 #     example for O2 would be this:
73 #     <Optimization>MaxSpeed</Optimization>
74 #     example for O1 would be this:
75 #     <Optimization>MinSpace</Optimization>
76 #
77 #  StringListProperty
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>
86
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>
95 #  StringProperty
96
97 # Example add bill include:
98
99 #   <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
100
101
102 import sys
103 from xml.dom.minidom import parse, parseString
104
105 def getText(node):
106     nodelist = node.childNodes
107     rc = ""
108     for child in nodelist:
109         if child.nodeType == child.TEXT_NODE:
110             rc = rc + child.data
111     return rc
112
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+"----")
118   pass
119
120 ###########################################################################################
121 #Data structure that stores a property of MSBuild
122 class Property:
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
130     self.attributes = {}
131     self.DisplayName = ""
132     self.Description = ""
133     self.argumentProperty = ""
134     self.argumentIsRequired = ""
135     self.values = []
136     if document is not None:
137       self.populate(document)
138     pass
139
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">
141   #spaces = do not use
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"
159           va.populate(child)
160           self.values.append(va)
161       self.populate(child,spaces+"----")
162       pass
163
164   #toString function
165   def __str__(self):
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    ")
173     return toReturn
174 ###########################################################################################
175
176 ###########################################################################################
177 #Class that populates itself from an MSBuild file and outputs it in CMake
178 #format
179
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 = []
188     if document!=None :
189       self.populate(document)
190     pass
191
192   #document = the entire MSBuild xml file
193   #spaces = don't use
194   #To add a new property (if they exist) copy and paste this code and fill in appropriate places
195   #
196   #if child.nodeName == "<Name>Property":
197   #        self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
198   #
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 = []
202   #
203   #That is all that is required to add new properties
204   #
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+"----")
220     pass
221
222   #outputs information that CMake needs to know about MSBuild xml files
223   def toCMake(self):
224     toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
225     toReturn += "\n  //Enum Properties\n"
226     lastProp = {}
227     for i in self.enumProperties:
228       if i.attributes["Name"] == "CompileAsManaged":
229         #write these out after the rest of the enumProperties
230         lastProp = i
231         continue
232       for j in i.values:
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"
236         else:
237           #default (normal, non-hardcoded) case
238           toReturn+="  {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n   \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
239       toReturn += "\n"
240
241     if lastProp != {}:
242       for j in lastProp.values:
243           toReturn+="  {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n   \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
244       toReturn += "\n"
245
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"
253
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"
263
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";
268       else:
269         toReturn +="  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n   \""+i.attributes["DisplayName"]+"\",\n   \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
270
271     toReturn += "\n  //String Properties\n"
272     for i in self.stringProperties:
273       if i.attributes["Switch"] == "":
274         if i.attributes["Name"] == "PrecompiledHeaderFile":
275           #more hardcoding
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"
282         else:
283           toReturn += "  // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
284       else:
285         toReturn +="  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n   \""+i.attributes["DisplayName"]+"\",\n   \"\", cmVS7FlagTable::UserValue},\n"
286
287     toReturn += "  {0,0,0,0,0}\n};"
288     return toReturn
289     pass
290
291   #toString function
292   def __str__(self):
293     toReturn = ""
294     allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties]
295     for p in allList:
296       for i in p:
297         toReturn += "==================================================\n"+str(i).replace("\n","\n    ")+"\n==================================================\n"
298
299     return toReturn
300 ###########################################################################################
301
302 ###########################################################################################
303 # main function
304 def main(argv):
305   xml_file = None
306   help = """
307   Please specify an input xml file with -x
308
309   Exiting...
310   Have a nice day :)"""
311   for i in range(0,len(argv)):
312     if argv[i] == "-x":
313       xml_file = argv[i+1]
314     if argv[i] == "-h":
315       print help
316       sys.exit(0)
317     pass
318   if xml_file == None:
319     print help
320     sys.exit(1)
321
322   f = open(xml_file,"r")
323   xml_str = f.read()
324   xml_dom = parseString(xml_str)
325
326   convertor = MSBuildToCMake(xml_dom)
327   print convertor.toCMake()
328
329   xml_dom.unlink()
330 ###########################################################################################
331 # main entry point
332 if __name__ == "__main__":
333   main(sys.argv)
334
335 sys.exit(0)