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