radeon: drop assert accessing cref which is meant to be hidden
[mesa.git] / scons / generic.py
1 """generic
2
3 Generic tool that provides a commmon ground for all platforms.
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 os
34 import os.path
35 import re
36 import platform as _platform
37 import sys
38
39 import SCons.Action
40 import SCons.Builder
41 import SCons.Scanner
42
43
44 def quietCommandLines(env):
45 # Quiet command lines
46 # See also http://www.scons.org/wiki/HidingCommandLinesInOutput
47 env['CCCOMSTR'] = "Compiling $SOURCE ..."
48 env['CXXCOMSTR'] = "Compiling $SOURCE ..."
49 env['ARCOMSTR'] = "Archiving $TARGET ..."
50 env['RANLIBCOMSTR'] = ""
51 env['LINKCOMSTR'] = "Linking $TARGET ..."
52
53
54 def createConvenienceLibBuilder(env):
55 """This is a utility function that creates the ConvenienceLibrary
56 Builder in an Environment if it is not there already.
57
58 If it is already there, we return the existing one.
59
60 Based on the stock StaticLibrary and SharedLibrary builders.
61 """
62
63 try:
64 convenience_lib = env['BUILDERS']['ConvenienceLibrary']
65 except KeyError:
66 action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ]
67 if env.Detect('ranlib'):
68 ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR")
69 action_list.append(ranlib_action)
70
71 convenience_lib = SCons.Builder.Builder(action = action_list,
72 emitter = '$LIBEMITTER',
73 prefix = '$LIBPREFIX',
74 suffix = '$LIBSUFFIX',
75 src_suffix = '$SHOBJSUFFIX',
76 src_builder = 'SharedObject')
77 env['BUILDERS']['ConvenienceLibrary'] = convenience_lib
78
79 return convenience_lib
80
81
82 # TODO: handle import statements with multiple modules
83 # TODO: handle from import statements
84 import_re = re.compile(r'^import\s+(\S+)$', re.M)
85
86 def python_scan(node, env, path):
87 # http://www.scons.org/doc/0.98.5/HTML/scons-user/c2781.html#AEN2789
88 contents = node.get_contents()
89 source_dir = node.get_dir()
90 imports = import_re.findall(contents)
91 results = []
92 for imp in imports:
93 for dir in path:
94 file = os.path.join(str(dir), imp.replace('.', os.sep) + '.py')
95 if os.path.exists(file):
96 results.append(env.File(file))
97 break
98 file = os.path.join(str(dir), imp.replace('.', os.sep), '__init__.py')
99 if os.path.exists(file):
100 results.append(env.File(file))
101 break
102 return results
103
104 python_scanner = SCons.Scanner.Scanner(function = python_scan, skeys = ['.py'])
105
106
107 def code_generate(env, script, target, source, command):
108 """Method to simplify code generation via python scripts.
109
110 http://www.scons.org/wiki/UsingCodeGenerators
111 http://www.scons.org/doc/0.98.5/HTML/scons-user/c2768.html
112 """
113
114 # We're generating code using Python scripts, so we have to be
115 # careful with our scons elements. This entry represents
116 # the generator file *in the source directory*.
117 script_src = env.File(script).srcnode()
118
119 # This command creates generated code *in the build directory*.
120 command = command.replace('$SCRIPT', script_src.path)
121 code = env.Command(target, source, command)
122
123 # Explicitly mark that the generated code depends on the generator,
124 # and on implicitly imported python modules
125 path = (script_src.get_dir(),)
126 deps = [script_src]
127 deps += script_src.get_implicit_deps(env, python_scanner, path)
128 env.Depends(code, deps)
129
130 # Running the Python script causes .pyc files to be generated in the
131 # source directory. When we clean up, they should go too. So add side
132 # effects for .pyc files
133 for dep in deps:
134 pyc = env.File(str(dep) + 'c')
135 env.SideEffect(pyc, code)
136
137 return code
138
139
140 def createCodeGenerateMethod(env):
141 env.Append(SCANNERS = python_scanner)
142 env.AddMethod(code_generate, 'CodeGenerate')
143
144
145 def symlink(target, source, env):
146 target = str(target[0])
147 source = str(source[0])
148 if os.path.islink(target) or os.path.exists(target):
149 os.remove(target)
150 os.symlink(os.path.basename(source), target)
151
152 def install_shared_library(env, source, version = ()):
153 source = str(source[0])
154 version = tuple(map(str, version))
155 target_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build'], 'lib')
156 target_name = '.'.join((str(source),) + version)
157 last = env.InstallAs(os.path.join(target_dir, target_name), source)
158 while len(version):
159 version = version[:-1]
160 target_name = '.'.join((str(source),) + version)
161 action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE")
162 last = env.Command(os.path.join(target_dir, target_name), last, action)
163
164 def createInstallMethods(env):
165 env.AddMethod(install_shared_library, 'InstallSharedLibrary')
166
167
168 _platform_map = {
169 'linux2': 'linux',
170 'win32': 'windows',
171 }
172
173
174 _machine_map = {
175 'x86': 'x86',
176 'i386': 'x86',
177 'i486': 'x86',
178 'i586': 'x86',
179 'i686': 'x86',
180 'ppc': 'ppc',
181 'x86_64': 'x86_64',
182 }
183
184
185 _toolchain_map = {
186 'winddk': 'winddk',
187 'wince': 'wcesdk',
188 }
189
190
191 _bool_map = {
192 'y': 1,
193 'yes': 1,
194 't': 1,
195 'true': 1,
196 '1': 1,
197 'on': 1,
198 'all': 1,
199 'n': 0,
200 'no': 0,
201 'f': 0,
202 'false': 0,
203 '0': 0,
204 'off': 0,
205 'none': 0,
206 }
207
208
209 def num_jobs():
210 try:
211 return int(os.environ['NUMBER_OF_PROCESSORS'])
212 except (ValueError, KeyError):
213 pass
214
215 try:
216 return os.sysconf('SC_NPROCESSORS_ONLN')
217 except (ValueError, OSError, AttributeError):
218 pass
219
220 try:
221 return int(os.popen2("sysctl -n hw.ncpu")[1].read())
222 except ValueError:
223 pass
224
225 return 1
226
227
228 def generate(env):
229 """Common environment generation code"""
230
231 from SCons.Script import ARGUMENTS
232
233 # FIXME: this is already too late
234 #if env.get('quiet', False):
235 # quietCommandLines(env)
236
237
238 # Platform
239 try:
240 env['platform'] = ARGUMENTS['platform']
241 except KeyError:
242 env['platform'] = _platform_map.get(sys.platform, sys.platform)
243
244 # Machine
245 try:
246 env['machine'] = ARGUMENTS['machine']
247 except KeyError:
248 env['machine'] = _machine_map.get(os.environ.get('PROCESSOR_ARCHITECTURE', _platform.machine()), 'generic')
249
250 # Toolchain
251 try:
252 env['toolchain'] = ARGUMENTS['toolchain']
253 except KeyError:
254 if env['platform'] in ('windows', 'winddk', 'wince') and sys.platform != 'win32':
255 env['toolchain'] = 'crossmingw'
256 else:
257 env['toolchain'] = _toolchain_map.get(env['platform'], 'default')
258 if env['toolchain'] == 'crossmingw' and env['machine'] not in ('generic', 'x86'):
259 env['machine'] = 'x86'
260
261 try:
262 env['MSVS_VERSION'] = ARGUMENTS['MSVS_VERSION']
263 except KeyError:
264 pass
265
266 # Build type
267 env['debug'] = _bool_map[ARGUMENTS.get('debug', 'no')]
268 env['profile'] = _bool_map[ARGUMENTS.get('profile', 'no')]
269
270 # Put build output in a separate dir, which depends on the current
271 # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
272 try:
273 env['build'] = ARGUMENTS['build']
274 except KeyError:
275 build_topdir = 'build'
276 build_subdir = env['platform']
277 if env['machine'] != 'generic':
278 build_subdir += '-' + env['machine']
279 if env['debug']:
280 build_subdir += "-debug"
281 if env['profile']:
282 build_subdir += "-profile"
283 env['build'] = os.path.join(build_topdir, build_subdir)
284 # Place the .sconsign file in the build dir too, to avoid issues with
285 # different scons versions building the same source file
286 env.SConsignFile(os.path.join(env['build'], '.sconsign'))
287
288 # Parallel build
289 if env.GetOption('num_jobs') <= 1:
290 env.SetOption('num_jobs', num_jobs())
291
292 # Summary
293 print
294 print ' platform=%s' % env['platform']
295 print ' machine=%s' % env['machine']
296 print ' toolchain=%s' % env['toolchain']
297 print ' debug=%s' % ['no', 'yes'][env['debug']]
298 print ' profile=%s' % ['no', 'yes'][env['profile']]
299 print ' build=%s' % env['build']
300 print ' %s jobs' % env.GetOption('num_jobs')
301 print
302
303 # Load tool chain
304 env.Tool(env['toolchain'])
305
306 env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-')
307 env['msvc'] = env['CC'] == 'cl'
308
309 # shortcuts
310 debug = env['debug']
311 machine = env['machine']
312 platform = env['platform']
313 x86 = env['machine'] == 'x86'
314 ppc = env['machine'] == 'ppc'
315 gcc = env['gcc']
316 msvc = env['msvc']
317
318 # C preprocessor options
319 cppdefines = []
320 if debug:
321 cppdefines += ['DEBUG']
322 else:
323 cppdefines += ['NDEBUG']
324 if env['profile']:
325 cppdefines += ['PROFILE']
326 if platform == 'windows':
327 cppdefines += [
328 'WIN32',
329 '_WINDOWS',
330 #'_UNICODE',
331 #'UNICODE',
332 # http://msdn2.microsoft.com/en-us/library/6dwk3a1z.aspx,
333 #'WIN32_LEAN_AND_MEAN',
334 ]
335 if msvc:
336 cppdefines += [
337 'VC_EXTRALEAN',
338 '_CRT_SECURE_NO_DEPRECATE',
339 ]
340 if debug:
341 cppdefines += ['_DEBUG']
342 if platform == 'winddk':
343 # Mimic WINDDK's builtin flags. See also:
344 # - WINDDK's bin/makefile.new i386mk.inc for more info.
345 # - buildchk_wxp_x86.log files, generated by the WINDDK's build
346 # - http://alter.org.ua/docs/nt_kernel/vc8_proj/
347 cppdefines += [
348 ('_X86_', '1'),
349 ('i386', '1'),
350 'STD_CALL',
351 ('CONDITION_HANDLING', '1'),
352 ('NT_INST', '0'),
353 ('WIN32', '100'),
354 ('_NT1X_', '100'),
355 ('WINNT', '1'),
356 ('_WIN32_WINNT', '0x0501'), # minimum required OS version
357 ('WINVER', '0x0501'),
358 ('_WIN32_IE', '0x0603'),
359 ('WIN32_LEAN_AND_MEAN', '1'),
360 ('DEVL', '1'),
361 ('__BUILDMACHINE__', 'WinDDK'),
362 ('FPO', '0'),
363 ]
364 if debug:
365 cppdefines += [('DBG', 1)]
366 if platform == 'wince':
367 cppdefines += [
368 '_CRT_SECURE_NO_DEPRECATE',
369 '_USE_32BIT_TIME_T',
370 'UNICODE',
371 '_UNICODE',
372 ('UNDER_CE', '600'),
373 ('_WIN32_WCE', '0x600'),
374 'WINCEOEM',
375 'WINCEINTERNAL',
376 'WIN32',
377 'STRICT',
378 'x86',
379 '_X86_',
380 'INTERNATIONAL',
381 ('INTLMSG_CODEPAGE', '1252'),
382 ]
383 env.Append(CPPDEFINES = cppdefines)
384
385 # C preprocessor includes
386 if platform == 'winddk':
387 env.Append(CPPPATH = [
388 env['SDK_INC_PATH'],
389 env['DDK_INC_PATH'],
390 env['WDM_INC_PATH'],
391 env['CRT_INC_PATH'],
392 ])
393
394 # C compiler options
395 cflags = [] # C
396 cxxflags = [] # C++
397 ccflags = [] # C & C++
398 if gcc:
399 if debug:
400 ccflags += ['-O0', '-g3']
401 elif env['toolchain'] == 'crossmingw':
402 ccflags += ['-O0', '-g3'] # mingw 4.2.1 optimizer is broken
403 else:
404 ccflags += ['-O3', '-g0']
405 if env['profile']:
406 ccflags += ['-pg']
407 if env['machine'] == 'x86':
408 ccflags += [
409 '-m32',
410 #'-march=pentium4',
411 '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics
412 #'-mfpmath=sse',
413 ]
414 if env['machine'] == 'x86_64':
415 ccflags += ['-m64']
416 # See also:
417 # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
418 ccflags += [
419 '-Wall',
420 '-Wmissing-field-initializers',
421 '-Wpointer-arith',
422 '-Wno-long-long',
423 '-ffast-math',
424 '-fmessage-length=0', # be nice to Eclipse
425 ]
426 cflags += [
427 '-Werror=declaration-after-statement',
428 '-Wmissing-prototypes',
429 '-std=gnu99',
430 ]
431 if msvc:
432 # See also:
433 # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
434 # - cl /?
435 if debug:
436 ccflags += [
437 '/Od', # disable optimizations
438 '/Oi', # enable intrinsic functions
439 '/Oy-', # disable frame pointer omission
440 '/GL-', # disable whole program optimization
441 ]
442 else:
443 ccflags += [
444 '/Ox', # maximum optimizations
445 '/Oi', # enable intrinsic functions
446 '/Ot', # favor code speed
447 #'/fp:fast', # fast floating point
448 ]
449 if env['profile']:
450 ccflags += [
451 '/Gh', # enable _penter hook function
452 '/GH', # enable _pexit hook function
453 ]
454 ccflags += [
455 '/W3', # warning level
456 #'/Wp64', # enable 64 bit porting warnings
457 ]
458 if env['machine'] == 'x86':
459 ccflags += [
460 #'/QIfist', # Suppress _ftol
461 #'/arch:SSE2', # use the SSE2 instructions
462 ]
463 if platform == 'windows':
464 ccflags += [
465 # TODO
466 ]
467 if platform == 'winddk':
468 ccflags += [
469 '/Zl', # omit default library name in .OBJ
470 '/Zp8', # 8bytes struct member alignment
471 '/Gy', # separate functions for linker
472 '/Gm-', # disable minimal rebuild
473 '/WX', # treat warnings as errors
474 '/Gz', # __stdcall Calling convention
475 '/GX-', # disable C++ EH
476 '/GR-', # disable C++ RTTI
477 '/GF', # enable read-only string pooling
478 '/G6', # optimize for PPro, P-II, P-III
479 '/Ze', # enable extensions
480 '/Gi-', # disable incremental compilation
481 '/QIfdiv-', # disable Pentium FDIV fix
482 '/hotpatch', # prepares an image for hotpatching.
483 #'/Z7', #enable old-style debug info
484 ]
485 if platform == 'wince':
486 # See also C:\WINCE600\public\common\oak\misc\makefile.def
487 ccflags += [
488 '/Zl', # omit default library name in .OBJ
489 '/GF', # enable read-only string pooling
490 '/GR-', # disable C++ RTTI
491 '/GS', # enable security checks
492 # Allow disabling language conformance to maintain backward compat
493 #'/Zc:wchar_t-', # don't force wchar_t as native type, instead of typedef
494 #'/Zc:forScope-', # don't enforce Standard C++ for scoping rules
495 #'/wd4867',
496 #'/wd4430',
497 #'/MT',
498 #'/U_MT',
499 ]
500 # Automatic pdb generation
501 # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
502 env.EnsureSConsVersion(0, 98, 0)
503 env['PDB'] = '${TARGET.base}.pdb'
504 env.Append(CCFLAGS = ccflags)
505 env.Append(CFLAGS = cflags)
506 env.Append(CXXFLAGS = cxxflags)
507
508 if env['platform'] == 'windows' and msvc:
509 # Choose the appropriate MSVC CRT
510 # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
511 if env['debug']:
512 env.Append(CCFLAGS = ['/MTd'])
513 env.Append(SHCCFLAGS = ['/LDd'])
514 else:
515 env.Append(CCFLAGS = ['/MT'])
516 env.Append(SHCCFLAGS = ['/LD'])
517
518 # Assembler options
519 if gcc:
520 if env['machine'] == 'x86':
521 env.Append(ASFLAGS = ['-m32'])
522 if env['machine'] == 'x86_64':
523 env.Append(ASFLAGS = ['-m64'])
524
525 # Linker options
526 linkflags = []
527 if gcc:
528 if env['machine'] == 'x86':
529 linkflags += ['-m32']
530 if env['machine'] == 'x86_64':
531 linkflags += ['-m64']
532 if platform == 'windows' and msvc:
533 # See also:
534 # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
535 linkflags += [
536 '/fixed:no',
537 '/incremental:no',
538 ]
539 if platform == 'winddk':
540 linkflags += [
541 '/merge:_PAGE=PAGE',
542 '/merge:_TEXT=.text',
543 '/section:INIT,d',
544 '/opt:ref',
545 '/opt:icf',
546 '/ignore:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221',
547 '/incremental:no',
548 '/fullbuild',
549 '/release',
550 '/nodefaultlib',
551 '/wx',
552 '/debug',
553 '/debugtype:cv',
554 '/version:5.1',
555 '/osversion:5.1',
556 '/functionpadmin:5',
557 '/safeseh',
558 '/pdbcompress',
559 '/stack:0x40000,0x1000',
560 '/driver',
561 '/align:0x80',
562 '/subsystem:native,5.01',
563 '/base:0x10000',
564
565 '/entry:DrvEnableDriver',
566 ]
567 if env['debug'] or env['profile']:
568 linkflags += [
569 '/MAP', # http://msdn.microsoft.com/en-us/library/k7xkk3e2.aspx
570 ]
571 if platform == 'wince':
572 linkflags += [
573 '/nodefaultlib',
574 #'/incremental:no',
575 #'/fullbuild',
576 '/entry:_DllMainCRTStartup',
577 ]
578 env.Append(LINKFLAGS = linkflags)
579
580 # Default libs
581 env.Append(LIBS = [])
582
583 # Custom builders and methods
584 createConvenienceLibBuilder(env)
585 createCodeGenerateMethod(env)
586 createInstallMethods(env)
587
588 # for debugging
589 #print env.Dump()
590
591
592 def exists(env):
593 return 1