scons: New build= option, with support for checked builds.
[mesa.git] / scons / gallium.py
1 """gallium
2
3 Frontend-tool for Gallium3D architecture.
4
5 """
6
7 #
8 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
9 # All Rights Reserved.
10 #
11 # Permission is hereby granted, free of charge, to any person obtaining a
12 # copy of this software and associated documentation files (the
13 # "Software"), to deal in the Software without restriction, including
14 # without limitation the rights to use, copy, modify, merge, publish,
15 # distribute, sub license, and/or sell copies of the Software, and to
16 # permit persons to whom the Software is furnished to do so, subject to
17 # the following conditions:
18 #
19 # The above copyright notice and this permission notice (including the
20 # next paragraph) shall be included in all copies or substantial portions
21 # of the Software.
22 #
23 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
26 # IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
27 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #
31
32
33 import distutils.version
34 import os
35 import os.path
36 import re
37 import subprocess
38
39 import SCons.Action
40 import SCons.Builder
41 import SCons.Scanner
42
43
44 def symlink(target, source, env):
45 target = str(target[0])
46 source = str(source[0])
47 if os.path.islink(target) or os.path.exists(target):
48 os.remove(target)
49 os.symlink(os.path.basename(source), target)
50
51 def install(env, source, subdir):
52 target_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build_dir'], subdir)
53 env.Install(target_dir, source)
54
55 def install_program(env, source):
56 install(env, source, 'bin')
57
58 def install_shared_library(env, sources, version = ()):
59 install_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build_dir'])
60 version = tuple(map(str, version))
61 if env['SHLIBSUFFIX'] == '.dll':
62 dlls = env.FindIxes(sources, 'SHLIBPREFIX', 'SHLIBSUFFIX')
63 install(env, dlls, 'bin')
64 libs = env.FindIxes(sources, 'LIBPREFIX', 'LIBSUFFIX')
65 install(env, libs, 'lib')
66 else:
67 for source in sources:
68 target_dir = os.path.join(install_dir, 'lib')
69 target_name = '.'.join((str(source),) + version)
70 last = env.InstallAs(os.path.join(target_dir, target_name), source)
71 while len(version):
72 version = version[:-1]
73 target_name = '.'.join((str(source),) + version)
74 action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE")
75 last = env.Command(os.path.join(target_dir, target_name), last, action)
76
77 def createInstallMethods(env):
78 env.AddMethod(install_program, 'InstallProgram')
79 env.AddMethod(install_shared_library, 'InstallSharedLibrary')
80
81
82 def num_jobs():
83 try:
84 return int(os.environ['NUMBER_OF_PROCESSORS'])
85 except (ValueError, KeyError):
86 pass
87
88 try:
89 return os.sysconf('SC_NPROCESSORS_ONLN')
90 except (ValueError, OSError, AttributeError):
91 pass
92
93 try:
94 return int(os.popen2("sysctl -n hw.ncpu")[1].read())
95 except ValueError:
96 pass
97
98 return 1
99
100
101 def generate(env):
102 """Common environment generation code"""
103
104 # Toolchain
105 platform = env['platform']
106 if env['toolchain'] == 'default':
107 if platform == 'winddk':
108 env['toolchain'] = 'winddk'
109 elif platform == 'wince':
110 env['toolchain'] = 'wcesdk'
111 env.Tool(env['toolchain'])
112
113 if env['platform'] == 'embedded':
114 # Allow overriding compiler from environment
115 if os.environ.has_key('CC'):
116 env['CC'] = os.environ['CC']
117 # Update CCVERSION to match
118 pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
119 stdin = 'devnull',
120 stderr = 'devnull',
121 stdout = subprocess.PIPE)
122 if pipe.wait() == 0:
123 line = pipe.stdout.readline()
124 match = re.search(r'[0-9]+(\.[0-9]+)+', line)
125 if match:
126 env['CCVERSION'] = match.group(0)
127
128
129 env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-')
130 env['msvc'] = env['CC'] == 'cl'
131
132 # shortcuts
133 debug = env['debug']
134 machine = env['machine']
135 platform = env['platform']
136 x86 = env['machine'] == 'x86'
137 ppc = env['machine'] == 'ppc'
138 gcc = env['gcc']
139 msvc = env['msvc']
140
141 # Backwards compatability with the debug= profile= options
142 if env['build'] == 'debug':
143 if not env['debug']:
144 print 'scons: debug option is deprecated: use instead build=release'
145 env['build'] = 'release'
146 if env['profile']:
147 print 'scons: profile option is deprecated: use instead build=profile'
148 env['build'] = 'profile'
149 if False:
150 # Enforce SConscripts to use the new build variable
151 env.popitem('debug')
152 env.popitem('profile')
153 else:
154 # Backwards portability with older sconscripts
155 if env['build'] in ('debug', 'checked'):
156 env['debug'] = True
157 env['profile'] = False
158 if env['build'] == 'profile':
159 env['debug'] = False
160 env['profile'] = True
161 if env['build'] == 'release':
162 env['debug'] = False
163 env['profile'] = False
164
165 # Put build output in a separate dir, which depends on the current
166 # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
167 build_topdir = 'build'
168 build_subdir = env['platform']
169 if env['machine'] != 'generic':
170 build_subdir += '-' + env['machine']
171 if env['build'] != 'release':
172 build_subdir += '-' + env['build']
173 build_dir = os.path.join(build_topdir, build_subdir)
174 # Place the .sconsign file in the build dir too, to avoid issues with
175 # different scons versions building the same source file
176 env['build_dir'] = build_dir
177 env.SConsignFile(os.path.join(build_dir, '.sconsign'))
178 if 'SCONS_CACHE_DIR' in os.environ:
179 print 'scons: Using build cache in %s.' % (os.environ['SCONS_CACHE_DIR'],)
180 env.CacheDir(os.environ['SCONS_CACHE_DIR'])
181 env['CONFIGUREDIR'] = os.path.join(build_dir, 'conf')
182 env['CONFIGURELOG'] = os.path.join(os.path.abspath(build_dir), 'config.log')
183
184 # Parallel build
185 if env.GetOption('num_jobs') <= 1:
186 env.SetOption('num_jobs', num_jobs())
187
188 # C preprocessor options
189 cppdefines = []
190 if env['build'] in ('debug', 'checked'):
191 cppdefines += ['DEBUG']
192 else:
193 cppdefines += ['NDEBUG']
194 if env['build'] == 'profile':
195 cppdefines += ['PROFILE']
196 if platform == 'windows':
197 cppdefines += [
198 'WIN32',
199 '_WINDOWS',
200 #'_UNICODE',
201 #'UNICODE',
202 # http://msdn.microsoft.com/en-us/library/aa383745.aspx
203 ('_WIN32_WINNT', '0x0601'),
204 ('WINVER', '0x0601'),
205 ]
206 if msvc and env['toolchain'] != 'winddk':
207 cppdefines += [
208 'VC_EXTRALEAN',
209 '_USE_MATH_DEFINES',
210 '_CRT_SECURE_NO_WARNINGS',
211 '_CRT_SECURE_NO_DEPRECATE',
212 '_SCL_SECURE_NO_WARNINGS',
213 '_SCL_SECURE_NO_DEPRECATE',
214 ]
215 if env['build'] in ('debug', 'checked'):
216 cppdefines += ['_DEBUG']
217 if env['toolchain'] == 'winddk':
218 # Mimic WINDDK's builtin flags. See also:
219 # - WINDDK's bin/makefile.new i386mk.inc for more info.
220 # - buildchk_wxp_x86.log files, generated by the WINDDK's build
221 # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
222 if machine == 'x86':
223 cppdefines += ['_X86_', 'i386']
224 if machine == 'x86_64':
225 cppdefines += ['_AMD64_', 'AMD64']
226 if platform == 'winddk':
227 cppdefines += [
228 'STD_CALL',
229 ('CONDITION_HANDLING', '1'),
230 ('NT_INST', '0'),
231 ('WIN32', '100'),
232 ('_NT1X_', '100'),
233 ('WINNT', '1'),
234 ('_WIN32_WINNT', '0x0501'), # minimum required OS version
235 ('WINVER', '0x0501'),
236 ('_WIN32_IE', '0x0603'),
237 ('WIN32_LEAN_AND_MEAN', '1'),
238 ('DEVL', '1'),
239 ('__BUILDMACHINE__', 'WinDDK'),
240 ('FPO', '0'),
241 ]
242 if env['build'] in ('debug', 'checked'):
243 cppdefines += [('DBG', 1)]
244 if platform == 'wince':
245 cppdefines += [
246 '_CRT_SECURE_NO_DEPRECATE',
247 '_USE_32BIT_TIME_T',
248 'UNICODE',
249 '_UNICODE',
250 ('UNDER_CE', '600'),
251 ('_WIN32_WCE', '0x600'),
252 'WINCEOEM',
253 'WINCEINTERNAL',
254 'WIN32',
255 'STRICT',
256 'x86',
257 '_X86_',
258 'INTERNATIONAL',
259 ('INTLMSG_CODEPAGE', '1252'),
260 ]
261 if platform == 'windows':
262 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_USER']
263 if platform == 'winddk':
264 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_DISPLAY']
265 if platform == 'wince':
266 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE']
267 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE_OGL']
268 if platform == 'embedded':
269 cppdefines += ['PIPE_OS_EMBEDDED']
270 env.Append(CPPDEFINES = cppdefines)
271
272 # C compiler options
273 cflags = [] # C
274 cxxflags = [] # C++
275 ccflags = [] # C & C++
276 if gcc:
277 ccversion = env['CCVERSION']
278 if env['build'] == 'debug':
279 ccflags += ['-O0']
280 elif ccversion.startswith('4.2.'):
281 # gcc 4.2.x optimizer is broken
282 print "warning: gcc 4.2.x optimizer is broken -- disabling optimizations"
283 ccflags += ['-O0']
284 else:
285 ccflags += ['-O3']
286 ccflags += ['-g3']
287 if env['build'] in ('checked', 'profile'):
288 # See http://code.google.com/p/jrfonseca/wiki/Gprof2Dot#Which_options_should_I_pass_to_gcc_when_compiling_for_profiling?
289 ccflags += [
290 '-fno-omit-frame-pointer',
291 '-fno-optimize-sibling-calls',
292 ]
293 if env['machine'] == 'x86':
294 ccflags += [
295 '-m32',
296 #'-march=pentium4',
297 ]
298 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'):
299 # NOTE: We need to ensure stack is realigned given that we
300 # produce shared objects, and have no control over the stack
301 # alignment policy of the application. Therefore we need
302 # -mstackrealign ore -mincoming-stack-boundary=2.
303 #
304 # XXX: We could have SSE without -mstackrealign if we always used
305 # __attribute__((force_align_arg_pointer)), but that's not
306 # always the case.
307 ccflags += [
308 '-mstackrealign', # ensure stack is aligned
309 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
310 #'-mfpmath=sse',
311 ]
312 if platform in ['windows', 'darwin']:
313 # Workaround http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216
314 ccflags += ['-fno-common']
315 if env['machine'] == 'x86_64':
316 ccflags += ['-m64']
317 if platform == 'darwin':
318 ccflags += ['-fno-common']
319 # See also:
320 # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
321 ccflags += [
322 '-Wall',
323 '-Wno-long-long',
324 '-ffast-math',
325 '-fmessage-length=0', # be nice to Eclipse
326 ]
327 cflags += [
328 '-Wmissing-prototypes',
329 '-std=gnu99',
330 ]
331 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.0'):
332 ccflags += [
333 '-Wmissing-field-initializers',
334 ]
335 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'):
336 ccflags += [
337 '-Werror=pointer-arith',
338 ]
339 cflags += [
340 '-Werror=declaration-after-statement',
341 ]
342 if msvc:
343 # See also:
344 # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
345 # - cl /?
346 if env['build'] == 'debug':
347 ccflags += [
348 '/Od', # disable optimizations
349 '/Oi', # enable intrinsic functions
350 '/Oy-', # disable frame pointer omission
351 '/GL-', # disable whole program optimization
352 ]
353 else:
354 ccflags += [
355 '/O2', # optimize for speed
356 '/GL', # enable whole program optimization
357 ]
358 ccflags += [
359 '/fp:fast', # fast floating point
360 '/W3', # warning level
361 #'/Wp64', # enable 64 bit porting warnings
362 ]
363 if env['machine'] == 'x86':
364 ccflags += [
365 #'/arch:SSE2', # use the SSE2 instructions
366 ]
367 if platform == 'windows':
368 ccflags += [
369 # TODO
370 ]
371 if platform == 'winddk':
372 ccflags += [
373 '/Zl', # omit default library name in .OBJ
374 '/Zp8', # 8bytes struct member alignment
375 '/Gy', # separate functions for linker
376 '/Gm-', # disable minimal rebuild
377 '/WX', # treat warnings as errors
378 '/Gz', # __stdcall Calling convention
379 '/GX-', # disable C++ EH
380 '/GR-', # disable C++ RTTI
381 '/GF', # enable read-only string pooling
382 '/G6', # optimize for PPro, P-II, P-III
383 '/Ze', # enable extensions
384 '/Gi-', # disable incremental compilation
385 '/QIfdiv-', # disable Pentium FDIV fix
386 '/hotpatch', # prepares an image for hotpatching.
387 #'/Z7', #enable old-style debug info
388 ]
389 if platform == 'wince':
390 # See also C:\WINCE600\public\common\oak\misc\makefile.def
391 ccflags += [
392 '/Zl', # omit default library name in .OBJ
393 '/GF', # enable read-only string pooling
394 '/GR-', # disable C++ RTTI
395 '/GS', # enable security checks
396 # Allow disabling language conformance to maintain backward compat
397 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
398 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
399 #'/wd4867',
400 #'/wd4430',
401 #'/MT',
402 #'/U_MT',
403 ]
404 # Automatic pdb generation
405 # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
406 env.EnsureSConsVersion(0, 98, 0)
407 env['PDB'] = '${TARGET.base}.pdb'
408 env.Append(CCFLAGS = ccflags)
409 env.Append(CFLAGS = cflags)
410 env.Append(CXXFLAGS = cxxflags)
411
412 if env['platform'] == 'windows' and msvc:
413 # Choose the appropriate MSVC CRT
414 # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
415 if env['debug']:
416 env.Append(CCFLAGS = ['/MTd'])
417 env.Append(SHCCFLAGS = ['/LDd'])
418 else:
419 env.Append(CCFLAGS = ['/MT'])
420 env.Append(SHCCFLAGS = ['/LD'])
421
422 # Assembler options
423 if gcc:
424 if env['machine'] == 'x86':
425 env.Append(ASFLAGS = ['-m32'])
426 if env['machine'] == 'x86_64':
427 env.Append(ASFLAGS = ['-m64'])
428
429 # Linker options
430 linkflags = []
431 shlinkflags = []
432 if gcc:
433 if env['machine'] == 'x86':
434 linkflags += ['-m32']
435 if env['machine'] == 'x86_64':
436 linkflags += ['-m64']
437 if env['platform'] not in ('darwin'):
438 shlinkflags += [
439 '-Wl,-Bsymbolic',
440 ]
441 # Handle circular dependencies in the libraries
442 if env['platform'] in ('darwin'):
443 pass
444 else:
445 env['_LIBFLAGS'] = '-Wl,--start-group ' + env['_LIBFLAGS'] + ' -Wl,--end-group'
446 if msvc:
447 if not env['debug']:
448 # enable Link-time Code Generation
449 linkflags += ['/LTCG']
450 env.Append(ARFLAGS = ['/LTCG'])
451 if platform == 'windows' and msvc:
452 # See also:
453 # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
454 linkflags += [
455 '/fixed:no',
456 '/incremental:no',
457 ]
458 if platform == 'winddk':
459 linkflags += [
460 '/merge:_PAGE=PAGE',
461 '/merge:_TEXT=.text',
462 '/section:INIT,d',
463 '/opt:ref',
464 '/opt:icf',
465 '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
466 '/incremental:no',
467 '/fullbuild',
468 '/release',
469 '/nodefaultlib',
470 '/wx',
471 '/debug',
472 '/debugtype:cv',
473 '/version:5.1',
474 '/osversion:5.1',
475 '/functionpadmin:5',
476 '/safeseh',
477 '/pdbcompress',
478 '/stack:0x40000,0x1000',
479 '/driver',
480 '/align:0x80',
481 '/subsystem:native,5.01',
482 '/base:0x10000',
483
484 '/entry:DrvEnableDriver',
485 ]
486 if env['build'] != 'release':
487 linkflags += [
488 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
489 ]
490 if platform == 'wince':
491 linkflags += [
492 '/nodefaultlib',
493 #'/incremental:no',
494 #'/fullbuild',
495 '/entry:_DllMainCRTStartup',
496 ]
497 env.Append(LINKFLAGS = linkflags)
498 env.Append(SHLINKFLAGS = shlinkflags)
499
500 # Default libs
501 env.Append(LIBS = [])
502
503 # Load LLVM
504 if env['llvm']:
505 env.Tool('llvm')
506
507 # Custom builders and methods
508 env.Tool('custom')
509 createInstallMethods(env)
510
511 # for debugging
512 #print env.Dump()
513
514
515 def exists(env):
516 return 1