build: Use Python to Generate the MSVC Projects
[platform/upstream/atk.git] / build / msvcfiles.py
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
8
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]
15
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
38
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)
78
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
118
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
127
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)
149
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
169
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')
173
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')
178
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])
182
183     os.unlink(os.path.join(srcroot, 'build', 'win32', projname + '.sourcefiles'))
184
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')
188
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')
193
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')
198
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])
205
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'))
208
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'
222
223     with open (os.path.join (vs_file_list_dir,
224               projname + '.vs' + vsver + 'instfiles'), 'w') as vsinstlist:
225
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])
237
238     os.unlink(os.path.join (vs_file_list_dir, projname + '.vs' + vsver + 'instfiles'))
239
240 def generate_nmake_makefiles(srcroot, srcdir, base_name, makefile_name, progs_list):
241     file_list_dir = os.path.join (srcroot, 'build', 'win32')
242
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')
247
248
249     process_include (os.path.join(srcdir, makefile_name + 'in'),
250                     os.path.join(srcdir, makefile_name),
251                     includes = [file_list_dir])
252
253     os.unlink(os.path.join (file_list_dir, base_name + '_progs'))
254