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