build: Use Python to Generate the MSVC Projects
[atk.git] / build / msvcfiles.py
blob05957acec248ecb393225bf4a094ee505f8fcbbd
1 #!/usr/bin/python
2 # vim: encoding=utf-8
3 #expand *.in files
4 import os
5 import sys
6 import re
7 import optparse
9 def parent_dir(path):
10 if not os.path.isabs(path):
11 path = os.path.abspath(path)
12 if os.path.isfile(path):
13 path = os.path.dirname(path)
14 return os.path.split(path)[0]
16 def check_output_type (btype):
17 print_bad_type = False
18 output_type = -1
19 if (btype is None):
20 output_type = -1
21 print_bad_type = False
22 elif (btype == "vs9"):
23 output_type = 1
24 elif (btype == "vs10"):
25 output_type = 2
26 elif (btype == "nmake-exe"):
27 output_type = 3
28 else:
29 output_type = -1
30 print_bad_type = True
31 if (output_type == -1):
32 if (print_bad_type is True):
33 print ("The entered output build file type '%s' is not valid" % btype)
34 else:
35 print ("Output build file type is not specified.\nUse -t <type> to specify the output build file type.")
36 print ("Valid output build file types are: nmake-exe, vs9 , vs10")
37 return output_type
39 def read_vars_from_AM(path, vars = {}, conds = {}, filters = None):
40 '''
41 path: path to the Makefile.am
42 vars: predefined variables
43 conds: condition variables for Makefile
44 filters: if None, all variables defined are returned,
45 otherwise, it is a list contains that variables should be returned
46 '''
47 cur_vars = vars.copy()
48 RE_AM_VAR_REF = re.compile(r'\$\((\w+?)\)')
49 RE_AM_VAR = re.compile(r'^\s*(\w+)\s*=(.*)$')
50 RE_AM_INCLUDE = re.compile(r'^\s*include\s+(\w+)')
51 RE_AM_VAR_ADD = re.compile(r'^\s*(\w+)\s*\+=(.*)$')
52 RE_AM_CONTINUING = re.compile(r'\\\s*$')
53 RE_AM_IF = re.compile(r'^\s*if\s+(\w+)')
54 RE_AM_ELSE = re.compile(r'^\s*else')
55 RE_AM_ENDIF = re.compile(r'^\s*endif')
56 def am_eval(cont):
57 return RE_AM_VAR_REF.sub(lambda x: cur_vars.get(x.group(1), ''), cont)
58 with open(path, 'r') as f:
59 contents = f.readlines()
60 #combine continuing lines
61 i = 0
62 ncont = []
63 while i < len(contents):
64 line = contents[i]
65 if RE_AM_CONTINUING.search(line):
66 line = RE_AM_CONTINUING.sub('', line)
67 j = i + 1
68 while j < len(contents) and RE_AM_CONTINUING.search(contents[j]):
69 line += RE_AM_CONTINUING.sub('', contents[j])
70 j += 1
71 else:
72 if j < len(contents):
73 line += contents[j]
74 i = j
75 else:
76 i += 1
77 ncont.append(line)
79 #include, var define, var evaluation
80 i = -1
81 skip = False
82 oldskip = []
83 while i < len(ncont) - 1:
84 i += 1
85 line = ncont[i]
86 mo = RE_AM_IF.search(line)
87 if mo:
88 oldskip.append(skip)
89 skip = False if mo.group(1) in conds and conds[mo.group(1)] \
90 else True
91 continue
92 mo = RE_AM_ELSE.search(line)
93 if mo:
94 skip = not skip
95 continue
96 mo = RE_AM_ENDIF.search(line)
97 if mo:
98 if oldskip:
99 skip = oldskip.pop()
100 continue
101 if not skip:
102 mo = RE_AM_INCLUDE.search(line)
103 if mo:
104 cur_vars.update(read_vars_from_AM(am_eval(mo.group(1)), cur_vars, conds, None))
105 continue
106 mo = RE_AM_VAR.search(line)
107 if mo:
108 cur_vars[mo.group(1)] = am_eval(mo.group(2).strip())
109 continue
110 mo = RE_AM_VAR_ADD.search(line)
111 if mo:
112 try:
113 cur_vars[mo.group(1)] += ' '
114 except KeyError:
115 cur_vars[mo.group(1)] = ''
116 cur_vars[mo.group(1)] += am_eval(mo.group(2).strip())
117 continue
119 #filter:
120 if filters != None:
121 ret = {}
122 for i in filters:
123 ret[i] = cur_vars.get(i, '')
124 return ret
125 else:
126 return cur_vars
128 def process_include(src, dest, includes):
129 RE_INCLUDE = re.compile(r'^\s*#include\s+"(.*)"')
130 with open(src, 'r') as s:
131 with open(dest, 'w') as d:
132 for i in s:
133 mo = RE_INCLUDE.search(i)
134 if mo:
135 target = ''
136 for j in includes:
137 #print "searching in ", j
138 if mo.group(1) in os.listdir(j):
139 target = os.path.join(j, mo.group(1))
140 break
141 if not target:
142 raise Exception("Couldn't find include file %s" % mo.group(1))
143 else:
144 with open(target, 'r') as t:
145 for inc in t.readlines():
146 d.write(inc)
147 else:
148 d.write(i)
150 #Generate the source files listing that is used
151 def generate_src_list (srcroot, srcdir, filters_src, filter_conds, filter_c, mk_am_file):
152 mkfile = ''
153 if mk_am_file is None or mk_am_file == '':
154 mkfile = 'Makefile.am'
155 else:
156 mkfile = mk_am_file
157 vars = read_vars_from_AM(os.path.join(srcdir, mkfile),
158 vars = {'top_srcdir': srcroot},
159 conds = filter_conds,
160 filters = filters_src)
161 files = []
162 for src_filters_item in filters_src:
163 files += vars[src_filters_item].split()
164 if filter_c is True:
165 sources = [i for i in files if i.endswith('.c') ]
166 return sources
167 else:
168 return files
170 # Generate the Visual Studio 2008 Project Files from the templates
171 def gen_vs9_project (projname, srcroot, srcdir_name, sources_list):
172 vs_file_list_dir = os.path.join (srcroot, 'build', 'win32')
174 with open (os.path.join (vs_file_list_dir,
175 projname + '.sourcefiles'), 'w') as vs9srclist:
176 for i in sources_list:
177 vs9srclist.write ('\t\t\t<File RelativePath="..\\..\\..\\' + srcdir_name + '\\' + i.replace('/', '\\') + '" />\n')
179 process_include (os.path.join(srcroot, 'build', 'win32', 'vs9', projname + '.vcprojin'),
180 os.path.join(srcroot, 'build', 'win32', 'vs9', projname + '.vcproj'),
181 includes = [vs_file_list_dir])
183 os.unlink(os.path.join(srcroot, 'build', 'win32', projname + '.sourcefiles'))
185 # Generate the Visual Studio 2010 Project Files from the templates
186 def gen_vs10_project (projname, srcroot, srcdir_name, sources_list):
187 vs_file_list_dir = os.path.join (srcroot, 'build', 'win32')
189 with open (os.path.join (vs_file_list_dir,
190 projname + '.vs10.sourcefiles'), 'w') as vs10srclist:
191 for j in sources_list:
192 vs10srclist.write (' <ClCompile Include="..\\..\\..\\' + srcdir_name + '\\' + j.replace('/', '\\') + '" />\n')
194 with open (os.path.join (vs_file_list_dir,
195 projname + '.vs10.sourcefiles.filters'), 'w') as vs10srclist_filter:
196 for k in sources_list:
197 vs10srclist_filter.write (' <ClCompile Include="..\\..\\..\\' + srcdir_name + '\\' + k.replace('/', '\\') + '"><Filter>Source Files</Filter></ClCompile>\n')
199 process_include (os.path.join(srcroot, 'build', 'win32', 'vs10', projname + '.vcxprojin'),
200 os.path.join(srcroot, 'build', 'win32', 'vs10', projname + '.vcxproj'),
201 includes = [vs_file_list_dir])
202 process_include (os.path.join(srcroot, 'build', 'win32', 'vs10', projname + '.vcxproj.filtersin'),
203 os.path.join(srcroot, 'build', 'win32', 'vs10', projname + '.vcxproj.filters'),
204 includes = [vs_file_list_dir])
206 os.unlink(os.path.join(srcroot, 'build', 'win32', projname + '.vs10.sourcefiles'))
207 os.unlink(os.path.join(srcroot, 'build', 'win32', projname + '.vs10.sourcefiles.filters'))
209 def gen_vs_inst_list (projname, srcroot, srcdirs, inst_lists, destdir_names, isVS9):
210 vs_file_list_dir = os.path.join (srcroot, 'build', 'win32')
211 vsver = ''
212 vsprops_line_ending = ''
213 vsprops_file_ext = ''
214 if isVS9 is True:
215 vsver = '9'
216 vsprops_line_ending = '&#x0D;&#x0A;\n'
217 vsprops_file_ext = '.vsprops'
218 else:
219 vsver = '10'
220 vsprops_line_ending = '\n\n'
221 vsprops_file_ext = '.props'
223 with open (os.path.join (vs_file_list_dir,
224 projname + '.vs' + vsver + 'instfiles'), 'w') as vsinstlist:
226 for file_list, srcdir, dir_name in zip (inst_lists, srcdirs, destdir_names):
227 for i in file_list:
228 vsinstlist.write ('copy ..\\..\\..\\' +
229 srcdir + '\\' +
230 i.replace ('/', '\\') +
231 ' $(CopyDir)\\' +
232 dir_name +
233 vsprops_line_ending)
234 process_include (os.path.join(srcroot, 'build', 'win32', 'vs' + vsver, projname + '-install' + vsprops_file_ext + 'in'),
235 os.path.join(srcroot, 'build', 'win32', 'vs' + vsver, projname + '-install' + vsprops_file_ext),
236 includes = [vs_file_list_dir])
238 os.unlink(os.path.join (vs_file_list_dir, projname + '.vs' + vsver + 'instfiles'))
240 def generate_nmake_makefiles(srcroot, srcdir, base_name, makefile_name, progs_list):
241 file_list_dir = os.path.join (srcroot, 'build', 'win32')
243 with open (os.path.join (file_list_dir,
244 base_name + '_progs'), 'w') as proglist:
245 for i in progs_list:
246 proglist.write ('\t' + i + '$(EXEEXT)\t\\\n')
249 process_include (os.path.join(srcdir, makefile_name + 'in'),
250 os.path.join(srcdir, makefile_name),
251 includes = [file_list_dir])
253 os.unlink(os.path.join (file_list_dir, base_name + '_progs'))