322b23b2b00f4637d2972537f32fc299d479fa4c
[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 and (platform != 'windows' or env['build'] == 'debug' or True):
354 # NOTE: We need to ensure stack is realigned given that we
355 # produce shared objects, and have no control over the stack
356 # alignment policy of the application. Therefore we need
357 # -mstackrealign ore -mincoming-stack-boundary=2.
358 #
359 # XXX: -O and -mstackrealign causes stack corruption on MinGW
360 #
361 # XXX: We could have SSE without -mstackrealign if we always used
362 # __attribute__((force_align_arg_pointer)), but that's not
363 # always the case.
364 ccflags += [
365 '-mstackrealign', # ensure stack is aligned
366 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
367 #'-mfpmath=sse',
368 ]
369 if platform in ['windows', 'darwin']:
370 # Workaround http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216
371 ccflags += ['-fno-common']
372 if env['machine'] == 'x86_64':
373 ccflags += ['-m64']
374 if platform == 'darwin':
375 ccflags += ['-fno-common']
376 # See also:
377 # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
378 ccflags += [
379 '-Wall',
380 '-Wno-long-long',
381 '-ffast-math',
382 '-fmessage-length=0', # be nice to Eclipse
383 ]
384 cflags += [
385 '-Wmissing-prototypes',
386 '-std=gnu99',
387 ]
388 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.0'):
389 ccflags += [
390 '-Wmissing-field-initializers',
391 ]
392 if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'):
393 ccflags += [
394 '-Werror=pointer-arith',
395 ]
396 cflags += [
397 '-Werror=declaration-after-statement',
398 ]
399 if msvc:
400 # See also:
401 # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
402 # - cl /?
403 if env['build'] == 'debug':
404 ccflags += [
405 '/Od', # disable optimizations
406 '/Oi', # enable intrinsic functions
407 '/Oy-', # disable frame pointer omission
408 ]
409 else:
410 ccflags += [
411 '/O2', # optimize for speed
412 ]
413 if env['build'] == 'release':
414 ccflags += [
415 '/GL', # enable whole program optimization
416 ]
417 else:
418 ccflags += [
419 '/GL-', # disable whole program optimization
420 ]
421 ccflags += [
422 '/fp:fast', # fast floating point
423 '/W3', # warning level
424 #'/Wp64', # enable 64 bit porting warnings
425 ]
426 if env['machine'] == 'x86':
427 ccflags += [
428 #'/arch:SSE2', # use the SSE2 instructions
429 ]
430 if platform == 'windows':
431 ccflags += [
432 # TODO
433 ]
434 if platform == 'winddk':
435 ccflags += [
436 '/Zl', # omit default library name in .OBJ
437 '/Zp8', # 8bytes struct member alignment
438 '/Gy', # separate functions for linker
439 '/Gm-', # disable minimal rebuild
440 '/WX', # treat warnings as errors
441 '/Gz', # __stdcall Calling convention
442 '/GX-', # disable C++ EH
443 '/GR-', # disable C++ RTTI
444 '/GF', # enable read-only string pooling
445 '/G6', # optimize for PPro, P-II, P-III
446 '/Ze', # enable extensions
447 '/Gi-', # disable incremental compilation
448 '/QIfdiv-', # disable Pentium FDIV fix
449 '/hotpatch', # prepares an image for hotpatching.
450 #'/Z7', #enable old-style debug info
451 ]
452 if platform == 'wince':
453 # See also C:\WINCE600\public\common\oak\misc\makefile.def
454 ccflags += [
455 '/Zl', # omit default library name in .OBJ
456 '/GF', # enable read-only string pooling
457 '/GR-', # disable C++ RTTI
458 '/GS', # enable security checks
459 # Allow disabling language conformance to maintain backward compat
460 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
461 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
462 #'/wd4867',
463 #'/wd4430',
464 #'/MT',
465 #'/U_MT',
466 ]
467 # Automatic pdb generation
468 # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
469 env.EnsureSConsVersion(0, 98, 0)
470 env['PDB'] = '${TARGET.base}.pdb'
471 env.Append(CCFLAGS = ccflags)
472 env.Append(CFLAGS = cflags)
473 env.Append(CXXFLAGS = cxxflags)
474
475 if env['platform'] == 'windows' and msvc:
476 # Choose the appropriate MSVC CRT
477 # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
478 if env['build'] in ('debug', 'checked'):
479 env.Append(CCFLAGS = ['/MTd'])
480 env.Append(SHCCFLAGS = ['/LDd'])
481 else:
482 env.Append(CCFLAGS = ['/MT'])
483 env.Append(SHCCFLAGS = ['/LD'])
484
485 # Assembler options
486 if gcc:
487 if env['machine'] == 'x86':
488 env.Append(ASFLAGS = ['-m32'])
489 if env['machine'] == 'x86_64':
490 env.Append(ASFLAGS = ['-m64'])
491
492 # Linker options
493 linkflags = []
494 shlinkflags = []
495 if gcc:
496 if env['machine'] == 'x86':
497 linkflags += ['-m32']
498 if env['machine'] == 'x86_64':
499 linkflags += ['-m64']
500 if env['platform'] not in ('darwin'):
501 shlinkflags += [
502 '-Wl,-Bsymbolic',
503 ]
504 # Handle circular dependencies in the libraries
505 if env['platform'] in ('darwin'):
506 pass
507 else:
508 env['_LIBFLAGS'] = '-Wl,--start-group ' + env['_LIBFLAGS'] + ' -Wl,--end-group'
509 if msvc:
510 if env['build'] == 'release':
511 # enable Link-time Code Generation
512 linkflags += ['/LTCG']
513 env.Append(ARFLAGS = ['/LTCG'])
514 if platform == 'windows' and msvc:
515 # See also:
516 # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
517 linkflags += [
518 '/fixed:no',
519 '/incremental:no',
520 ]
521 if platform == 'winddk':
522 linkflags += [
523 '/merge:_PAGE=PAGE',
524 '/merge:_TEXT=.text',
525 '/section:INIT,d',
526 '/opt:ref',
527 '/opt:icf',
528 '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
529 '/incremental:no',
530 '/fullbuild',
531 '/release',
532 '/nodefaultlib',
533 '/wx',
534 '/debug',
535 '/debugtype:cv',
536 '/version:5.1',
537 '/osversion:5.1',
538 '/functionpadmin:5',
539 '/safeseh',
540 '/pdbcompress',
541 '/stack:0x40000,0x1000',
542 '/driver',
543 '/align:0x80',
544 '/subsystem:native,5.01',
545 '/base:0x10000',
546
547 '/entry:DrvEnableDriver',
548 ]
549 if env['build'] != 'release':
550 linkflags += [
551 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
552 ]
553 if platform == 'wince':
554 linkflags += [
555 '/nodefaultlib',
556 #'/incremental:no',
557 #'/fullbuild',
558 '/entry:_DllMainCRTStartup',
559 ]
560 env.Append(LINKFLAGS = linkflags)
561 env.Append(SHLINKFLAGS = shlinkflags)
562
563 # We have C++ in several libraries, so always link with the C++ compiler
564 if env['gcc']:
565 env['LINK'] = env['CXX']
566
567 # Default libs
568 env.Append(LIBS = [])
569
570 # Load tools
571 if env['llvm']:
572 env.Tool('llvm')
573 env.Tool('udis86')
574
575 pkg_config_modules(env, 'x11', ['x11', 'xext'])
576 pkg_config_modules(env, 'drm', ['libdrm'])
577 pkg_config_modules(env, 'drm_intel', ['libdrm_intel'])
578 pkg_config_modules(env, 'drm_radeon', ['libdrm_radeon'])
579 pkg_config_modules(env, 'xorg', ['xorg-server'])
580 pkg_config_modules(env, 'kms', ['libkms'])
581
582 env['dri'] = env['x11'] and env['drm']
583
584 # Custom builders and methods
585 env.Tool('custom')
586 createInstallMethods(env)
587
588 # for debugging
589 #print env.Dump()
590
591
592 def exists(env):
593 return 1