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