gallium.py revision 11b15c4d254ee689183306579d9c4851e29c3c4a
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 distutils.version 34import os 35import os.path 36import re 37import subprocess 38 39import SCons.Action 40import SCons.Builder 41import SCons.Scanner 42 43 44def 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 51def 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 55def install_program(env, source): 56 return install(env, source, 'bin') 57 58def 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 82def createInstallMethods(env): 83 env.AddMethod(install_program, 'InstallProgram') 84 env.AddMethod(install_shared_library, 'InstallSharedLibrary') 85 86 87def 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 106def 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 141def 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 # We have C++ in several libraries, so always link with the C++ compiler 555 if env['gcc']: 556 env['LINK'] = env['CXX'] 557 558 # Default libs 559 env.Append(LIBS = []) 560 561 # Load tools 562 if env['llvm']: 563 env.Tool('llvm') 564 env.Tool('udis86') 565 566 pkg_config_modules(env, 'x11', ['x11', 'xext']) 567 pkg_config_modules(env, 'drm', ['libdrm']) 568 pkg_config_modules(env, 'drm_intel', ['libdrm_intel']) 569 pkg_config_modules(env, 'drm_radeon', ['libdrm_radeon']) 570 pkg_config_modules(env, 'xorg', ['xorg-server']) 571 pkg_config_modules(env, 'kms', ['libkms']) 572 573 env['dri'] = env['x11'] and env['drm'] 574 575 # Custom builders and methods 576 env.Tool('custom') 577 createInstallMethods(env) 578 579 # for debugging 580 #print env.Dump() 581 582 583def exists(env): 584 return 1 585