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
8 # BoolProperty <Name>true|false</Name>
10 # <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
11 # Category="Optimization" Switch="Oy">
12 # <BoolProperty.DisplayName> <BoolProperty.Description>
14 # <OmitFramePointers>true</OmitFramePointers>
17 # argument means it might be this: /MP3
18 # example with argument:
19 # <BoolProperty Name="MultiProcessorCompilation" Category="General" Switch="MP">
20 # <BoolProperty.DisplayName>
21 # <sys:String>Multi-processor Compilation</sys:String>
22 # </BoolProperty.DisplayName>
23 # <BoolProperty.Description>
24 # <sys:String>Multi-processor Compilation</sys:String>
25 # </BoolProperty.Description>
26 # <Argument Property="ProcessorNumber" IsRequired="false" />
29 # <MultiProcessorCompilation>true</MultiProcessorCompilation>
30 # <ProcessorNumber>4</ProcessorNumber>
34 # <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
37 # per config options example
38 # <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
41 # <EnumProperty Name="Optimization" Category="Optimization">
42 # <EnumProperty.DisplayName>
43 # <sys:String>Optimization</sys:String>
44 # </EnumProperty.DisplayName>
45 # <EnumProperty.Description>
46 # <sys:String>Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)</sys:String>
47 # </EnumProperty.Description>
48 # <EnumValue Name="MaxSpeed" Switch="O2">
49 # <EnumValue.DisplayName>
50 # <sys:String>Maximize Speed</sys:String>
51 # </EnumValue.DisplayName>
52 # <EnumValue.Description>
53 # <sys:String>Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy</sys:String>
54 # </EnumValue.Description>
56 # <EnumValue Name="MinSpace" Switch="O1">
57 # <EnumValue.DisplayName>
58 # <sys:String>Minimize Size</sys:String>
59 # </EnumValue.DisplayName>
60 # <EnumValue.Description>
61 # <sys:String>Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy</sys:String>
62 # </EnumValue.Description>
64 # example for O2 would be this:
65 # <Optimization>MaxSpeed</Optimization>
66 # example for O1 would be this:
67 # <Optimization>MinSpace</Optimization>
70 # <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" Switch="D ">
71 # <StringListProperty.DisplayName>
72 # <sys:String>Preprocessor Definitions</sys:String>
73 # </StringListProperty.DisplayName>
74 # <StringListProperty.Description>
75 # <sys:String>Defines a preprocessing symbols for your source file.</sys:String>
76 # </StringListProperty.Description>
77 # </StringListProperty>
79 # <StringListProperty Subtype="folder" Name="AdditionalIncludeDirectories" Category="General" Switch="I">
80 # <StringListProperty.DisplayName>
81 # <sys:String>Additional Include Directories</sys:String>
82 # </StringListProperty.DisplayName>
83 # <StringListProperty.Description>
84 # <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>
85 # </StringListProperty.Description>
86 # </StringListProperty>
89 # Example add bill include:
91 # <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
95 from xml
.dom
.minidom
import parse
, parseString
98 nodelist
= node
.childNodes
100 for child
in nodelist
:
101 if child
.nodeType
== child
.TEXT_NODE
:
105 def print_tree(document
, spaces
=""):
106 for i
in range(len(document
.childNodes
)):
107 if document
.childNodes
[i
].nodeType
== document
.childNodes
[i
].ELEMENT_NODE
:
108 print spaces
+str(document
.childNodes
[i
].nodeName
)
109 print_tree(document
.childNodes
[i
],spaces
+"----")
112 ###########################################################################################
113 #Data structure that stores a property of MSBuild
115 #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum")
116 #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"])
117 #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">
118 def __init__(self
,type,attributeNames
,document
=None):
119 self
.suffix_type
= "Property"
120 self
.prefix_type
= type
121 self
.attributeNames
= attributeNames
123 self
.DisplayName
= ""
124 self
.Description
= ""
125 self
.argumentProperty
= ""
126 self
.argumentIsRequired
= ""
128 if document
is not None:
129 self
.populate(document
)
132 #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">
134 def populate(self
,document
, spaces
= ""):
135 if document
.nodeName
== self
.prefix_type
+self
.suffix_type
:
136 for i
in self
.attributeNames
:
137 self
.attributes
[i
] = document
.getAttribute(i
)
138 for i
in range(len(document
.childNodes
)):
139 child
= document
.childNodes
[i
]
140 if child
.nodeType
== child
.ELEMENT_NODE
:
141 if child
.nodeName
== self
.prefix_type
+self
.suffix_type
+".DisplayName":
142 self
.DisplayName
= getText(child
.childNodes
[1])
143 if child
.nodeName
== self
.prefix_type
+self
.suffix_type
+".Description":
144 self
.Description
= getText(child
.childNodes
[1])
145 if child
.nodeName
== "Argument":
146 self
.argumentProperty
= child
.getAttribute("Property")
147 self
.argumentIsRequired
= child
.getAttribute("IsRequired")
148 if child
.nodeName
== self
.prefix_type
+"Value":
149 va
= Property(self
.prefix_type
,["Name","Switch"])
150 va
.suffix_type
= "Value"
152 self
.values
.append(va
)
153 self
.populate(child
,spaces
+"----")
158 toReturn
= self
.prefix_type
+self
.suffix_type
+":"
159 for i
in self
.attributeNames
:
160 toReturn
+= "\n "+i
+": "+self
.attributes
[i
]
161 if self
.argumentProperty
!= "":
162 toReturn
+= "\n Argument:\n Property: "+self
.argumentProperty
+"\n IsRequired: "+self
.argumentIsRequired
163 for i
in self
.values
:
164 toReturn
+="\n "+str(i
).replace("\n","\n ")
166 ###########################################################################################
168 ###########################################################################################
169 #Class that populates itself from an MSBuild file and outputs it in CMake
172 class MSBuildToCMake
:
173 #document = the entire MSBuild xml file
174 def __init__(self
,document
=None):
175 self
.enumProperties
= []
176 self
.stringProperties
= []
177 self
.stringListProperties
= []
178 self
.boolProperties
= []
179 self
.intProperties
= []
181 self
.populate(document
)
184 #document = the entire MSBuild xml file
186 #To add a new property (if they exist) copy and paste this code and fill in appropriate places
188 #if child.nodeName == "<Name>Property":
189 # self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
191 #Replace <Name> with the name of the new property (ex. if property is StringProperty replace <Name> with String)
192 #Replace <List of attributes> with a list of attributes in your property's root node
193 #in the __init__ function add the line self.<Name>Properties = []
195 #That is all that is required to add new properties
197 def populate(self
,document
, spaces
=""):
198 for i
in range(len(document
.childNodes
)):
199 child
= document
.childNodes
[i
]
200 if child
.nodeType
== child
.ELEMENT_NODE
:
201 if child
.nodeName
== "EnumProperty":
202 self
.enumProperties
.append(Property("Enum",["Name","Category"],child
))
203 if child
.nodeName
== "StringProperty":
204 self
.stringProperties
.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","ReadOnly"],child
))
205 if child
.nodeName
== "StringListProperty":
206 self
.stringListProperties
.append(Property("StringList",["Name","Category","Switch","Subtype"],child
))
207 if child
.nodeName
== "BoolProperty":
208 self
.boolProperties
.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","SwitchPrefix","IncludeInCommandLine"],child
))
209 if child
.nodeName
== "IntProperty":
210 self
.intProperties
.append(Property("Int",["Name","Category","Visible"],child
))
211 self
.populate(child
,spaces
+"----")
214 #outputs information that CMake needs to know about MSBuild xml files
216 toReturn
= "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
217 toReturn
+= "\n //Enum Properties\n"
218 for i
in self
.enumProperties
:
220 toReturn
+=" {\""+i
.attributes
["Name"]+"\", \""+j
.attributes
["Switch"]+"\",\n \""+j
.DisplayName
+"\", \""+j
.attributes
["Name"]+"\", 0},\n"
224 toReturn
+= "\n //Bool Properties\n"
225 for i
in self
.boolProperties
:
226 if i
.argumentProperty
== "":
227 if i
.attributes
["ReverseSwitch"] != "":
228 toReturn
+= " {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["ReverseSwitch"]+"\", \"\", \"false\", 0},\n"
229 if i
.attributes
["Switch"] != "":
230 toReturn
+= " {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["Switch"]+"\", \"\", \"true\", 0},\n"
232 toReturn
+= "\n //Bool Properties With Argument\n"
233 for i
in self
.boolProperties
:
234 if i
.argumentProperty
!= "":
235 if i
.attributes
["ReverseSwitch"] != "":
236 toReturn
+= " {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["ReverseSwitch"]+"\", \"\", \"false\", cmVS7FlagTable::Continue},\n"
237 toReturn
+= " {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["ReverseSwitch"]+"\", \""+i
.DisplayName
+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
238 if i
.attributes
["Switch"] != "":
239 toReturn
+= " {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["Switch"]+"\", \"\", \"true\", cmVS7FlagTable::Continue},\n"
240 toReturn
+= " {\""+i
.argumentProperty
+"\", \""+i
.attributes
["Switch"]+"\", \""+i
.DisplayName
+"\", \"\",\n cmVS7FlagTable::UserValueRequired},\n"
242 toReturn
+= "\n //String List Properties\n"
243 for i
in self
.stringListProperties
:
244 if i
.attributes
["Switch"] == "":
245 toReturn
+= " // Skip [" + i
.attributes
["Name"] + "] - no command line Switch.\n";
247 toReturn
+=" {\""+i
.attributes
["Name"]+"\", \""+i
.attributes
["Switch"]+"\",\n \""+i
.DisplayName
+"\",\n \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
249 toReturn
+= " {0,0,0,0,0}\n};"
256 allList
= [self
.enumProperties
,self
.stringProperties
,self
.stringListProperties
,self
.boolProperties
,self
.intProperties
]
259 toReturn
+= "==================================================\n"+str(i
).replace("\n","\n ")+"\n==================================================\n"
262 ###########################################################################################
264 ###########################################################################################
269 Please specify an input xml file with -x
272 Have a nice day :)"""
273 for i
in range(0,len(argv
)):
284 f
= open(xml_file
,"r")
286 xml_dom
= parseString(xml_str
)
288 convertor
= MSBuildToCMake(xml_dom
)
289 print convertor
.toCMake()
292 ###########################################################################################
294 if __name__
== "__main__":