improved and completely automatic vc2010 projectfile updater
[libfirm] / win32 / vc2010 / update_vc_project.py
1 #!/usr/bin/env python
2 # Update msvc project...
3 #
4 # This basically reads in the existing project file and replaces the list of
5 # files in there while keeping the project settings and compiler flags
6 # intact...
7 from lxml import etree as ElementTree
8 import glob
9 import os
10 import uuid
11
12 # Namespace handling in ElementTree really sucks...
13 ms_ns = "http://schemas.microsoft.com/developer/msbuild/2003"
14 ns = "{%s}" % ms_ns
15
16 vcxproj = ElementTree.parse("firm.vcxproj")
17 project = vcxproj.getroot()
18
19 # Find the correct "ItemGroup" element. (somehow there are multiple of them
20 # in the file). The first one without a "Label" attribute seems to be the
21 # one we want...
22 mainItemGroup = None
23 for igroup in project.findall(ns+"ItemGroup"):
24         if "Label" in igroup.attrib:
25                 continue
26         mainItemGroup = igroup
27         break
28 # Remove all existing compile statement, we will recreate them
29 for comp in (mainItemGroup.findall(ns+"ClCompile") +
30                 mainItemGroup.findall(ns+"ClInclude") +
31                 mainItemGroup.findall(ns+"None") +
32                 mainItemGroup.findall(ns+"CustomBuild")):
33         mainItemGroup.remove(comp)
34
35 filters = ElementTree.parse("firm.vcxproj.filters")
36 fproject = filters.getroot()
37 # The first "ItemGroup" appears to contain directories, the second one
38 # most of the files. (and the 3rd/4th is unclear to me...)
39 dirfilters = None
40 filefilters = None
41 for igroup in fproject.findall(ns+"ItemGroup"):
42         if dirfilters == None:
43                 dirfilters = igroup
44         else:
45                 filefilters = igroup
46                 break
47
48 # Simply remove everything
49 for f in dirfilters.findall(ns+"Filter"):
50         dirfilters.remove(f)
51 for f in filefilters.findall(ns+"Filter"):
52         filefilters.remove(f)
53
54 # simply remove everything
55
56 # Directory where we find sourcefiles and at the same time the list of
57 # directories that will appear in the project.
58 # Note that you have to specify all parent dirs, so if you have "ir/foo"
59 # then make sure "ir" is in the list too before "ir/foo"
60 dirs = [
61         "scripts",
62         "ir",
63         "ir/adt",
64         "ir/ana",
65         "ir/be",
66         "ir/be/scripts",
67         "ir/common",
68         "ir/debug",
69         "ir/ident",
70         "ir/ir",
71         "ir/libcore",
72         "ir/lower",
73         "ir/obstack",
74         "ir/opt",
75         "ir/stat",
76         "ir/tr",
77         "ir/tv",
78         "win32",
79         "include",
80         "include/libfirm",
81         "include/libfirm/adt"
82 ]
83 backends = [ "ia32", "arm", "amd64", "sparc", "TEMPLATE" ]
84 dirs += map(lambda x: "ir/be/%s" % x, backends)
85
86 # Adds a file to the project. With build type @p type.
87 # This also adds a filter with the same name as the files directory
88 def addFile(type, f):
89         global filefilters
90         inc = "$(FirmRoot)\\%s" % f.replace("/", "\\")
91         element = ElementTree.SubElement(mainItemGroup, ns+type, Include=inc)
92         fc = ElementTree.SubElement(filefilters, ns+type, Include=inc)
93         filt = ElementTree.SubElement(fc, ns+"Filter")
94         filt.text = os.path.dirname(f).replace("/", "\\")
95         return element
96
97 os.chdir("../..")
98 # "Normal" .c/.h files
99 for d in dirs:
100         # Create the filtergroup for the directory
101         wind = d.replace("/", "\\")
102         f = ElementTree.SubElement(dirfilters, ns+"Filter", Include=wind)
103         ui = ElementTree.SubElement(f, ns+"UniqueIdentifier")
104         ui.text = "{%s}" % uuid.uuid4()
105
106         # Compile normal C files
107         for cfile in glob.glob("%s/*.c" % d):
108                 addFile("ClCompile", cfile)
109         # "Include" header files
110         for hfile in glob.glob("%s/*.h" % d):
111                 addFile("ClInclude", hfile)
112
113 # CustomBuild stuff for the backends
114 custombuild = []
115 for be in backends:
116         spec = "ir/be/%s/%s_spec.pl" % (be,be)
117         custombuild.append(spec)
118         cb = addFile("CustomBuild", spec)
119         message = ElementTree.SubElement(cb, ns+"Message")
120         message.text = "Translate Spec: %(FullPath)"
121         command = ElementTree.SubElement(cb, ns+"Command")
122         command.text = \
123 """$(FirmRoot)\\ir\\be\\scripts\\generate_emitter.pl %%(FullPath) $(FirmRoot)\\ir\\be\\%(arch)s
124 $(FirmRoot)\\ir\\be\\scripts\\generate_new_opcodes.pl %%(FullPath) $(FirmRoot)\\ir\\be\\%(arch)s
125 $(FirmRoot)\\ir\\be\\scripts\\generate_regalloc_if.pl %%(FullPath) $(FirmRoot)\\ir\\be\\%(arch)s
126 $(FirmRoot)\\ir\\be\\scripts\\generate_machine.pl %%(FullPath) $(FirmRoot)\\ir\\be\\%(arch)s
127 """ % { "arch":be }
128
129         inputfiles = [
130                         "ir/be/scripts/generate_emitter.pl",
131                         "ir/be/scripts/generate_new_opcodes.pl",
132                         "ir/be/scripts/generate_regalloc_if.pl",
133                         "ir/be/scripts/generate_machine.pl",
134         ]
135         inputfiles = map(lambda x: "$(FirmRoot)\\%s" % x.replace("/", "\\"), inputfiles)
136         inputfiles.append("$(AdditonalInputs)")
137         inputs = ElementTree.SubElement(cb, ns+"AdditionalInputs")
138         inputs.text = ";".join(inputfiles)
139
140         outputfiles = [
141                         "ir/be/%s/gen_%s_emitter.c" % (be,be),
142                         "ir/be/%s/gen_%s_emitter.h" % (be,be),
143                         "ir/be/%s/gen_%s_new_nodes.c" % (be,be),
144                         "ir/be/%s/gen_%s_new_nodes.h" % (be,be),
145                         "ir/be/%s/gen_%s_regalloc_if.c" % (be,be),
146                         "ir/be/%s/gen_%s_regalloc_if.h" % (be,be),
147                         "ir/be/%s/gen_%s_machine.c" % (be,be),
148                         "ir/be/%s/gen_%s_machine.h" % (be,be)
149         ]
150         outputfiles = map(lambda x: "$(FirmRoot)\\%s" % x.replace("/", "\\"), outputfiles)
151         outputfiles.append("$(Outputs)")
152         outputs = ElementTree.SubElement(cb, ns+"Outputs")
153         outputs.text = ";".join(outputfiles)
154
155 # CustomBuild for ir_io:
156 custombuild.append("scripts/gen_ir_io.py")
157 cb = addFile("CustomBuild", "scripts/gen_ir_io.py")
158 message = ElementTree.SubElement(cb, ns+"Message")
159 message.text = "Generating I/O code: %(FullPath)"
160 command = ElementTree.SubElement(cb, ns+"Command")
161 command.text = "python %(FullPath) $(FirmRoot)\\scripts\\ir_spec.py $(FirmRoot)\\ir\\ir"
162 additionalinputs = ElementTree.SubElement(cb, ns+"AdditionalInputs")
163 additionalinputs.text = "$(FirmRoot)\\scripts\\ir_spec.py;%(AdditionalInputs)"
164 outputs = ElementTree.SubElement(cb, ns+"Outputs")
165 outputs.text = "$(FirmRoot)\\ir\\ir\\gen_irio_import.inl;$(FirmRoot)\\ir\\ir\\gen_irio_export.inl;$(FirmRoot)\\ir\\ir\\gen_irio_lex.inl;%(Outputs)"
166
167 # CustomBuild for ir_spec:
168 custombuild.append("scripts/gen_ir.py")
169 cb = addFile("CustomBuild", "scripts/gen_ir.py")
170 message = ElementTree.SubElement(cb, ns+"Message")
171 message.text = "Translate IR-Spec: %(FullPath)"
172 command = ElementTree.SubElement(cb, ns+"Command")
173 command.text = "python %(FullPath) $(FirmRoot) $(FirmRoot)\\ir\\ir"
174 additionalinputs = ElementTree.SubElement(cb, ns+"AdditionalInputs")
175 additionalinputs.text = "$(FirmRoot)\\scripts\\gen_ir.py;%(AdditionalInputs)"
176 outputs = ElementTree.SubElement(cb, ns+"Outputs")
177 outputs.text = "$(FirmRoot)\ir\ir\gen_ir_cons.c.inl;$(FirmRoot)\ir\ir\gen_irnode.h;$(FirmRoot)\ir\ir\gen_irnode.c.inl;$(FirmRoot)\ir\ir\gen_irop.c.inl;%(Outputs)"
178
179 # Stuff we simply include... but which is neither a .c nor a .h file
180 stuff = [
181         "ir/ir/irflag_t.def",
182         "ir/libcore/lc_printf_arg_types.def",
183 ]
184 stuff += glob.glob("scripts/*.py")
185 stuff += glob.glob("ir/be/scripts/*.pl")
186 for s in stuff:
187         if s in custombuild:
188                 continue
189         addFile("None", s)
190
191 vcxproj.write("/tmp/out.xml")
192 filters.write("/tmp/outf.xml")
193
194 # Use xmllint to reformat the output to something more readable
195 vcxo = "/tmp/firm.vcxproj"
196 vcxfo = "/tmp/firm.vcxproj.filters"
197 os.system("xmllint --format /tmp/out.xml > %s" % vcxo)
198 os.system("xmllint --format /tmp/outf.xml > %s" % vcxfo)
199
200 print "Generated: %s %s" % (vcxo, vcxfo)