chris
[tamarin-stm.git] / build / configuration.py
blob598e0bd999129144d763492384cb457a32b0ca70
1 # -*- Mode: Python; indent-tabs-mode: nil -*-
2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
13 # License.
15 # The Original Code is [Open Source Virtual Machine].
17 # The Initial Developer of the Original Code is
18 # Adobe System Incorporated.
19 # Portions created by the Initial Developer are Copyright (C) 2005-2006
20 # the Initial Developer. All Rights Reserved.
22 # Contributor(s):
24 # Alternatively, the contents of this file may be used under the terms of
25 # either the GNU General Public License Version 2 or later (the "GPL"), or
26 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 # in which case the provisions of the GPL or the LGPL are applicable instead
28 # of those above. If you wish to allow use of your version of this file only
29 # under the terms of either the GPL or the LGPL, and not to allow others to
30 # use your version of this file under the terms of the MPL, indicate your
31 # decision by deleting the provisions above and replace them with the notice
32 # and other provisions required by the GPL or the LGPL. If you do not delete
33 # the provisions above, a recipient may use your version of this file under
34 # the terms of any one of the MPL, the GPL or the LGPL.
36 # ***** END LICENSE BLOCK *****
38 import os
39 import sys
40 import build.process
41 import re
43 def writeFileIfChanged(path, contents):
44 """Write some contents to a file. Avoids modifying the file timestamp if the file contents already match."""
45 print "Generating " + path + "...",
46 try:
47 outf = open(path, "r")
48 oldcontents = outf.read()
49 outf.close()
51 if oldcontents == contents:
52 print "not changed"
53 return
54 except IOError:
55 pass
57 outf = open(path, "w")
58 outf.write(contents)
59 outf.close()
60 print
62 # Figure out TARGET and CPU, a la config.guess
63 # Do cross-compilation in the future, which will require HOST_OS and perhaps
64 # other settings
66 def _configGuess():
67 ostest = sys.platform
68 cputest = build.process.run_for_output(['uname', '-m'])
69 return _configSub(ostest, cputest)
71 def _configSub(ostest, cputest):
72 if ostest.startswith('win') or ostest.startswith('cygwin'):
73 os = 'windows'
74 elif ostest.startswith('darwin') or ostest.startswith('apple-darwin'):
75 os = 'darwin'
76 elif ostest.startswith('linux') or ostest.startswith('pc-linux'):
77 os = 'linux'
78 elif ostest.startswith('sunos'):
79 os = 'sunos'
80 else:
81 raise Exception('Unrecognized OS: ' + ostest)
83 if re.search(r'^i(\d86|86pc|x86)$', cputest):
84 cpu = 'i686'
85 elif re.search('^(x86_64|amd64)$', cputest):
86 cpu = 'x86_64'
87 elif re.search('^(ppc64|powerpc64)$', cputest):
88 cpu = 'ppc64'
89 elif re.search('^(ppc|powerpc|Power Macintosh)$', cputest):
90 cpu = 'powerpc'
91 elif re.search('sun', cputest):
92 cpu = 'sparc'
93 elif re.search('arm', cputest):
94 cpu = 'arm'
95 elif re.search('mips', cputest):
96 cpu = 'mips'
97 elif re.search('sh4', cputest):
98 cpu = 'sh4'
99 else:
100 raise Exception('Unrecognized CPU: ' + cputest)
102 return (os, cpu)
104 class Configuration:
105 def __init__(self, topsrcdir, options=None, sourcefile=None, objdir=None,
106 optimize=True, debug=False):
107 self._topsrcdir = topsrcdir
108 if objdir:
109 self._objdir = objdir
110 else:
111 self._objdir = os.getcwd()
113 self._optimize = optimize
114 self._debug = debug
115 self._host = _configGuess()
116 self._target = self._host
118 if sourcefile:
119 srcfile = self._topsrcdir + "/" + sourcefile
120 if not os.path.exists(srcfile):
121 raise Exception("Source file " + srcfile + " doesn't exist.")
123 objfile = self._objdir + "/" + sourcefile
124 if os.path.exists(objfile):
125 raise Exception("It appears you're trying to build in the source directory. "
126 "(Source file " + objfile + " exists here.) "
127 "You must use an object directory to build Tamarin. "
128 "Create an empty directory, cd into it, and run this configure.py script from there.")
131 if options:
132 o = options.getStringArg("optimize")
134 if o != None:
135 self._optimize = o
137 d = options.getStringArg("debug")
138 if d != None:
139 self._debug = d
141 if options.host:
142 hostcpu, hostos = options.host.split('-', 1)
143 self._host = _configSub(hostos, hostcpu)
145 if options.target:
146 targetcpu, targetos = options.target.split('-', 1)
147 self._target = _configSub(targetos, targetcpu)
149 self._acvars = {
150 'topsrcdir': self._topsrcdir,
151 'HOST_OS': self._host[0],
152 'TARGET_OS': self._target[0],
153 'TARGET_CPU': self._target[1]
156 if self._host[0] == 'windows':
157 self._acvars['topsrcdir'] = toMSYSPath(self._topsrcdir)
159 if self._debug:
160 self._acvars['ENABLE_DEBUG'] = 1
163 self._compiler = 'GCC'
164 self._acvars.update({
165 'I_SUFFIX': 'i',
166 'II_SUFFIX': 'ii',
167 'OBJ_SUFFIX': 'o',
168 'LIB_PREFIX': 'lib',
169 'LIB_SUFFIX': 'a',
170 'DLL_SUFFIX': 'so',
171 'PROGRAM_SUFFIX': '',
172 'USE_COMPILER_DEPS': 1,
173 'EXPAND_LIBNAME' : '-l$(1)',
174 'EXPAND_DLLNAME' : '-l$(1)',
175 'OUTOPTION' : '-o ',
176 'LIBPATH': '-L'
179 if self._target[0] == 'windows':
180 self._compiler = 'VS'
181 del self._acvars['USE_COMPILER_DEPS']
183 static_crt = options.getBoolArg('static-crt')
184 self._acvars.update({
185 'OBJ_SUFFIX' : 'obj',
186 'LIB_PREFIX' : '',
187 'LIB_SUFFIX' : 'lib',
188 'DLL_SUFFIX' : 'dll',
189 'PROGRAM_SUFFIX': '.exe',
190 'CPPFLAGS' : (self._debug and '-MTd' or '-MT') or (self._debug and '-MDd' or '-MD'),
191 'CXX' : 'cl.exe -nologo',
192 'CXXFLAGS' : '-TP',
193 'CC' : 'cl.exe -nologo',
194 'CFLAGS' : '-TC',
195 'DLL_CFLAGS' : '',
196 'AR' : 'lib.exe -nologo',
197 'LD' : 'link.exe -nologo',
198 'LDFLAGS' : '',
199 'MKSTATICLIB' : '$(AR) -OUT:$(1)',
200 'MKDLL' : '$(LD) -DLL -OUT:$(1)',
201 'MKPROGRAM' : '$(LD) -OUT:$(1)',
202 'EXPAND_LIBNAME' : '$(1).lib',
203 'EXPAND_DLLNAME' : '$(1).lib',
204 'OUTOPTION' : '-Fo',
205 'LIBPATH' : '-LIBPATH:'
207 if self._target[1] == "arm":
208 self._acvars.update({'LDFLAGS' : '-NODEFAULTLIB:"oldnames.lib" -ENTRY:"mainWCRTStartup"'})
209 if sys.platform.startswith('cygwin'):
210 self._acvars.update({'ASM' : '$(topsrcdir)/build/cygwin-wrapper.sh armasm.exe -nologo -arch 5T'})
211 else:
212 self._acvars.update({'ASM' : 'armasm.exe -nologo -arch 5T'})
214 if self._target[1] == "x86_64":
215 if sys.platform.startswith('cygwin'):
216 self._acvars.update({'MASM' : '$(topsrcdir)/build/cygwin-wrapper.sh ml64.exe -nologo -c '})
217 else:
218 self._acvars.update({'MASM' : 'ml64.exe -nologo -c '})
220 if sys.platform.startswith('cygwin'):
221 self._acvars.update({'CXX' : '$(topsrcdir)/build/cygwin-wrapper.sh cl.exe -nologo'})
222 self._acvars.update({'CC' : '$(topsrcdir)/build/cygwin-wrapper.sh cl.exe -nologo'})
224 # Hackery! Make assumptions that we want to build with GCC 3.3 on MacPPC
225 # and GCC4 on MacIntel
226 elif self._target[0] == 'darwin':
227 self._acvars.update({
228 'DLL_SUFFIX' : 'dylib',
229 'CPPFLAGS' : '-pipe',
230 'CXXFLAGS' : '',
231 'CFLAGS' : '',
232 'DLL_CFLAGS' : '-fPIC',
233 'LDFLAGS' : '-framework CoreServices',
234 'AR' : 'ar',
235 'MKSTATICLIB' : '$(AR) cr $(1)',
236 'MKDLL' : '$(CXX) -dynamiclib -single_module -install_name @executable_path/$(1) -o $(1)',
237 'MKPROGRAM' : '$(CXX) -o $(1)',
238 'POSTMKPROGRAM': 'dsymutil $(1)'
241 # -Wno-trigraphs -Wreturn-type -Wnon-virtual-dtor -Wmissing-braces -Wparentheses -Wunused-label -Wunused-parameter -Wunused-variable -Wunused-value -Wuninitialized
243 if 'CXX' in os.environ:
244 self._acvars['CXX'] = os.environ['CXX']
245 elif self._target[1] == 'i686':
246 self._acvars['CXX'] = 'g++'
247 self._acvars['CXXFLAGS'] += ' -arch i686 '
248 self._acvars['LDFLAGS'] += ' -arch i686 '
249 elif self._target[1] == 'x86_64':
250 self._acvars['CXX'] = 'g++'
251 self._acvars['CXXFLAGS'] += ' -arch x86_64 '
252 self._acvars['LDFLAGS'] += ' -arch x86_64 '
253 elif self._target[1] == 'powerpc':
254 self._acvars['CXX'] = 'g++'
255 self._acvars['CXXFLAGS'] += ' -arch ppc '
256 self._acvars['LDFLAGS'] += ' -arch ppc '
257 elif self._target[1] == 'ppc64':
258 self._acvars['CXX'] = 'g++'
259 self._acvars['CXXFLAGS'] += ' -arch ppc64 '
260 self._acvars['LDFLAGS'] += ' -arch ppc64 '
261 else:
262 raise Exception("Unexpected Darwin processor.")
264 if 'CC' in os.environ:
265 self._acvars['CC'] = os.environ['CC']
266 elif self._target[1] == 'i686':
267 self._acvars['CC'] = 'gcc'
268 self._acvars['CFLAGS'] += ' -arch i686 '
269 elif self._target[1] == 'x86_64':
270 self._acvars['CC'] = 'gcc'
271 self._acvars['CFLAGS'] += ' -arch x86_64 '
272 elif self._target[1] == 'powerpc':
273 self._acvars['CC'] = 'gcc'
274 self._acvars['CFLAGS'] += ' -arch ppc '
275 elif self._target[1] == 'ppc64':
276 self._acvars['CC'] = 'gcc'
277 self._acvars['CFLAGS'] += ' -arch ppc64 '
278 else:
279 raise Exception("Unexpected Darwin processor.")
281 elif self._target[0] == 'linux':
282 self._acvars.update({
283 'CPPFLAGS' : os.environ.get('CPPFLAGS', ''),
284 'CXX' : os.environ.get('CXX', 'g++'),
285 'CXXFLAGS' : os.environ.get('CXXFLAGS', ''),
286 'CC' : os.environ.get('CC', 'gcc'),
287 'CFLAGS' : os.environ.get('CFLAGS', ''),
288 'DLL_CFLAGS' : '-fPIC',
289 'LD' : os.environ.get('LD', 'ar'),
290 'LDFLAGS' : os.environ.get('LDFLAGS', ''),
291 'AR' : os.environ.get('AR', 'ar'),
292 'MKSTATICLIB' : '$(AR) cr $(1)',
293 'MKDLL' : '$(CXX) -shared -o $(1)',
294 'MKPROGRAM' : '$(CXX) -o $(1)'
296 if self._target[1] == "mips":
297 self._acvars.update({'CXXFLAGS' : ''})
298 self._acvars.update({'LDFLAGS' : ''})
299 self._acvars.update({'zlib_EXTRA_CFLAGS' : ''})
301 elif self._target[0] == 'sunos':
302 if options.getBoolArg("gcc", False):
303 self._acvars.update({
304 'CPPFLAGS' : os.environ.get('CPPFLAGS', '') + "-DBROKEN_OFFSETOF",
305 'CXX' : os.environ.get('CXX', 'g++'),
306 'CXXFLAGS' : os.environ.get('CXXFLAGS', ''),
307 'CC' : os.environ.get('CC', 'gcc'),
308 'CFLAGS' : os.environ.get('CFLAGS', ''),
309 'DLL_CFLAGS' : '-fPIC',
310 'LD' : 'ar',
311 'LDFLAGS' : '',
312 'MKSTATICLIB' : '$(AR) cr $(1)',
313 'MKDLL' : '$(CXX) -shared -o $(1)',
314 'MKPROGRAM' : '$(CXX) -o $(1)'
316 else:
317 self._compiler = 'SunStudio'
318 self._acvars.update({
319 'I_SUFFIX': 'i',
320 'II_SUFFIX': 'i',
321 'CPPFLAGS' : '',
322 'CXX' : 'CC',
323 'CXXFLAGS' : '',
324 'CC' : 'cc',
325 'CFLAGS' : '',
326 'LD' : 'ar',
327 'LDFLAGS' : '',
328 'MKSTATICLIB' : '$(AR) cr $(1)',
329 'MKPROGRAM' : '$(CXX) -o $(1)'
331 self._acvars['COMPILER'] = self._compiler
333 def getObjDir(self):
334 """Returns the build directory being configured."""
335 return self._objdir
337 def getHost(self):
338 """Returns an (os, cpu) tuple of the host machine."""
339 return self._host
341 def getTarget(self):
342 """Returns an (os, cpu) tuple of the target machine."""
343 return self._target
345 def getCompiler(self):
346 """Returns the compiler in use, as a string.
347 Possible values are:
348 - 'GCC': the GNU Compiler Collection, including GCC and G++
349 - 'VS': Microsoft Visual Studio
350 - 'SunStudio': Sun Studio"""
351 return self._compiler
353 def getDebug(self):
354 return self._debug
356 def subst(self, name, value):
357 self._acvars[name] = value
359 _confvar = re.compile("@([^@]+)@")
361 def generate(self, makefile):
362 outpath = self._objdir + "/" + makefile
364 contents = \
365 "\n".join([k + "=" + str(v) \
366 for (k,v) in self._acvars.iteritems()]) + \
367 "\n\ninclude $(topsrcdir)/build/config.mk\n" \
368 "include $(topsrcdir)/manifest.mk\n" \
369 "include $(topsrcdir)/build/rules.mk\n"
371 writeFileIfChanged(outpath, contents)
373 def toMSYSPath(path):
374 if sys.platform.startswith('cygwin'):
375 return path
376 elif path[1] != ':':
377 raise ValueError("win32 path without drive letter! %s" % path)
378 else:
379 return '/%s%s' % (path[0], path[2:].replace('\\', '/'))