1"""gallium
2
3Frontend-tool for Gallium3D architecture.
4
5"""
6
7#
8# Copyright 2008 VMware, Inc.
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 VMWARE 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
32from __future__ import print_function
33
34import distutils.version
35import os
36import os.path
37import re
38import subprocess
39import platform as host_platform
40import sys
41import tempfile
42
43import SCons.Action
44import SCons.Builder
45import SCons.Scanner
46
47
48def symlink(target, source, env):
49    target = str(target[0])
50    source = str(source[0])
51    if os.path.islink(target) or os.path.exists(target):
52        os.remove(target)
53    os.symlink(os.path.basename(source), target)
54
55def install(env, source, subdir):
56    target_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build_dir'], subdir)
57    return env.Install(target_dir, source)
58
59def install_program(env, source):
60    return install(env, source, 'bin')
61
62def install_shared_library(env, sources, version = ()):
63    targets = []
64    install_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build_dir'])
65    version = tuple(map(str, version))
66    if env['SHLIBSUFFIX'] == '.dll':
67        dlls = env.FindIxes(sources, 'SHLIBPREFIX', 'SHLIBSUFFIX')
68        targets += install(env, dlls, 'bin')
69        libs = env.FindIxes(sources, 'LIBPREFIX', 'LIBSUFFIX')
70        targets += install(env, libs, 'lib')
71    else:
72        for source in sources:
73            target_dir =  os.path.join(install_dir, 'lib')
74            target_name = '.'.join((str(source),) + version)
75            last = env.InstallAs(os.path.join(target_dir, target_name), source)
76            targets += last
77            while len(version):
78                version = version[:-1]
79                target_name = '.'.join((str(source),) + version)
80                action = SCons.Action.Action(symlink, "  Symlinking $TARGET ...")
81                last = env.Command(os.path.join(target_dir, target_name), last, action)
82                targets += last
83    return targets
84
85
86def msvc2013_compat(env):
87    if env['gcc']:
88        env.Append(CCFLAGS = [
89            '-Werror=vla',
90            '-Werror=pointer-arith',
91        ])
92
93
94def unit_test(env, test_name, program_target, args=None):
95    env.InstallProgram(program_target)
96
97    cmd = [program_target[0].abspath]
98    if args is not None:
99        cmd += args
100    cmd = ' '.join(cmd)
101
102    # http://www.scons.org/wiki/UnitTests
103    action = SCons.Action.Action(cmd, "  Running $SOURCE ...")
104    alias = env.Alias(test_name, program_target, action)
105    env.AlwaysBuild(alias)
106    env.Depends('check', alias)
107
108
109def num_jobs():
110    try:
111        return int(os.environ['NUMBER_OF_PROCESSORS'])
112    except (ValueError, KeyError):
113        pass
114
115    try:
116        return os.sysconf('SC_NPROCESSORS_ONLN')
117    except (ValueError, OSError, AttributeError):
118        pass
119
120    try:
121        return int(os.popen2("sysctl -n hw.ncpu")[1].read())
122    except ValueError:
123        pass
124
125    return 1
126
127
128def check_cc(env, cc, expr, cpp_opt = '-E'):
129    # Invoke C-preprocessor to determine whether the specified expression is
130    # true or not.
131
132    sys.stdout.write('Checking for %s ... ' % cc)
133
134    source = tempfile.NamedTemporaryFile(suffix='.c', delete=False)
135    source.write('#if !(%s)\n#error\n#endif\n' % expr)
136    source.close()
137
138    # sys.stderr.write('%r %s %s\n' % (env['CC'], cpp_opt, source.name));
139
140    pipe = SCons.Action._subproc(env, env.Split(env['CC']) + [cpp_opt, source.name],
141                                 stdin = 'devnull',
142                                 stderr = 'devnull',
143                                 stdout = 'devnull')
144    result = pipe.wait() == 0
145
146    os.unlink(source.name)
147
148    sys.stdout.write(' %s\n' % ['no', 'yes'][int(bool(result))])
149    return result
150
151def check_header(env, header):
152    '''Check if the header exist'''
153
154    conf = SCons.Script.Configure(env)
155    have_header = False
156
157    if conf.CheckHeader(header):
158        have_header = True
159
160    env = conf.Finish()
161    return have_header
162
163def check_functions(env, functions):
164    '''Check if all of the functions exist'''
165
166    conf = SCons.Script.Configure(env)
167    have_functions = True
168
169    for function in functions:
170        if not conf.CheckFunc(function):
171            have_functions = False
172
173    env = conf.Finish()
174    return have_functions
175
176def check_prog(env, prog):
177    """Check whether this program exists."""
178
179    sys.stdout.write('Checking for %s ... ' % prog)
180
181    result = env.Detect(prog)
182
183    sys.stdout.write(' %s\n' % ['no', 'yes'][int(bool(result))])
184    return result
185
186
187def generate(env):
188    """Common environment generation code"""
189
190    # Tell tools which machine to compile for
191    env['TARGET_ARCH'] = env['machine']
192    env['MSVS_ARCH'] = env['machine']
193
194    # Toolchain
195    platform = env['platform']
196    env.Tool(env['toolchain'])
197
198    # Allow override compiler and specify additional flags from environment
199    if 'CC' in os.environ:
200        env['CC'] = os.environ['CC']
201    if 'CFLAGS' in os.environ:
202        env['CCFLAGS'] += SCons.Util.CLVar(os.environ['CFLAGS'])
203    if 'CXX' in os.environ:
204        env['CXX'] = os.environ['CXX']
205    if 'CXXFLAGS' in os.environ:
206        env['CXXFLAGS'] += SCons.Util.CLVar(os.environ['CXXFLAGS'])
207    if 'LDFLAGS' in os.environ:
208        env['LINKFLAGS'] += SCons.Util.CLVar(os.environ['LDFLAGS'])
209
210    # Detect gcc/clang not by executable name, but through pre-defined macros
211    # as autoconf does, to avoid drawing wrong conclusions when using tools
212    # that overrice CC/CXX like scan-build.
213    env['gcc_compat'] = 0
214    env['clang'] = 0
215    env['msvc'] = 0
216    if host_platform.system() == 'Windows':
217        env['msvc'] = check_cc(env, 'MSVC', 'defined(_MSC_VER)', '/E')
218    if not env['msvc']:
219        env['gcc_compat'] = check_cc(env, 'GCC', 'defined(__GNUC__)')
220    env['clang'] = check_cc(env, 'Clang', '__clang__')
221    env['gcc'] = env['gcc_compat'] and not env['clang']
222    env['suncc'] = env['platform'] == 'sunos' and os.path.basename(env['CC']) == 'cc'
223    env['icc'] = 'icc' == os.path.basename(env['CC'])
224
225    # shortcuts
226    machine = env['machine']
227    platform = env['platform']
228    x86 = env['machine'] == 'x86'
229    ppc = env['machine'] == 'ppc'
230    gcc_compat = env['gcc_compat']
231    msvc = env['msvc']
232    suncc = env['suncc']
233    icc = env['icc']
234
235    # Determine whether we are cross compiling; in particular, whether we need
236    # to compile code generators with a different compiler as the target code.
237    hosthost_platform = host_platform.system().lower()
238    if hosthost_platform.startswith('cygwin'):
239        hosthost_platform = 'cygwin'
240    host_machine = os.environ.get('PROCESSOR_ARCHITEW6432', os.environ.get('PROCESSOR_ARCHITECTURE', host_platform.machine()))
241    host_machine = {
242        'x86': 'x86',
243        'i386': 'x86',
244        'i486': 'x86',
245        'i586': 'x86',
246        'i686': 'x86',
247        'ppc' : 'ppc',
248        'AMD64': 'x86_64',
249        'x86_64': 'x86_64',
250    }.get(host_machine, 'generic')
251    env['crosscompile'] = platform != hosthost_platform
252    if machine == 'x86_64' and host_machine != 'x86_64':
253        env['crosscompile'] = True
254    env['hostonly'] = False
255
256    # Backwards compatability with the debug= profile= options
257    if env['build'] == 'debug':
258        if not env['debug']:
259            print('scons: warning: debug option is deprecated and will be removed eventually; use instead')
260            print('')
261            print(' scons build=release')
262            print('')
263            env['build'] = 'release'
264        if env['profile']:
265            print('scons: warning: profile option is deprecated and will be removed eventually; use instead')
266            print('')
267            print(' scons build=profile')
268            print('')
269            env['build'] = 'profile'
270    if False:
271        # Enforce SConscripts to use the new build variable
272        env.popitem('debug')
273        env.popitem('profile')
274    else:
275        # Backwards portability with older sconscripts
276        if env['build'] in ('debug', 'checked'):
277            env['debug'] = True
278            env['profile'] = False
279        if env['build'] == 'profile':
280            env['debug'] = False
281            env['profile'] = True
282        if env['build'] == 'release':
283            env['debug'] = False
284            env['profile'] = False
285
286    # Put build output in a separate dir, which depends on the current
287    # configuration. See also http://www.scons.org/wiki/AdvancedBuildExample
288    build_topdir = 'build'
289    build_subdir = env['platform']
290    if env['embedded']:
291        build_subdir =  'embedded-' + build_subdir
292    if env['machine'] != 'generic':
293        build_subdir += '-' + env['machine']
294    if env['build'] != 'release':
295        build_subdir += '-' +  env['build']
296    build_dir = os.path.join(build_topdir, build_subdir)
297    # Place the .sconsign file in the build dir too, to avoid issues with
298    # different scons versions building the same source file
299    env['build_dir'] = build_dir
300    env.SConsignFile(os.path.join(build_dir, '.sconsign'))
301    if 'SCONS_CACHE_DIR' in os.environ:
302        print('scons: Using build cache in %s.' % (os.environ['SCONS_CACHE_DIR'],))
303        env.CacheDir(os.environ['SCONS_CACHE_DIR'])
304    env['CONFIGUREDIR'] = os.path.join(build_dir, 'conf')
305    env['CONFIGURELOG'] = os.path.join(os.path.abspath(build_dir), 'config.log')
306
307    # Parallel build
308    if env.GetOption('num_jobs') <= 1:
309        env.SetOption('num_jobs', num_jobs())
310
311    # Speed up dependency checking.  See
312    # - https://github.com/SCons/scons/wiki/GoFastButton
313    # - https://bugs.freedesktop.org/show_bug.cgi?id=109443
314
315    # Scons version string has consistently been in this format:
316    # MajorVersion.MinorVersion.Patch[.alpha/beta.yyyymmdd]
317    # so this formula should cover all versions regardless of type
318    # stable, alpha or beta.
319    # For simplicity alpha and beta flags are removed.
320
321    scons_version = distutils.version.StrictVersion('.'.join(SCons.__version__.split('.')[:3]))
322    if scons_version < distutils.version.StrictVersion('3.0.2') or \
323       scons_version > distutils.version.StrictVersion('3.0.4'):
324        env.Decider('MD5-timestamp')
325    env.SetOption('max_drift', 60)
326
327    # C preprocessor options
328    cppdefines = []
329    cppdefines += [
330        '__STDC_CONSTANT_MACROS',
331        '__STDC_FORMAT_MACROS',
332        '__STDC_LIMIT_MACROS',
333        'HAVE_NO_AUTOCONF',
334    ]
335    if env['build'] in ('debug', 'checked'):
336        cppdefines += ['DEBUG']
337    else:
338        cppdefines += ['NDEBUG']
339    if env['build'] == 'profile':
340        cppdefines += ['PROFILE']
341    if env['platform'] in ('posix', 'linux', 'freebsd', 'darwin'):
342        cppdefines += [
343            '_POSIX_SOURCE',
344            ('_POSIX_C_SOURCE', '199309L'),
345            '_SVID_SOURCE',
346            '_BSD_SOURCE',
347            '_GNU_SOURCE',
348            '_DEFAULT_SOURCE',
349        ]
350        if env['platform'] == 'darwin':
351            cppdefines += [
352                '_DARWIN_C_SOURCE',
353                'GLX_USE_APPLEGL',
354                'GLX_DIRECT_RENDERING',
355                'BUILDING_MESA',
356            ]
357        else:
358            cppdefines += [
359                'GLX_DIRECT_RENDERING',
360                'GLX_INDIRECT_RENDERING',
361            ]
362
363        if check_header(env, 'xlocale.h'):
364            cppdefines += ['HAVE_XLOCALE_H']
365
366        if check_header(env, 'endian.h'):
367            cppdefines += ['HAVE_ENDIAN_H']
368
369        if check_functions(env, ['strtod_l', 'strtof_l']):
370            cppdefines += ['HAVE_STRTOD_L']
371
372        if check_functions(env, ['timespec_get']):
373            cppdefines += ['HAVE_TIMESPEC_GET']
374
375    if platform == 'windows':
376        cppdefines += [
377            'WIN32',
378            '_WINDOWS',
379            #'_UNICODE',
380            #'UNICODE',
381            # http://msdn.microsoft.com/en-us/library/aa383745.aspx
382            ('_WIN32_WINNT', '0x0601'),
383            ('WINVER', '0x0601'),
384        ]
385        if gcc_compat:
386            cppdefines += [('__MSVCRT_VERSION__', '0x0700')]
387        if msvc:
388            cppdefines += [
389                'VC_EXTRALEAN',
390                '_USE_MATH_DEFINES',
391                '_CRT_SECURE_NO_WARNINGS',
392                '_CRT_SECURE_NO_DEPRECATE',
393                '_SCL_SECURE_NO_WARNINGS',
394                '_SCL_SECURE_NO_DEPRECATE',
395                '_ALLOW_KEYWORD_MACROS',
396                '_HAS_EXCEPTIONS=0', # Tell C++ STL to not use exceptions
397            ]
398        if env['build'] in ('debug', 'checked'):
399            cppdefines += ['_DEBUG']
400    if platform == 'windows':
401        cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_USER']
402    if env['embedded']:
403        cppdefines += ['PIPE_SUBSYSTEM_EMBEDDED']
404    env.Append(CPPDEFINES = cppdefines)
405
406    # C compiler options
407    cflags = [] # C
408    cxxflags = [] # C++
409    ccflags = [] # C & C++
410    if gcc_compat:
411        if env['build'] == 'debug':
412            ccflags += ['-O0']
413        else:
414            ccflags += ['-O3']
415        if env['gcc']:
416            # gcc's builtin memcmp is slower than glibc's
417            # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43052
418            ccflags += ['-fno-builtin-memcmp']
419        # Work around aliasing bugs - developers should comment this out
420        ccflags += ['-fno-strict-aliasing']
421        ccflags += ['-g']
422        if env['build'] in ('checked', 'profile') or env['asan']:
423            # See http://code.google.com/p/jrfonseca/wiki/Gprof2Dot#Which_options_should_I_pass_to_gcc_when_compiling_for_profiling?
424            ccflags += [
425                '-fno-omit-frame-pointer',
426            ]
427            if env['gcc']:
428                ccflags += ['-fno-optimize-sibling-calls']
429        if env['machine'] == 'x86':
430            ccflags += [
431                '-m32',
432                #'-march=pentium4',
433            ]
434            if platform != 'haiku':
435                # NOTE: We need to ensure stack is realigned given that we
436                # produce shared objects, and have no control over the stack
437                # alignment policy of the application. Therefore we need
438                # -mstackrealign ore -mincoming-stack-boundary=2.
439                #
440                # XXX: We could have SSE without -mstackrealign if we always used
441                # __attribute__((force_align_arg_pointer)), but that's not
442                # always the case.
443                ccflags += [
444                    '-mstackrealign', # ensure stack is aligned
445                    '-msse', '-msse2', # enable SIMD intrinsics
446                    '-mfpmath=sse', # generate SSE floating-point arithmetic
447                ]
448            if platform in ['windows', 'darwin']:
449                # Workaround http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216
450                ccflags += ['-fno-common']
451            if platform in ['haiku']:
452                # Make optimizations compatible with Pentium or higher on Haiku
453                ccflags += [
454                    '-mstackrealign', # ensure stack is aligned
455                    '-march=i586', # Haiku target is Pentium
456                    '-mtune=i686' # use i686 where we can
457                ]
458        if env['machine'] == 'x86_64':
459            ccflags += ['-m64']
460            if platform == 'darwin':
461                ccflags += ['-fno-common']
462        if env['platform'] not in ('cygwin', 'haiku', 'windows'):
463            ccflags += ['-fvisibility=hidden']
464        # See also:
465        # - http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
466        ccflags += [
467            '-Wall',
468            '-Wno-long-long',
469            '-fmessage-length=0', # be nice to Eclipse
470        ]
471        cflags += [
472            '-Wmissing-prototypes',
473            '-std=gnu99',
474        ]
475    if icc:
476        cflags += [
477            '-std=gnu99',
478        ]
479    if msvc:
480        # See also:
481        # - http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
482        # - cl /?
483        if env['build'] == 'debug':
484            ccflags += [
485              '/Od', # disable optimizations
486              '/Oi', # enable intrinsic functions
487            ]
488        else:
489            ccflags += [
490                '/O2', # optimize for speed
491            ]
492        if env['build'] == 'release':
493            if not env['clang']:
494                ccflags += [
495                    '/GL', # enable whole program optimization
496                ]
497        else:
498            ccflags += [
499                '/Oy-', # disable frame pointer omission
500            ]
501        ccflags += [
502            '/W3', # warning level
503            '/wd4018', # signed/unsigned mismatch
504            '/wd4056', # overflow in floating-point constant arithmetic
505            '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
506            '/wd4267', # 'var' : conversion from 'size_t' to 'type', possible loss of data
507            '/wd4305', # truncation from 'type1' to 'type2'
508            '/wd4351', # new behavior: elements of array 'array' will be default initialized
509            '/wd4756', # overflow in constant arithmetic
510            '/wd4800', # forcing value to bool 'true' or 'false' (performance warning)
511            '/wd4996', # disable deprecated POSIX name warnings
512        ]
513        if env['clang']:
514            ccflags += [
515                '-Wno-microsoft-enum-value', # enumerator value is not representable in underlying type 'int'
516            ]
517        if env['machine'] == 'x86':
518            ccflags += [
519                '/arch:SSE2', # use the SSE2 instructions (default since MSVC 2012)
520            ]
521        if platform == 'windows':
522            ccflags += [
523                # TODO
524            ]
525        # Automatic pdb generation
526        # See http://scons.tigris.org/issues/show_bug.cgi?id=1656
527        env.EnsureSConsVersion(0, 98, 0)
528        env['PDB'] = '${TARGET.base}.pdb'
529    env.Append(CCFLAGS = ccflags)
530    env.Append(CFLAGS = cflags)
531    env.Append(CXXFLAGS = cxxflags)
532
533    if env['platform'] == 'windows' and msvc:
534        # Choose the appropriate MSVC CRT
535        # http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx
536        if env['build'] in ('debug', 'checked'):
537            env.Append(CCFLAGS = ['/MTd'])
538            env.Append(SHCCFLAGS = ['/LDd'])
539        else:
540            env.Append(CCFLAGS = ['/MT'])
541            env.Append(SHCCFLAGS = ['/LD'])
542
543    # Static code analysis
544    if env['analyze']:
545        if env['msvc']:
546            # http://msdn.microsoft.com/en-us/library/ms173498.aspx
547            env.Append(CCFLAGS = [
548                '/analyze',
549                #'/analyze:log', '${TARGET.base}.xml',
550                '/wd28251', # Inconsistent annotation for function
551            ])
552        if env['clang']:
553            # scan-build will produce more comprehensive output
554            env.Append(CCFLAGS = ['--analyze'])
555
556    # https://github.com/google/sanitizers/wiki/AddressSanitizer
557    if env['asan']:
558        if gcc_compat:
559            env.Append(CCFLAGS = [
560                '-fsanitize=address',
561            ])
562            env.Append(LINKFLAGS = [
563                '-fsanitize=address',
564            ])
565
566    # Assembler options
567    if gcc_compat:
568        if env['machine'] == 'x86':
569            env.Append(ASFLAGS = ['-m32'])
570        if env['machine'] == 'x86_64':
571            env.Append(ASFLAGS = ['-m64'])
572
573    # Linker options
574    linkflags = []
575    shlinkflags = []
576    if gcc_compat:
577        if env['machine'] == 'x86':
578            linkflags += ['-m32']
579        if env['machine'] == 'x86_64':
580            linkflags += ['-m64']
581        if env['platform'] not in ('darwin'):
582            shlinkflags += [
583                '-Wl,-Bsymbolic',
584            ]
585        # Handle circular dependencies in the libraries
586        if env['platform'] in ('darwin'):
587            pass
588        else:
589            env['_LIBFLAGS'] = '-Wl,--start-group ' + env['_LIBFLAGS'] + ' -Wl,--end-group'
590        if env['platform'] == 'windows':
591            linkflags += [
592                '-Wl,--nxcompat', # DEP
593                '-Wl,--dynamicbase', # ASLR
594            ]
595            # Avoid depending on gcc runtime DLLs
596            linkflags += ['-static-libgcc']
597            if 'w64' in env['CC'].split('-'):
598                linkflags += ['-static-libstdc++']
599            # Handle the @xx symbol munging of DLL exports
600            shlinkflags += ['-Wl,--enable-stdcall-fixup']
601            #shlinkflags += ['-Wl,--kill-at']
602    if msvc:
603        if env['build'] == 'release' and not env['clang']:
604            # enable Link-time Code Generation
605            linkflags += ['/LTCG']
606            env.Append(ARFLAGS = ['/LTCG'])
607    if platform == 'windows' and msvc:
608        # See also:
609        # - http://msdn2.microsoft.com/en-us/library/y0zzbyt4.aspx
610        linkflags += [
611            '/fixed:no',
612            '/incremental:no',
613            '/dynamicbase', # ASLR
614            '/nxcompat', # DEP
615        ]
616    env.Append(LINKFLAGS = linkflags)
617    env.Append(SHLINKFLAGS = shlinkflags)
618
619    # We have C++ in several libraries, so always link with the C++ compiler
620    if gcc_compat:
621        env['LINK'] = env['CXX']
622
623    # Default libs
624    libs = []
625    if env['platform'] in ('darwin', 'freebsd', 'linux', 'posix', 'sunos'):
626        libs += ['m', 'pthread', 'dl']
627    if env['platform'] in ('linux',):
628        libs += ['rt']
629    if env['platform'] in ('haiku'):
630        libs += ['root', 'be', 'network', 'translation']
631    env.Append(LIBS = libs)
632
633    # OpenMP
634    if env['openmp']:
635        if env['msvc']:
636            env.Append(CCFLAGS = ['/openmp'])
637            # When building openmp release VS2008 link.exe crashes with LNK1103 error.
638            # Workaround: overwrite PDB flags with empty value as it isn't required anyways
639            if env['build'] == 'release':
640                env['PDB'] = ''
641        if env['gcc']:
642            env.Append(CCFLAGS = ['-fopenmp'])
643            env.Append(LIBS = ['gomp'])
644
645    # Load tools
646    env.Tool('lex')
647    if env['msvc']:
648        env.Append(LEXFLAGS = [
649            # Force flex to use const keyword in prototypes, as relies on
650            # __cplusplus or __STDC__ macro to determine whether it's safe to
651            # use const keyword, but MSVC never defines __STDC__ unless we
652            # disable all MSVC extensions.
653            '-DYY_USE_CONST=',
654        ])
655        # Flex relies on __STDC_VERSION__>=199901L to decide when to include
656        # C99 inttypes.h.  We always have inttypes.h available with MSVC
657        # (either the one bundled with MSVC 2013, or the one we bundle
658        # ourselves), but we can't just define __STDC_VERSION__ without
659        # breaking stuff, as MSVC doesn't fully support C99.  There's also no
660        # way to premptively include stdint.
661        env.Append(CCFLAGS = ['-FIinttypes.h'])
662    if host_platform.system() == 'Windows':
663        # Prefer winflexbison binaries, as not only they are easier to install
664        # (no additional dependencies), but also better Windows support.
665        if check_prog(env, 'win_flex'):
666            env["LEX"] = 'win_flex'
667            env.Append(LEXFLAGS = [
668                # windows compatibility (uses <io.h> instead of <unistd.h> and
669                # _isatty, _fileno functions)
670                '--wincompat'
671            ])
672
673    env.Tool('yacc')
674    if host_platform.system() == 'Windows':
675        if check_prog(env, 'win_bison'):
676            env["YACC"] = 'win_bison'
677
678    if env['llvm']:
679        env.Tool('llvm')
680
681    # Custom builders and methods
682    env.Tool('custom')
683    env.AddMethod(install_program, 'InstallProgram')
684    env.AddMethod(install_shared_library, 'InstallSharedLibrary')
685    env.AddMethod(msvc2013_compat, 'MSVC2013Compat')
686    env.AddMethod(unit_test, 'UnitTest')
687
688    env.PkgCheckModules('X11', ['x11', 'xext', 'xdamage >= 1.1', 'xfixes', 'glproto >= 1.4.13', 'dri2proto >= 2.8'])
689    env.PkgCheckModules('XCB', ['x11-xcb', 'xcb-glx >= 1.8.1', 'xcb-dri2 >= 1.8'])
690    env.PkgCheckModules('XF86VIDMODE', ['xxf86vm'])
691    env.PkgCheckModules('DRM', ['libdrm >= 2.4.75'])
692
693    if not os.path.exists("src/util/format_srgb.c"):
694        print("Checking for Python Mako module (>= 0.8.0)... ", end='')
695        try:
696            import mako
697        except ImportError:
698            print("no")
699            exit(1)
700        if distutils.version.StrictVersion(mako.__version__) < distutils.version.StrictVersion('0.8.0'):
701            print("no")
702            exit(1)
703        print("yes")
704
705    if env['x11']:
706        env.Append(CPPPATH = env['X11_CPPPATH'])
707
708    env['dri'] = env['x11'] and env['drm']
709
710    # for debugging
711    #print env.Dump()
712
713
714def exists(env):
715    return 1
716