Merge branch 'lp-offset-twoside'
[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 return env.Install(target_dir, source)
54
55 def install_program(env, source):
56 return install(env, source, 'bin')
57
58 def install_shared_library(env, sources, version = ()):
59 targets = []
60 install_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build_dir'])
61 version = tuple(map(str, version))
62 if env['SHLIBSUFFIX'] == '.dll':
63 dlls = env.FindIxes(sources, 'SHLIBPREFIX', 'SHLIBSUFFIX')
64 targets += install(env, dlls, 'bin')
65 libs = env.FindIxes(sources, 'LIBPREFIX', 'LIBSUFFIX')
66 targets += install(env, libs, 'lib')
67 else:
68 for source in sources:
69 target_dir = os.path.join(install_dir, 'lib')
70 target_name = '.'.join((str(source),) + version)
71 last = env.InstallAs(os.path.join(target_dir, target_name), source)
72 targets += last
73 while len(version):
74 version = version[:-1]
75 target_name = '.'.join((str(source),) + version)
76 action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE")
77 last = env.Command(os.path.join(target_dir, target_name), last, action)
78 targets += last
79 return targets
80
81
82 def createInstallMethods(env):
83 env.AddMethod(install_program, 'InstallProgram')
84 env.AddMethod(install_shared_library, 'InstallSharedLibrary')
85
86
87 def num_jobs():
88 try:
89 return int(os.environ['NUMBER_OF_PROCESSORS'])
90 except (ValueError, KeyError):
91 pass
92
93 try:
94 return os.sysconf('SC_NPROCESSORS_ONLN')
95 except (ValueError, OSError, AttributeError):
96 pass
97
98 try:
99 return int(os.popen2("sysctl -n hw.ncpu")[1].read())
100 except ValueError:
101 pass
102
103 return 1
104
105
106 def pkg_config_modules(env, name, modules):
107 '''Simple wrapper for pkg-config.'''
108
109 env[name] = False
110
111 if env['platform'] == 'windows':
112 return
113
114 if not env.Detect('pkg-config'):
115 return
116
117 if subprocess.call(["pkg-config", "--exists", ' '.join(modules)]) != 0:
118 return
119
120 # Put -I and -L flags directly into the environment, as these don't affect
121 # the compilation of targets that do not use them
122 try:
123 env.ParseConfig('pkg-config --cflags-only-I --libs-only-L ' + ' '.join(modules))
124 except OSError:
125 return
126
127 # Other flags may affect the compilation of unrelated targets, so store
128 # them with a prefix, (e.g., XXX_CFLAGS, XXX_LIBS, etc)
129 try:
130 flags = env.ParseFlags('!pkg-config --cflags-only-other --libs-only-l --libs-only-other ' + ' '.join(modules))
131 except OSError:
132 return
133 prefix = name.upper() + '_'
134 for flag_name, flag_value in flags.iteritems():
135 env[prefix + flag_name] = flag_value
136
137 env[name] = True
138
139
140
141 def generate(env):
142 """Common environment generation code"""
143
144 # Toolchain
145 platform = env['platform']
146 if env['toolchain'] == 'default':
147 if platform == 'winddk':
148 env['toolchain'] = 'winddk'
149 elif platform == 'wince':
150 env['toolchain'] = 'wcesdk'
151 env.Tool(env['toolchain'])
152
153 # Allow override compiler and specify additional flags from environment
154 if os.environ.has_key('CC'):
155 env['CC'] = os.environ['CC']
156 # Update CCVERSION to match
157 pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
158 stdin = 'devnull',
159 stderr = 'devnull',
160 stdout = subprocess.PIPE)
161 if pipe.wait() == 0:
162 line = pipe.stdout.readline()
163 match = re.search(r'[0-9]+(\.[0-9]+)+', line)
164 if match:
165 env['CCVERSION'] = match.group(0)
166 if os.environ.has_key('CFLAGS'):
167 env['CCFLAGS'] += SCons.Util.CLVar(os.environ['CFLAGS'])
168 if os.environ.has_key('CXX'):
169 env['CXX'] = os.environ['CXX']
170 if os.environ.has_key('CXXFLAGS'):
171 env['CXXFLAGS'] += SCons.Util.CLVar(os.environ['CXXFLAGS'])
172 if os.environ.has_key('LDFLAGS'):
173 env['LINKFLAGS'] += SCons.Util.CLVar(os.environ['LDFLAGS'])
174
175 env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-')
176 env['msvc'] = env['CC'] == 'cl'
177
178 # shortcuts
179 machine = env['machine']
180 platform = env['platform']
181 x86 = env['machine'] == 'x86'
182 ppc = env['machine'] == 'ppc'
183 gcc = env['gcc']
184 msvc = env['msvc']
185
186 # Backwards compatability with the debug= profile= options
187 if env['build'] == 'debug':
188 if not env['debug']:
189 print 'scons: warning: debug option is deprecated and will be removed eventually; use instead'
190 print
191 print ' scons build=release'
192 print
193 env['build'] = 'release'
194 if env['profile']:
195 print 'scons: warning: profile option is deprecated and will be removed eventually; use instead'
196 print
197 print ' scons build=profile'
198 print
199 env['build'] = 'profile'
200 if False:
201 # Enforce SConscripts to use the new build variable
202 env.popitem('debug')
203 env.popitem('profile')
204 else:
205 # Backwards portability with older sconscripts
206 if env['build'] in ('debug', 'checked'):
207 env['debug'] = True
208 env['profile'] = False
209 if env['build'] == 'profile':
210 env['debug'] = False
211 env['profile'] = True
212 if env['build'] == 'release':
213 env['debug'] = False
214 env['profile'] = False
215
216 # Put build output in a separate dir, which depends on the current
217 # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
218 build_topdir = 'build'
219 build_subdir = env['platform']
220 if env['machine'] != 'generic':
221 build_subdir += '-' + env['machine']
222 if env['build'] != 'release':
223 build_subdir += '-' + env['build']
224 build_dir = os.path.join(build_topdir, build_subdir)
225 # Place the .sconsign file in the build dir too, to avoid issues with
226 # different scons versions building the same source file
227 env['build_dir'] = build_dir
228 env.SConsignFile(os.path.join(build_dir, '.sconsign'))
229 if 'SCONS_CACHE_DIR' in os.environ:
230 print 'scons: Using build cache in %s.' % (os.environ['SCONS_CACHE_DIR'],)
231 env.CacheDir(os.environ['SCONS_CACHE_DIR'])
232 env['CONFIGUREDIR'] = os.path.join(build_dir, 'conf')
233 env['CONFIGURELOG'] = os.path.join(os.path.abspath(build_dir), 'config.log')
234
235 # Parallel build
236 if env.GetOption('num_jobs') <= 1:
237 env.SetOption('num_jobs', num_jobs())
238
239 env.Decider('MD5-timestamp')
240 env.SetOption('max_drift', 60)
241
242 # C preprocessor options
243 cppdefines = []
244 if env['build'] in ('debug', 'checked'):
245 cppdefines += ['DEBUG']
246 else:
247 cppdefines += ['NDEBUG']
248 if env['build'] == 'profile':
249 cppdefines += ['PROFILE']
250 if platform == 'windows':
251 cppdefines += [
252 'WIN32',
253 '_WINDOWS',
254 #'_UNICODE',
255 #'UNICODE',
256 # http://msdn.microsoft.com/en-us/library/aa383745.aspx
257 ('_WIN32_WINNT', '0x0601'),
258 ('WINVER', '0x0601'),
259 ]
260 if msvc and env['toolchain'] != 'winddk':
261 cppdefines += [
262 'VC_EXTRALEAN',
263 '_USE_MATH_DEFINES',
264 '_CRT_SECURE_NO_WARNINGS',
265 '_CRT_SECURE_NO_DEPRECATE',
266 '_SCL_SECURE_NO_WARNINGS',
267 '_SCL_SECURE_NO_DEPRECATE',
268 ]
269 if env['build'] in ('debug', 'checked'):
270 cppdefines += ['_DEBUG']
271 if env['toolchain'] == 'winddk':
272 # Mimic WINDDK's builtin flags. See also:
273 # - WINDDK's bin/makefile.new i386mk.inc for more info.
274 # - buildchk_wxp_x86.log files, generated by the WINDDK's build
275 # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
276 if machine == 'x86':
277 cppdefines += ['_X86_', 'i386']
278 if machine == 'x86_64':
279 cppdefines += ['_AMD64_', 'AMD64']
280 if platform == 'winddk':
281 cppdefines += [
282 'STD_CALL',
283 ('CONDITION_HANDLING', '1'),
284 ('NT_INST', '0'),
285 ('WIN32', '100'),
286 ('_NT1X_', '100'),
287 ('WINNT', '1'),
288 ('_WIN32_WINNT', '0x0501'), # minimum required OS version
289 ('WINVER', '0x0501'),
290 ('_WIN32_IE', '0x0603'),
291 ('WIN32_LEAN_AND_MEAN', '1'),
292 ('DEVL', '1'),
293 ('__BUILDMACHINE__', 'WinDDK'),
294 ('FPO', '0'),
295 ]
296 if env['build'] in ('debug', 'checked'):
297 cppdefines += [('DBG', 1)]
298 if platform == 'wince':
299 cppdefines += [
300 '_CRT_SECURE_NO_DEPRECATE',
301 '_USE_32BIT_TIME_T',
302 'UNICODE',
303 '_UNICODE',
304 ('UNDER_CE', '600'),
305 ('_WIN32_WCE', '0x600'),
306 'WINCEOEM',
307 'WINCEINTERNAL',
308 'WIN32',
309 'STRICT',
310 'x86',
311 '_X86_',
312 'INTERNATIONAL',
313 ('INTLMSG_CODEPAGE', '1252'),
314 ]
315 if platform == 'windows':
316 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_USER']
317 if platform == 'winddk':
318 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_DISPLAY']
319 if platform == 'wince':
320 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE']
321 cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_CE_OGL']
322 if platform == 'embedded':
323 cppdefines += ['PIPE_OS_EMBEDDED']
324 env.Append(CPPDEFINES = cppdefines)
325
326 # C compiler options
327 cflags = [] # C
328 cxxflags = [] # C++
329 ccflags = [] # C & C++
330 if gcc:
331 ccversion = env['CCVERSION']
332 if env['build'] == 'debug':
333 ccflags += ['-O0']
334 elif ccversion.startswith('4.2.'):
335 # gcc 4.2.x optimizer is broken
336 print "warning: gcc 4.2.x optimizer is broken -- disabling optimizations"
337 ccflags += ['-O0']
338 else:
339 ccflags += ['-O3']
340 ccflags += ['-g3']
341 if env['build'] in ('checked', 'profile'):
342 # See http://code.google.com/p/jrfonseca/wiki/Gprof2Dot#Which_options_should_I_pass_to_gcc_when_compiling_for_profiling?
343 ccflags += [
344 '-fno-omit-frame-pointer',
345 '-fno-optimize-sibling-calls',
346 ]
347 if env['machine'] == 'x86':
348 ccflags += [
349 '-m32',
350 #'-march=pentium4',
351 ]
352 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'):
353 # NOTE: We need to ensure stack is realigned given that we
354 # produce shared objects, and have no control over the stack
355 # alignment policy of the application. Therefore we need
356 # -mstackrealign ore -mincoming-stack-boundary=2.
357 #
358 # XXX: We could have SSE without -mstackrealign if we always used
359 # __attribute__((force_align_arg_pointer)), but that's not
360 # always the case.
361 ccflags += [
362 '-mstackrealign', # ensure stack is aligned
363 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
364 #'-mfpmath=sse',
365 ]
366 if platform in ['windows', 'darwin']:
367 # Workaround http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216
368 ccflags += ['-fno-common']
369 if env['machine'] == 'x86_64':
370 ccflags += ['-m64']
371 if platform == 'darwin':
372 ccflags += ['-fno-common']
373 # See also:
374 # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
375 ccflags += [
376 '-Wall',
377 '-Wno-long-long',
378 '-ffast-math',
379 '-fmessage-length=0', # be nice to Eclipse
380 ]
381 cflags += [
382 '-Wmissing-prototypes',
383 '-std=gnu99',
384 ]
385 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.0'):
386 ccflags += [
387 '-Wmissing-field-initializers',
388 ]
389 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'):
390 ccflags += [
391 '-Werror=pointer-arith',
392 ]
393 cflags += [
394 '-Werror=declaration-after-statement',
395 ]
396 if msvc:
397 # See also:
398 # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
399 # - cl /?
400 if env['build'] == 'debug':
401 ccflags += [
402 '/Od', # disable optimizations
403 '/Oi', # enable intrinsic functions
404 '/Oy-', # disable frame pointer omission
405 '/GL-', # disable whole program optimization
406 ]
407 else:
408 ccflags += [
409 '/O2', # optimize for speed
410 '/GL', # enable whole program optimization
411 ]
412 ccflags += [
413 '/fp:fast', # fast floating point
414 '/W3', # warning level
415 #'/Wp64', # enable 64 bit porting warnings
416 ]
417 if env['machine'] == 'x86':
418 ccflags += [
419 #'/arch:SSE2', # use the SSE2 instructions
420 ]
421 if platform == 'windows':
422 ccflags += [
423 # TODO
424 ]
425 if platform == 'winddk':
426 ccflags += [
427 '/Zl', # omit default library name in .OBJ
428 '/Zp8', # 8bytes struct member alignment
429 '/Gy', # separate functions for linker
430 '/Gm-', # disable minimal rebuild
431 '/WX', # treat warnings as errors
432 '/Gz', # __stdcall Calling convention
433 '/GX-', # disable C++ EH
434 '/GR-', # disable C++ RTTI
435 '/GF', # enable read-only string pooling
436 '/G6', # optimize for PPro, P-II, P-III
437 '/Ze', # enable extensions
438 '/Gi-', # disable incremental compilation
439 '/QIfdiv-', # disable Pentium FDIV fix
440 '/hotpatch', # prepares an image for hotpatching.
441 #'/Z7', #enable old-style debug info
442 ]
443 if platform == 'wince':
444 # See also C:\WINCE600\public\common\oak\misc\makefile.def
445 ccflags += [
446 '/Zl', # omit default library name in .OBJ
447 '/GF', # enable read-only string pooling
448 '/GR-', # disable C++ RTTI
449 '/GS', # enable security checks
450 # Allow disabling language conformance to maintain backward compat
451 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
452 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
453 #'/wd4867',
454 #'/wd4430',
455 #'/MT',
456 #'/U_MT',
457 ]
458 # Automatic pdb generation
459 # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
460 env.EnsureSConsVersion(0, 98, 0)
461 env['PDB'] = '${TARGET.base}.pdb'
462 env.Append(CCFLAGS = ccflags)
463 env.Append(CFLAGS = cflags)
464 env.Append(CXXFLAGS = cxxflags)
465
466 if env['platform'] == 'windows' and msvc:
467 # Choose the appropriate MSVC CRT
468 # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
469 if env['build'] in ('debug', 'checked'):
470 env.Append(CCFLAGS = ['/MTd'])
471 env.Append(SHCCFLAGS = ['/LDd'])
472 else:
473 env.Append(CCFLAGS = ['/MT'])
474 env.Append(SHCCFLAGS = ['/LD'])
475
476 # Assembler options
477 if gcc:
478 if env['machine'] == 'x86':
479 env.Append(ASFLAGS = ['-m32'])
480 if env['machine'] == 'x86_64':
481 env.Append(ASFLAGS = ['-m64'])
482
483 # Linker options
484 linkflags = []
485 shlinkflags = []
486 if gcc:
487 if env['machine'] == 'x86':
488 linkflags += ['-m32']
489 if env['machine'] == 'x86_64':
490 linkflags += ['-m64']
491 if env['platform'] not in ('darwin'):
492 shlinkflags += [
493 '-Wl,-Bsymbolic',
494 ]
495 # Handle circular dependencies in the libraries
496 if env['platform'] in ('darwin'):
497 pass
498 else:
499 env['_LIBFLAGS'] = '-Wl,--start-group ' + env['_LIBFLAGS'] + ' -Wl,--end-group'
500 if msvc:
501 if env['build'] != 'debug':
502 # enable Link-time Code Generation
503 linkflags += ['/LTCG']
504 env.Append(ARFLAGS = ['/LTCG'])
505 if platform == 'windows' and msvc:
506 # See also:
507 # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
508 linkflags += [
509 '/fixed:no',
510 '/incremental:no',
511 ]
512 if platform == 'winddk':
513 linkflags += [
514 '/merge:_PAGE=PAGE',
515 '/merge:_TEXT=.text',
516 '/section:INIT,d',
517 '/opt:ref',
518 '/opt:icf',
519 '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
520 '/incremental:no',
521 '/fullbuild',
522 '/release',
523 '/nodefaultlib',
524 '/wx',
525 '/debug',
526 '/debugtype:cv',
527 '/version:5.1',
528 '/osversion:5.1',
529 '/functionpadmin:5',
530 '/safeseh',
531 '/pdbcompress',
532 '/stack:0x40000,0x1000',
533 '/driver',
534 '/align:0x80',
535 '/subsystem:native,5.01',
536 '/base:0x10000',
537
538 '/entry:DrvEnableDriver',
539 ]
540 if env['build'] != 'release':
541 linkflags += [
542 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
543 ]
544 if platform == 'wince':
545 linkflags += [
546 '/nodefaultlib',
547 #'/incremental:no',
548 #'/fullbuild',
549 '/entry:_DllMainCRTStartup',
550 ]
551 env.Append(LINKFLAGS = linkflags)
552 env.Append(SHLINKFLAGS = shlinkflags)
553
554 # Default libs
555 env.Append(LIBS = [])
556
557 # Load tools
558 if env['llvm']:
559 env.Tool('llvm')
560 env.Tool('udis86')
561
562 pkg_config_modules(env, 'x11', ['x11', 'xext'])
563 pkg_config_modules(env, 'drm', ['libdrm'])
564 pkg_config_modules(env, 'drm_intel', ['libdrm_intel'])
565 pkg_config_modules(env, 'drm_radeon', ['libdrm_radeon'])
566 pkg_config_modules(env, 'xorg', ['xorg-server'])
567 pkg_config_modules(env, 'kms', ['libkms'])
568
569 env['dri'] = env['x11'] and env['drm']
570
571 # Custom builders and methods
572 env.Tool('custom')
573 createInstallMethods(env)
574
575 # for debugging
576 #print env.Dump()
577
578
579 def exists(env):
580 return 1