X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=scons%2Fgallium.py;h=ea212d15a95714356e3aa6c97faa9ce310f635cf;hb=2d3f81f3207b4002d565a42e8dc9aec2595d00b8;hp=bd71e51df71327888e7fb3904f6407c5187d6486;hpb=e3c58cdfd97d390cb4c1a02852ab0417bd68c861;p=mesa.git diff --git a/scons/gallium.py b/scons/gallium.py index bd71e51df71..ea212d15a95 100755 --- a/scons/gallium.py +++ b/scons/gallium.py @@ -29,13 +29,16 @@ Frontend-tool for Gallium3D architecture. # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +from __future__ import print_function import distutils.version import os import os.path import re import subprocess -import platform as _platform +import platform as host_platform +import sys +import tempfile import SCons.Action import SCons.Builder @@ -80,9 +83,27 @@ def install_shared_library(env, sources, version = ()): return targets -def createInstallMethods(env): - env.AddMethod(install_program, 'InstallProgram') - env.AddMethod(install_shared_library, 'InstallSharedLibrary') +def msvc2013_compat(env): + if env['gcc']: + env.Append(CCFLAGS = [ + '-Werror=vla', + '-Werror=pointer-arith', + ]) + + +def unit_test(env, test_name, program_target, args=None): + env.InstallProgram(program_target) + + cmd = [program_target[0].abspath] + if args is not None: + cmd += args + cmd = ' '.join(cmd) + + # http://www.scons.org/wiki/UnitTests + action = SCons.Action.Action(cmd, " Running $SOURCE ...") + alias = env.Alias(test_name, program_target, action) + env.AlwaysBuild(alias) + env.Depends('check', alias) def num_jobs(): @@ -104,6 +125,65 @@ def num_jobs(): return 1 +def check_cc(env, cc, expr, cpp_opt = '-E'): + # Invoke C-preprocessor to determine whether the specified expression is + # true or not. + + sys.stdout.write('Checking for %s ... ' % cc) + + source = tempfile.NamedTemporaryFile(suffix='.c', delete=False) + source.write(('#if !(%s)\n#error\n#endif\n' % expr).encode()) + source.close() + + # sys.stderr.write('%r %s %s\n' % (env['CC'], cpp_opt, source.name)); + + pipe = SCons.Action._subproc(env, env.Split(env['CC']) + [cpp_opt, source.name], + stdin = 'devnull', + stderr = 'devnull', + stdout = 'devnull') + result = pipe.wait() == 0 + + os.unlink(source.name) + + sys.stdout.write(' %s\n' % ['no', 'yes'][int(bool(result))]) + return result + +def check_header(env, header): + '''Check if the header exist''' + + conf = SCons.Script.Configure(env) + have_header = False + + if conf.CheckHeader(header): + have_header = True + + env = conf.Finish() + return have_header + +def check_functions(env, functions): + '''Check if all of the functions exist''' + + conf = SCons.Script.Configure(env) + have_functions = True + + for function in functions: + if not conf.CheckFunc(function): + have_functions = False + + env = conf.Finish() + return have_functions + +def check_prog(env, prog): + """Check whether this program exists.""" + + sys.stdout.write('Checking for %s ... ' % prog) + + result = env.Detect(prog) + + sys.stdout.write(' %s\n' % ['no', 'yes'][int(bool(result))]) + return result + + def generate(env): """Common environment generation code""" @@ -116,53 +196,51 @@ def generate(env): env.Tool(env['toolchain']) # Allow override compiler and specify additional flags from environment - if os.environ.has_key('CC'): + if 'CC' in os.environ: env['CC'] = os.environ['CC'] - # Update CCVERSION to match - pipe = SCons.Action._subproc(env, [env['CC'], '--version'], - stdin = 'devnull', - stderr = 'devnull', - stdout = subprocess.PIPE) - if pipe.wait() == 0: - line = pipe.stdout.readline() - match = re.search(r'[0-9]+(\.[0-9]+)+', line) - if match: - env['CCVERSION'] = match.group(0) - if os.environ.has_key('CFLAGS'): + if 'CFLAGS' in os.environ: env['CCFLAGS'] += SCons.Util.CLVar(os.environ['CFLAGS']) - if os.environ.has_key('CXX'): + if 'CXX' in os.environ: env['CXX'] = os.environ['CXX'] - if os.environ.has_key('CXXFLAGS'): + if 'CXXFLAGS' in os.environ: env['CXXFLAGS'] += SCons.Util.CLVar(os.environ['CXXFLAGS']) - if os.environ.has_key('LDFLAGS'): + if 'LDFLAGS' in os.environ: env['LINKFLAGS'] += SCons.Util.CLVar(os.environ['LDFLAGS']) - env['gcc'] = 'gcc' in os.path.basename(env['CC']).split('-') - env['msvc'] = env['CC'] == 'cl' + # Detect gcc/clang not by executable name, but through pre-defined macros + # as autoconf does, to avoid drawing wrong conclusions when using tools + # that overrice CC/CXX like scan-build. + env['gcc_compat'] = 0 + env['clang'] = 0 + env['msvc'] = 0 + if host_platform.system() == 'Windows': + env['msvc'] = check_cc(env, 'MSVC', 'defined(_MSC_VER)', '/E') + if not env['msvc']: + env['gcc_compat'] = check_cc(env, 'GCC', 'defined(__GNUC__)') + env['clang'] = check_cc(env, 'Clang', '__clang__') + env['gcc'] = env['gcc_compat'] and not env['clang'] env['suncc'] = env['platform'] == 'sunos' and os.path.basename(env['CC']) == 'cc' - env['clang'] = env['CC'] == 'clang' env['icc'] = 'icc' == os.path.basename(env['CC']) - if env['msvc'] and env['toolchain'] == 'default' and env['machine'] == 'x86_64': - # MSVC x64 support is broken in earlier versions of scons - env.EnsurePythonVersion(2, 0) - # shortcuts machine = env['machine'] platform = env['platform'] x86 = env['machine'] == 'x86' ppc = env['machine'] == 'ppc' - gcc_compat = env['gcc'] or env['clang'] + gcc_compat = env['gcc_compat'] msvc = env['msvc'] suncc = env['suncc'] icc = env['icc'] # Determine whether we are cross compiling; in particular, whether we need # to compile code generators with a different compiler as the target code. - host_platform = _platform.system().lower() - if host_platform.startswith('cygwin'): - host_platform = 'cygwin' - host_machine = os.environ.get('PROCESSOR_ARCHITEW6432', os.environ.get('PROCESSOR_ARCHITECTURE', _platform.machine())) + hosthost_platform = host_platform.system().lower() + if hosthost_platform.startswith('cygwin'): + hosthost_platform = 'cygwin' + # Avoid spurious crosscompilation in MSYS2 environment. + if hosthost_platform.startswith('mingw'): + hosthost_platform = 'windows' + host_machine = os.environ.get('PROCESSOR_ARCHITEW6432', os.environ.get('PROCESSOR_ARCHITECTURE', host_platform.machine())) host_machine = { 'x86': 'x86', 'i386': 'x86', @@ -173,7 +251,7 @@ def generate(env): 'AMD64': 'x86_64', 'x86_64': 'x86_64', }.get(host_machine, 'generic') - env['crosscompile'] = platform != host_platform + env['crosscompile'] = platform != hosthost_platform if machine == 'x86_64' and host_machine != 'x86_64': env['crosscompile'] = True env['hostonly'] = False @@ -181,16 +259,16 @@ def generate(env): # Backwards compatability with the debug= profile= options if env['build'] == 'debug': if not env['debug']: - print 'scons: warning: debug option is deprecated and will be removed eventually; use instead' - print - print ' scons build=release' - print + print('scons: warning: debug option is deprecated and will be removed eventually; use instead') + print('') + print(' scons build=release') + print('') env['build'] = 'release' if env['profile']: - print 'scons: warning: profile option is deprecated and will be removed eventually; use instead' - print - print ' scons build=profile' - print + print('scons: warning: profile option is deprecated and will be removed eventually; use instead') + print('') + print(' scons build=profile') + print('') env['build'] = 'profile' if False: # Enforce SConscripts to use the new build variable @@ -224,7 +302,7 @@ def generate(env): env['build_dir'] = build_dir env.SConsignFile(os.path.join(build_dir, '.sconsign')) if 'SCONS_CACHE_DIR' in os.environ: - print 'scons: Using build cache in %s.' % (os.environ['SCONS_CACHE_DIR'],) + print('scons: Using build cache in %s.' % (os.environ['SCONS_CACHE_DIR'],)) env.CacheDir(os.environ['SCONS_CACHE_DIR']) env['CONFIGUREDIR'] = os.path.join(build_dir, 'conf') env['CONFIGURELOG'] = os.path.join(os.path.abspath(build_dir), 'config.log') @@ -233,11 +311,30 @@ def generate(env): if env.GetOption('num_jobs') <= 1: env.SetOption('num_jobs', num_jobs()) - env.Decider('MD5-timestamp') + # Speed up dependency checking. See + # - https://github.com/SCons/scons/wiki/GoFastButton + # - https://bugs.freedesktop.org/show_bug.cgi?id=109443 + + # Scons version string has consistently been in this format: + # MajorVersion.MinorVersion.Patch[.alpha/beta.yyyymmdd] + # so this formula should cover all versions regardless of type + # stable, alpha or beta. + # For simplicity alpha and beta flags are removed. + + scons_version = distutils.version.StrictVersion('.'.join(SCons.__version__.split('.')[:3])) + if scons_version < distutils.version.StrictVersion('3.0.2') or \ + scons_version > distutils.version.StrictVersion('3.0.4'): + env.Decider('MD5-timestamp') env.SetOption('max_drift', 60) # C preprocessor options cppdefines = [] + cppdefines += [ + '__STDC_CONSTANT_MACROS', + '__STDC_FORMAT_MACROS', + '__STDC_LIMIT_MACROS', + 'HAVE_SCONS', + ] if env['build'] in ('debug', 'checked'): cppdefines += ['DEBUG'] else: @@ -251,29 +348,50 @@ def generate(env): '_SVID_SOURCE', '_BSD_SOURCE', '_GNU_SOURCE', - 'HAVE_PTHREAD', - 'HAVE_POSIX_MEMALIGN', + '_DEFAULT_SOURCE', ] if env['platform'] == 'darwin': cppdefines += [ '_DARWIN_C_SOURCE', 'GLX_USE_APPLEGL', 'GLX_DIRECT_RENDERING', + 'BUILDING_MESA', ] else: cppdefines += [ 'GLX_DIRECT_RENDERING', 'GLX_INDIRECT_RENDERING', ] - if env['platform'] in ('linux', 'freebsd'): - cppdefines += ['HAVE_ALIAS'] - else: - cppdefines += ['GLX_ALIAS_UNSUPPORTED'] - if env['platform'] == 'haiku': - cppdefines += [ - 'HAVE_PTHREAD', - 'HAVE_POSIX_MEMALIGN' - ] + + if check_header(env, 'xlocale.h'): + cppdefines += ['HAVE_XLOCALE_H'] + + if check_header(env, 'endian.h'): + cppdefines += ['HAVE_ENDIAN_H'] + + if check_functions(env, ['strtod_l', 'strtof_l']): + cppdefines += ['HAVE_STRTOD_L'] + + if check_functions(env, ['random_r']): + cppdefines += ['HAVE_RANDOM_R'] + + if check_functions(env, ['timespec_get']): + cppdefines += ['HAVE_TIMESPEC_GET'] + + if check_header(env, 'sys/shm.h'): + cppdefines += ['HAVE_SYS_SHM_H'] + + if check_functions(env, ['strtok_r']): + cppdefines += ['HAVE_STRTOK_R'] + + #FIXME: we should really be checking for the major()/minor() + # functions/macros in these headers, but check_functions()'s + # SConf.CheckFunc() doesn't seem to support macros. + if check_header(env, 'sys/mkdev.h'): + cppdefines += ['MAJOR_IN_MKDEV'] + if check_header(env, 'sys/sysmacros.h'): + cppdefines += ['MAJOR_IN_SYSMACROS'] + if platform == 'windows': cppdefines += [ 'WIN32', @@ -295,17 +413,12 @@ def generate(env): '_SCL_SECURE_NO_WARNINGS', '_SCL_SECURE_NO_DEPRECATE', '_ALLOW_KEYWORD_MACROS', + '_HAS_EXCEPTIONS=0', # Tell C++ STL to not use exceptions ] if env['build'] in ('debug', 'checked'): cppdefines += ['_DEBUG'] - if platform == 'windows': - cppdefines += ['PIPE_SUBSYSTEM_WINDOWS_USER'] if env['embedded']: - cppdefines += ['PIPE_SUBSYSTEM_EMBEDDED'] - if env['texture_float']: - print 'warning: Floating-point textures enabled.' - print 'warning: Please consult docs/patents.txt with your lawyer before building Mesa.' - cppdefines += ['TEXTURE_FLOAT_ENABLED'] + cppdefines += ['EMBEDDED_DEVICE'] env.Append(CPPDEFINES = cppdefines) # C compiler options @@ -313,13 +426,8 @@ def generate(env): cxxflags = [] # C++ ccflags = [] # C & C++ if gcc_compat: - ccversion = env['CCVERSION'] if env['build'] == 'debug': ccflags += ['-O0'] - elif env['gcc'] and ccversion.startswith('4.2.'): - # gcc 4.2.x optimizer is broken - print "warning: gcc 4.2.x optimizer is broken -- disabling optimizations" - ccflags += ['-O0'] else: ccflags += ['-O3'] if env['gcc']: @@ -329,7 +437,7 @@ def generate(env): # Work around aliasing bugs - developers should comment this out ccflags += ['-fno-strict-aliasing'] ccflags += ['-g'] - if env['build'] in ('checked', 'profile'): + if env['build'] in ('checked', 'profile') or env['asan']: # See http://code.google.com/p/jrfonseca/wiki/Gprof2Dot#Which_options_should_I_pass_to_gcc_when_compiling_for_profiling? ccflags += [ '-fno-omit-frame-pointer', @@ -341,23 +449,19 @@ def generate(env): '-m32', #'-march=pentium4', ] - if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2') \ - and (platform != 'windows' or env['build'] == 'debug' or True) \ - and platform != 'haiku': + if platform != 'haiku': # NOTE: We need to ensure stack is realigned given that we # produce shared objects, and have no control over the stack # alignment policy of the application. Therefore we need # -mstackrealign ore -mincoming-stack-boundary=2. # - # XXX: -O and -mstackrealign causes stack corruption on MinGW - # # XXX: We could have SSE without -mstackrealign if we always used # __attribute__((force_align_arg_pointer)), but that's not # always the case. ccflags += [ '-mstackrealign', # ensure stack is aligned - '-mmmx', '-msse', '-msse2', # enable SIMD intrinsics - #'-mfpmath=sse', + '-msse', '-msse2', # enable SIMD intrinsics + '-mfpmath=sse', # generate SSE floating-point arithmetic ] if platform in ['windows', 'darwin']: # Workaround http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216 @@ -383,16 +487,15 @@ def generate(env): '-fmessage-length=0', # be nice to Eclipse ] cflags += [ - '-Wmissing-prototypes', - '-std=gnu99', + '-Werror=implicit-function-declaration', + '-Werror=missing-prototypes', + '-Werror=return-type', + '-Werror=incompatible-pointer-types', ] - if distutils.version.LooseVersion(ccversion) >= distutils.version.LooseVersion('4.2'): - ccflags += [ - '-Wpointer-arith', - ] - cflags += [ - '-Wdeclaration-after-statement', - ] + if platform == 'darwin' and host_platform.mac_ver()[0] >= '10.15': + cflags += ['-std=gnu11'] + else: + cflags += ['-std=gnu99'] if icc: cflags += [ '-std=gnu99', @@ -407,28 +510,37 @@ def generate(env): '/Oi', # enable intrinsic functions ] else: - if 'MSVC_VERSION' in env and distutils.version.LooseVersion(env['MSVC_VERSION']) < distutils.version.LooseVersion('11.0'): - print 'scons: warning: Visual Studio versions prior to 2012 are known to produce incorrect code when optimizations are enabled ( https://bugs.freedesktop.org/show_bug.cgi?id=58718 )' ccflags += [ '/O2', # optimize for speed ] if env['build'] == 'release': - ccflags += [ - '/GL', # enable whole program optimization - ] + if not env['clang']: + ccflags += [ + '/GL', # enable whole program optimization + ] else: ccflags += [ '/Oy-', # disable frame pointer omission - '/GL-', # disable whole program optimization ] ccflags += [ '/W3', # warning level - #'/Wp64', # enable 64 bit porting warnings + '/wd4018', # signed/unsigned mismatch + '/wd4056', # overflow in floating-point constant arithmetic + '/wd4244', # conversion from 'type1' to 'type2', possible loss of data + '/wd4267', # 'var' : conversion from 'size_t' to 'type', possible loss of data + '/wd4305', # truncation from 'type1' to 'type2' + '/wd4351', # new behavior: elements of array 'array' will be default initialized + '/wd4756', # overflow in constant arithmetic + '/wd4800', # forcing value to bool 'true' or 'false' (performance warning) '/wd4996', # disable deprecated POSIX name warnings ] + if env['clang']: + ccflags += [ + '-Wno-microsoft-enum-value', # enumerator value is not representable in underlying type 'int' + ] if env['machine'] == 'x86': ccflags += [ - #'/arch:SSE2', # use the SSE2 instructions + '/arch:SSE2', # use the SSE2 instructions (default since MSVC 2012) ] if platform == 'windows': ccflags += [ @@ -459,11 +571,22 @@ def generate(env): env.Append(CCFLAGS = [ '/analyze', #'/analyze:log', '${TARGET.base}.xml', + '/wd28251', # Inconsistent annotation for function ]) if env['clang']: # scan-build will produce more comprehensive output env.Append(CCFLAGS = ['--analyze']) + # https://github.com/google/sanitizers/wiki/AddressSanitizer + if env['asan']: + if gcc_compat: + env.Append(CCFLAGS = [ + '-fsanitize=address', + ]) + env.Append(LINKFLAGS = [ + '-fsanitize=address', + ]) + # Assembler options if gcc_compat: if env['machine'] == 'x86': @@ -489,6 +612,10 @@ def generate(env): else: env['_LIBFLAGS'] = '-Wl,--start-group ' + env['_LIBFLAGS'] + ' -Wl,--end-group' if env['platform'] == 'windows': + linkflags += [ + '-Wl,--nxcompat', # DEP + '-Wl,--dynamicbase', # ASLR + ] # Avoid depending on gcc runtime DLLs linkflags += ['-static-libgcc'] if 'w64' in env['CC'].split('-'): @@ -497,7 +624,7 @@ def generate(env): shlinkflags += ['-Wl,--enable-stdcall-fixup'] #shlinkflags += ['-Wl,--kill-at'] if msvc: - if env['build'] == 'release': + if env['build'] == 'release' and not env['clang']: # enable Link-time Code Generation linkflags += ['/LTCG'] env.Append(ARFLAGS = ['/LTCG']) @@ -507,6 +634,8 @@ def generate(env): linkflags += [ '/fixed:no', '/incremental:no', + '/dynamicbase', # ASLR + '/nxcompat', # DEP ] env.Append(LINKFLAGS = linkflags) env.Append(SHLINKFLAGS = shlinkflags) @@ -539,20 +668,66 @@ def generate(env): # Load tools env.Tool('lex') + if env['msvc']: + env.Append(LEXFLAGS = [ + # Force flex to use const keyword in prototypes, as relies on + # __cplusplus or __STDC__ macro to determine whether it's safe to + # use const keyword, but MSVC never defines __STDC__ unless we + # disable all MSVC extensions. + '-DYY_USE_CONST=', + ]) + # Flex relies on __STDC_VERSION__>=199901L to decide when to include + # C99 inttypes.h. We always have inttypes.h available with MSVC + # (either the one bundled with MSVC 2013, or the one we bundle + # ourselves), but we can't just define __STDC_VERSION__ without + # breaking stuff, as MSVC doesn't fully support C99. There's also no + # way to premptively include stdint. + env.Append(CCFLAGS = ['-FIinttypes.h']) + if host_platform.system() == 'Windows': + # Prefer winflexbison binaries, as not only they are easier to install + # (no additional dependencies), but also better Windows support. + if check_prog(env, 'win_flex'): + env["LEX"] = 'win_flex' + env.Append(LEXFLAGS = [ + # windows compatibility (uses instead of and + # _isatty, _fileno functions) + '--wincompat' + ]) + env.Tool('yacc') + if host_platform.system() == 'Windows': + if check_prog(env, 'win_bison'): + env["YACC"] = 'win_bison' + if env['llvm']: env.Tool('llvm') # Custom builders and methods env.Tool('custom') - createInstallMethods(env) + env.AddMethod(install_program, 'InstallProgram') + env.AddMethod(install_shared_library, 'InstallSharedLibrary') + env.AddMethod(msvc2013_compat, 'MSVC2013Compat') + env.AddMethod(unit_test, 'UnitTest') - env.PkgCheckModules('X11', ['x11', 'xext', 'xdamage', 'xfixes']) - env.PkgCheckModules('XCB', ['x11-xcb', 'xcb-glx >= 1.8.1']) + env.PkgCheckModules('X11', ['x11', 'xext', 'xdamage >= 1.1', 'xfixes', 'glproto >= 1.4.13', 'dri2proto >= 2.8']) + env.PkgCheckModules('XCB', ['x11-xcb', 'xcb-glx >= 1.8.1', 'xcb-dri2 >= 1.8']) env.PkgCheckModules('XF86VIDMODE', ['xxf86vm']) - env.PkgCheckModules('DRM', ['libdrm >= 2.4.38']) - env.PkgCheckModules('DRM_INTEL', ['libdrm_intel >= 2.4.52']) - env.PkgCheckModules('UDEV', ['libudev >= 151']) + env.PkgCheckModules('DRM', ['libdrm >= 2.4.75']) + + if not os.path.exists("src/util/format_srgb.c"): + print("Checking for Python Mako module (>= 0.8.0)... ", end='') + try: + import mako + except ImportError: + print("no") + exit(1) + if distutils.version.StrictVersion(mako.__version__) < distutils.version.StrictVersion('0.8.0'): + print("no") + exit(1) + print("yes") + + if env['x11']: + env.Append(CPPPATH = env['X11_CPPPATH']) env['dri'] = env['x11'] and env['drm']