123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909 |
- # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- # PGO
- # ==============================================================
- option(env='MOZ_PGO', help='Build with profile guided optimizations')
- set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
- add_old_configure_assignment('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
- # yasm detection
- # ==============================================================
- yasm = check_prog('YASM', ['yasm'], allow_missing=True)
- @depends_if(yasm)
- @checking('yasm version')
- def yasm_version(yasm):
- version = check_cmd_output(
- yasm, '--version',
- onerror=lambda: die('Failed to get yasm version.')
- ).splitlines()[0].split()[1]
- return Version(version)
- # Until we move all the yasm consumers out of old-configure.
- # bug 1257904
- add_old_configure_assignment('_YASM_MAJOR_VERSION',
- delayed_getattr(yasm_version, 'major'))
- add_old_configure_assignment('_YASM_MINOR_VERSION',
- delayed_getattr(yasm_version, 'minor'))
- @depends(yasm, target)
- def yasm_asflags(yasm, target):
- if yasm:
- asflags = {
- ('OSX', 'x86'): '-f macho32',
- ('OSX', 'x86_64'): '-f macho64',
- ('WINNT', 'x86'): '-f win32',
- ('WINNT', 'x86_64'): '-f x64',
- }.get((target.os, target.cpu), None)
- if asflags is None:
- # We're assuming every x86 platform we support that's
- # not Windows or Mac is ELF.
- if target.cpu == 'x86':
- asflags = '-f elf32'
- elif target.cpu == 'x86_64':
- asflags = '-f elf64'
- if asflags:
- asflags += ' -rnasm -pnasm'
- return asflags
- set_config('YASM_ASFLAGS', yasm_asflags)
- @depends(yasm_asflags)
- def have_yasm(value):
- if value:
- return True
- set_config('HAVE_YASM', have_yasm)
- # Until the YASM variable is not necessary in old-configure.
- add_old_configure_assignment('YASM', have_yasm)
- # Android NDK
- # ==============================================================
- @depends('--disable-compile-environment', build_project, gonkdir, '--help')
- def compiling_android(compile_env, build_project, gonkdir, _):
- return compile_env and (gonkdir or build_project in ('mobile/android', 'js'))
- include('android-ndk.configure', when=compiling_android)
- # MacOS deployment target version
- # ==============================================================
- # This needs to happen before any compilation test is done.
- option('--enable-macos-target', env='MACOSX_DEPLOYMENT_TARGET', nargs=1,
- default='10.7', help='Set the minimum MacOS version needed at runtime')
- @depends('--enable-macos-target', target)
- @imports(_from='os', _import='environ')
- def macos_target(value, target):
- if value and target.os == 'OSX':
- # Ensure every compiler process we spawn uses this value.
- environ['MACOSX_DEPLOYMENT_TARGET'] = value[0]
- return value[0]
- if value and value.origin != 'default':
- die('--enable-macos-target cannot be used when targeting %s',
- target.os)
- set_config('MACOSX_DEPLOYMENT_TARGET', macos_target)
- add_old_configure_assignment('MACOSX_DEPLOYMENT_TARGET', macos_target)
- # Compiler wrappers
- # ==============================================================
- # Normally, we'd use js_option and automatically have those variables
- # propagated to js/src, but things are complicated by possible additional
- # wrappers in CC/CXX, and by other subconfigures that do not handle those
- # options and do need CC/CXX altered.
- option('--with-compiler-wrapper', env='COMPILER_WRAPPER', nargs=1,
- help='Enable compiling with wrappers such as distcc and ccache')
- option('--with-ccache', env='CCACHE', nargs='?',
- help='Enable compiling with ccache')
- @depends_if('--with-ccache')
- def ccache(value):
- if len(value):
- return value
- # If --with-ccache was given without an explicit value, we default to
- # 'ccache'.
- return 'ccache'
- ccache = check_prog('CCACHE', progs=(), input=ccache)
- @depends_if(ccache)
- def using_ccache(ccache):
- return True
- set_config('MOZ_USING_CCACHE', using_ccache)
- @depends('--with-compiler-wrapper', ccache)
- @imports(_from='mozbuild.shellutil', _import='split', _as='shell_split')
- def compiler_wrapper(wrapper, ccache):
- if wrapper:
- raw_wrapper = wrapper[0]
- wrapper = shell_split(raw_wrapper)
- wrapper_program = find_program(wrapper[0])
- if not wrapper_program:
- die('Cannot find `%s` from the given compiler wrapper `%s`',
- wrapper[0], raw_wrapper)
- wrapper[0] = wrapper_program
- if ccache:
- if wrapper:
- return tuple([ccache] + wrapper)
- else:
- return (ccache,)
- elif wrapper:
- return tuple(wrapper)
- add_old_configure_assignment('COMPILER_WRAPPER', compiler_wrapper)
- @depends_if(compiler_wrapper)
- def using_compiler_wrapper(compiler_wrapper):
- return True
- set_config('MOZ_USING_COMPILER_WRAPPER', using_compiler_wrapper)
- # Cross-compilation related things.
- # ==============================================================
- js_option('--with-toolchain-prefix', env='TOOLCHAIN_PREFIX', nargs=1,
- help='Prefix for the target toolchain')
- @depends('--with-toolchain-prefix', target, host, cross_compiling)
- def toolchain_prefix(value, target, host, cross_compiling):
- if value:
- return tuple(value)
- if cross_compiling:
- return ('%s-' % target.toolchain, '%s-' % target.alias)
- @depends(toolchain_prefix, target)
- def first_toolchain_prefix(toolchain_prefix, target):
- # Pass TOOLCHAIN_PREFIX down to the build system if it was given from the
- # command line/environment (in which case there's only one value in the tuple),
- # or when cross-compiling for Android.
- if toolchain_prefix and (target.os == 'Android' or len(toolchain_prefix) == 1):
- return toolchain_prefix[0]
- set_config('TOOLCHAIN_PREFIX', first_toolchain_prefix)
- add_old_configure_assignment('TOOLCHAIN_PREFIX', first_toolchain_prefix)
- # Compilers
- # ==============================================================
- include('compilers-util.configure')
- def try_preprocess(compiler, language, source):
- return try_invoke_compiler(compiler, language, source, ['-E'])
- @imports(_from='mozbuild.configure.constants', _import='CompilerType')
- @imports(_from='mozbuild.configure.constants',
- _import='CPU_preprocessor_checks')
- @imports(_from='mozbuild.configure.constants',
- _import='kernel_preprocessor_checks')
- @imports(_from='textwrap', _import='dedent')
- def get_compiler_info(compiler, language):
- '''Returns information about the given `compiler` (command line in the
- form of a list or tuple), in the given `language`.
- The returned information includes:
- - the compiler type (msvc, clang-cl, clang or gcc)
- - the compiler version
- - the compiler supported language
- - the compiler supported language version
- '''
- # Note: MSVC doesn't expose __STDC_VERSION__. It does expose __STDC__,
- # but only when given the -Za option, which disables compiler
- # extensions.
- # Note: We'd normally do a version check for clang, but versions of clang
- # in Xcode have a completely different versioning scheme despite exposing
- # the version with the same defines.
- # So instead, we make things such that the version is missing when the
- # clang used is below the minimum supported version (currently clang 3.6).
- # We then only include the version information when the C++ compiler
- # matches the feature check, so that an unsupported version of clang would
- # have no version number.
- check = dedent('''\
- #if defined(_MSC_VER)
- #if defined(__clang__)
- %COMPILER "clang-cl"
- %VERSION _MSC_FULL_VER
- #else
- %COMPILER "msvc"
- %VERSION _MSC_FULL_VER
- #endif
- #elif defined(__clang__)
- %COMPILER "clang"
- # if !__cplusplus || __has_feature(cxx_alignof)
- %VERSION __clang_major__.__clang_minor__.__clang_patchlevel__
- # endif
- #elif defined(__GNUC__)
- %COMPILER "gcc"
- %VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__
- #endif
- #if __cplusplus
- %cplusplus __cplusplus
- #elif __STDC_VERSION__
- %STDC_VERSION __STDC_VERSION__
- #elif __STDC__
- %STDC_VERSION 198900L
- #endif
- ''')
- # While we're doing some preprocessing, we might as well do some more
- # preprocessor-based tests at the same time, to check the toolchain
- # matches what we want.
- for name, preprocessor_checks in (
- ('CPU', CPU_preprocessor_checks),
- ('KERNEL', kernel_preprocessor_checks),
- ):
- for n, (value, condition) in enumerate(preprocessor_checks.iteritems()):
- check += dedent('''\
- #%(if)s %(condition)s
- %%%(name)s "%(value)s"
- ''' % {
- 'if': 'elif' if n else 'if',
- 'condition': condition,
- 'name': name,
- 'value': value,
- })
- check += '#endif\n'
- # Also check for endianness. The advantage of living in modern times is
- # that all the modern compilers we support now have __BYTE_ORDER__ defined
- # by the preprocessor, except MSVC, which only supports little endian.
- check += dedent('''\
- #if _MSC_VER || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- %ENDIANNESS "little"
- #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- %ENDIANNESS "big"
- #endif
- ''')
- result = try_preprocess(compiler, language, check)
- if not result:
- raise FatalCheckError(
- 'Unknown compiler or compiler not supported.')
- # Metadata emitted by preprocessors such as GCC with LANG=ja_JP.utf-8 may
- # have non-ASCII characters. Treat the output as bytearray.
- data = {}
- for line in result.splitlines():
- if line.startswith(b'%'):
- k, _, v = line.partition(' ')
- k = k.lstrip('%')
- data[k] = v.replace(' ', '').lstrip('"').rstrip('"')
- log.debug('%s = %s', k, data[k])
- try:
- type = CompilerType(data['COMPILER'])
- except:
- raise FatalCheckError(
- 'Unknown compiler or compiler not supported.')
- cplusplus = int(data.get('cplusplus', '0L').rstrip('L'))
- stdc_version = int(data.get('STDC_VERSION', '0L').rstrip('L'))
- version = data.get('VERSION')
- if version and type in ('msvc', 'clang-cl'):
- msc_ver = version
- version = msc_ver[0:2]
- if len(msc_ver) > 2:
- version += '.' + msc_ver[2:4]
- if len(msc_ver) > 4:
- version += '.' + msc_ver[4:]
- if version:
- version = Version(version)
- return namespace(
- type=type,
- version=version,
- cpu=data.get('CPU'),
- kernel=data.get('KERNEL'),
- endianness=data.get('ENDIANNESS'),
- language='C++' if cplusplus else 'C',
- language_version=cplusplus if cplusplus else stdc_version,
- )
- @imports(_from='mozbuild.shellutil', _import='quote')
- def check_compiler(compiler, language, target):
- info = get_compiler_info(compiler, language)
- flags = []
- def append_flag(flag):
- if flag not in flags:
- if info.type == 'clang-cl':
- flags.append('-Xclang')
- flags.append(flag)
- # Check language standards
- # --------------------------------------------------------------------
- if language != info.language:
- raise FatalCheckError(
- '`%s` is not a %s compiler.' % (quote(*compiler), language))
- # Note: We do a strict version check because there sometimes are backwards
- # incompatible changes in the standard, and not all code that compiles as
- # C99 compiles as e.g. C11 (as of writing, this is true of libnestegg, for
- # example)
- if info.language == 'C' and info.language_version != 199901:
- if info.type in ('clang-cl', 'clang', 'gcc'):
- append_flag('-std=gnu99')
- # Note: MSVC, while supporting C++11, still reports 199711L for __cplusplus.
- # Note: this is a strict version check because we used to always add
- # -std=gnu++11.
- if info.language == 'C++':
- if info.type in ('clang', 'gcc') and info.language_version != 201103:
- append_flag('-std=gnu++11')
- # MSVC 2015 headers include C++14 features, but don't guard them
- # with appropriate checks.
- if info.type == 'clang-cl' and info.language_version != 201402:
- append_flag('-std=c++14')
- # We force clang-cl to emulate Visual C++ 2015 Update 3 with fallback to
- # cl.exe.
- if info.type == 'clang-cl' and info.version != '19.00.24213':
- # Those flags are direct clang-cl flags that don't need -Xclang, add
- # them directly.
- flags.append('-fms-compatibility-version=19.00.24213')
- flags.append('-fallback')
- # Check compiler target
- # --------------------------------------------------------------------
- if not info.cpu or info.cpu != target.cpu:
- if info.type == 'clang':
- append_flag('--target=%s' % target.toolchain)
- elif info.type == 'gcc':
- same_arch_different_bits = (
- ('x86', 'x86_64'),
- ('ppc', 'ppc64'),
- ('sparc', 'sparc64'),
- )
- if (target.cpu, info.cpu) in same_arch_different_bits:
- append_flag('-m32')
- elif (info.cpu, target.cpu) in same_arch_different_bits:
- append_flag('-m64')
- if not info.kernel or info.kernel != target.kernel:
- if info.type == 'clang':
- append_flag('--target=%s' % target.toolchain)
- if not info.endianness or info.endianness != target.endianness:
- if info.type == 'clang':
- append_flag('--target=%s' % target.toolchain)
- return namespace(
- type=info.type,
- version=info.version,
- target_cpu=info.cpu,
- target_kernel=info.kernel,
- target_endianness=info.endianness,
- flags=flags,
- )
- @imports(_from='collections', _import='defaultdict')
- @imports(_from='__builtin__', _import='sorted')
- def get_vc_paths(base):
- vc = defaultdict(lambda: defaultdict(dict))
- subkey = r'Microsoft\VisualStudio\VC\*\*\*\Compiler'
- for v, h, t, p in get_registry_values(base + '\\' + subkey):
- vc[v][h][t] = p
- if not vc:
- return
- version, data = sorted(vc.iteritems(), key=lambda x: Version(x[0]))[-1]
- return data
- @depends(host)
- @imports('platform')
- def vc_compiler_path(host):
- if host.kernel != 'WINNT':
- return
- vc_host = {
- 'x86': 'x86',
- 'AMD64': 'x64',
- }.get(platform.machine())
- if vc_host is None:
- return
- vc_target = {
- 'x86': 'x86',
- 'x86_64': 'x64',
- 'arm': 'arm',
- }.get(host.cpu)
- if vc_target is None:
- return
- base_key = r'HKEY_LOCAL_MACHINE\SOFTWARE'
- data = get_vc_paths(base_key)
- if not data:
- data = get_vc_paths(base_key + r'\Wow6432Node')
- if not data:
- return
- path = data.get(vc_host, {}).get(vc_target)
- if not path and vc_host == 'x64':
- vc_host = 'x86'
- path = data.get(vc_host, {}).get(vc_target)
- if not path:
- return
- path = os.path.dirname(path)
- if vc_host != vc_target:
- other_path = data.get(vc_host, {}).get(vc_host)
- if other_path:
- return (path, os.path.dirname(other_path))
- return (path,)
- @depends(vc_compiler_path)
- @imports('os')
- def toolchain_search_path(vc_compiler_path):
- if vc_compiler_path:
- result = [os.environ.get('PATH')]
- result.extend(vc_compiler_path)
- # We're going to alter PATH for good in windows.configure, but we also
- # need to do it for the valid_compiler() check below.
- os.environ['PATH'] = os.pathsep.join(result)
- return result
- @template
- def default_c_compilers(host_or_target):
- '''Template defining the set of default C compilers for the host and
- target platforms.
- `host_or_target` is either `host` or `target` (the @depends functions
- from init.configure.
- '''
- assert host_or_target in (host, target)
- @depends(host_or_target, target, toolchain_prefix)
- def default_c_compilers(host_or_target, target, toolchain_prefix):
- gcc = ('gcc',)
- if toolchain_prefix and host_or_target is target:
- gcc = tuple('%sgcc' % p for p in toolchain_prefix) + gcc
- if host_or_target.kernel == 'WINNT':
- return ('cl', 'clang-cl') + gcc + ('clang',)
- if host_or_target.kernel == 'Darwin':
- return ('clang',)
- return gcc + ('clang',)
- return default_c_compilers
- @template
- def default_cxx_compilers(c_compiler):
- '''Template defining the set of default C++ compilers for the host and
- target platforms.
- `c_compiler` is the @depends function returning a Compiler instance for
- the desired platform.
- Because the build system expects the C and C++ compilers to be from the
- same compiler suite, we derive the default C++ compilers from the C
- compiler that was found if none was provided.
- '''
- @depends(c_compiler)
- def default_cxx_compilers(c_compiler):
- dir = os.path.dirname(c_compiler.compiler)
- file = os.path.basename(c_compiler.compiler)
- if c_compiler.type == 'gcc':
- return (os.path.join(dir, file.replace('gcc', 'g++')),)
- if c_compiler.type == 'clang':
- return (os.path.join(dir, file.replace('clang', 'clang++')),)
- return (c_compiler.compiler,)
- return default_cxx_compilers
- @template
- def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
- other_c_compiler=None):
- '''Template handling the generic base checks for the compiler for the
- given `language` on the given platform (`host_or_target`).
- `host_or_target` is either `host` or `target` (the @depends functions
- from init.configure.
- When the language is 'C++', `c_compiler` is the result of the `compiler`
- template for the language 'C' for the same `host_or_target`.
- When `host_or_target` is `host`, `other_compiler` is the result of the
- `compiler` template for the same `language` for `target`.
- When `host_or_target` is `host` and the language is 'C++',
- `other_c_compiler` is the result of the `compiler` template for the
- language 'C' for `target`.
- '''
- assert host_or_target in (host, target)
- assert language in ('C', 'C++')
- assert language == 'C' or c_compiler
- assert host_or_target == target or other_compiler
- assert language == 'C' or host_or_target == target or other_c_compiler
- host_or_target_str = {
- host: 'host',
- target: 'target',
- }[host_or_target]
- var = {
- ('C', target): 'CC',
- ('C++', target): 'CXX',
- ('C', host): 'HOST_CC',
- ('C++', host): 'HOST_CXX',
- }[language, host_or_target]
- default_compilers = {
- 'C': lambda: default_c_compilers(host_or_target),
- 'C++': lambda: default_cxx_compilers(c_compiler),
- }[language]()
- what='the %s %s compiler' % (host_or_target_str, language)
- option(env=var, nargs=1, help='Path to %s' % what)
- # Handle the compiler given by the user through one of the CC/CXX/HOST_CC/
- # HOST_CXX variables.
- @depends_if(var)
- @imports(_from='itertools', _import='takewhile')
- @imports(_from='mozbuild.shellutil', _import='split', _as='shell_split')
- def provided_compiler(cmd):
- # Historically, the compiler variables have contained more than the
- # path to the compiler itself. So for backwards compatibility, try to
- # find what is what in there, assuming the first dash-prefixed item is
- # a compiler option, the item before that is the compiler, and anything
- # before that is a compiler wrapper.
- cmd = shell_split(cmd[0])
- without_flags = list(takewhile(lambda x: not x.startswith('-'), cmd))
- return namespace(
- wrapper=without_flags[:-1],
- compiler=without_flags[-1],
- flags=cmd[len(without_flags):],
- )
- # Derive the host compiler from the corresponding target compiler when no
- # explicit compiler was given and we're not cross compiling. For the C++
- # compiler, though, prefer to derive from the host C compiler when it
- # doesn't match the target C compiler.
- # As a special case, since clang supports all kinds of targets in the same
- # executable, when cross compiling with clang, default to the same compiler
- # as the target compiler, resetting flags.
- if host_or_target == host:
- args = (c_compiler, other_c_compiler) if other_c_compiler else ()
- @depends(provided_compiler, other_compiler, cross_compiling, *args)
- def provided_compiler(value, other_compiler, cross_compiling, *args):
- if value:
- return value
- c_compiler, other_c_compiler = args if args else (None, None)
- if not cross_compiling and c_compiler == other_c_compiler:
- return other_compiler
- if cross_compiling and other_compiler.type == 'clang':
- return namespace(**{
- k: [] if k == 'flags' else v
- for k, v in other_compiler.__dict__.iteritems()
- })
- # Normally, we'd use `var` instead of `_var`, but the interaction with
- # old-configure complicates things, and for now, we a) can't take the plain
- # result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
- # old-configure AC_SUBST it (because it's autoconf doing it, not us)
- compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
- input=delayed_getattr(provided_compiler, 'compiler'),
- paths=toolchain_search_path)
- @depends(compiler, provided_compiler, compiler_wrapper, host_or_target)
- @checking('whether %s can be used' % what, lambda x: bool(x))
- @imports(_from='mozbuild.shellutil', _import='quote')
- def valid_compiler(compiler, provided_compiler, compiler_wrapper,
- host_or_target):
- wrapper = list(compiler_wrapper or ())
- if provided_compiler:
- provided_wrapper = list(provided_compiler.wrapper)
- # When doing a subconfigure, the compiler is set by old-configure
- # and it contains the wrappers from --with-compiler-wrapper and
- # --with-ccache.
- if provided_wrapper[:len(wrapper)] == wrapper:
- provided_wrapper = provided_wrapper[len(wrapper):]
- wrapper.extend(provided_wrapper)
- flags = provided_compiler.flags
- else:
- flags = []
- # Ideally, we'd always use the absolute path, but unfortunately, on
- # Windows, the compiler is very often in a directory containing spaces.
- # Unfortunately, due to the way autoconf does its compiler tests with
- # eval, that doesn't work out. So in that case, check that the
- # compiler can still be found in $PATH, and use the file name instead
- # of the full path.
- if quote(compiler) != compiler:
- full_path = os.path.abspath(compiler)
- compiler = os.path.basename(compiler)
- found_compiler = find_program(compiler)
- if not found_compiler:
- die('%s is not in your $PATH'
- % quote(os.path.dirname(full_path)))
- if os.path.normcase(find_program(compiler)) != os.path.normcase(
- full_path):
- die('Found `%s` before `%s` in your $PATH. '
- 'Please reorder your $PATH.',
- quote(os.path.dirname(found_compiler)),
- quote(os.path.dirname(full_path)))
- info = check_compiler(wrapper + [compiler] + flags, language,
- host_or_target)
- # Check that the additional flags we got are enough to not require any
- # more flags.
- if info.flags:
- flags += info.flags
- info = check_compiler(wrapper + [compiler] + flags, language,
- host_or_target)
- if not info.target_cpu or info.target_cpu != host_or_target.cpu:
- raise FatalCheckError(
- '%s %s compiler target CPU (%s) does not match --%s CPU (%s)'
- % (host_or_target_str.capitalize(), language,
- info.target_cpu or 'unknown', host_or_target_str,
- host_or_target.raw_cpu))
- if not info.target_kernel or (info.target_kernel !=
- host_or_target.kernel):
- raise FatalCheckError(
- '%s %s compiler target kernel (%s) does not match --%s kernel (%s)'
- % (host_or_target_str.capitalize(), language,
- info.target_kernel or 'unknown', host_or_target_str,
- host_or_target.kernel))
- if not info.target_endianness or (info.target_endianness !=
- host_or_target.endianness):
- raise FatalCheckError(
- '%s %s compiler target endianness (%s) does not match --%s '
- 'endianness (%s)'
- % (host_or_target_str.capitalize(), language,
- info.target_endianness or 'unknown', host_or_target_str,
- host_or_target.endianness))
- if info.flags:
- raise FatalCheckError(
- 'Unknown compiler or compiler not supported.')
- # Compiler version checks
- # ===================================================
- # Check the compiler version here instead of in `compiler_version` so
- # that the `checking` message doesn't pretend the compiler can be used
- # to then bail out one line later.
- if info.type == 'gcc' and info.version < '4.9.0':
- raise FatalCheckError(
- 'Only GCC 4.9 or newer is supported (found version %s).'
- % info.version)
- # If you want to bump the version check here search for
- # __cpp_static_assert above, and see the associated comment.
- if info.type == 'clang' and not info.version:
- raise FatalCheckError(
- 'Only clang/llvm 3.6 or newer is supported.')
- if info.type == 'msvc':
- if info.version < '19.00.24213':
- raise FatalCheckError(
- 'This version (%s) of the MSVC compiler is not '
- 'supported.\n'
- 'You must install Visual C++ 2015 Update 3 or newer in '
- 'order to build.\n'
- 'See https://developer.mozilla.org/en/'
- 'Windows_Build_Prerequisites' % info.version)
- return namespace(
- wrapper=wrapper,
- compiler=compiler,
- flags=flags,
- type=info.type,
- version=info.version,
- language=language,
- )
- @depends(valid_compiler)
- @checking('%s version' % what)
- def compiler_version(compiler):
- return compiler.version
- if language == 'C++':
- @depends(valid_compiler, c_compiler)
- def valid_compiler(compiler, c_compiler):
- if compiler.type != c_compiler.type:
- die('The %s C compiler is %s, while the %s C++ compiler is '
- '%s. Need to use the same compiler suite.',
- host_or_target_str, c_compiler.type,
- host_or_target_str, compiler.type)
- if compiler.version != c_compiler.version:
- die('The %s C compiler is version %s, while the %s C++ '
- 'compiler is version %s. Need to use the same compiler '
- 'version.',
- host_or_target_str, c_compiler.version,
- host_or_target_str, compiler.version)
- return compiler
- # Set CC/CXX/HOST_CC/HOST_CXX for old-configure, which needs the wrapper
- # and the flags that were part of the user input for those variables to
- # be provided.
- add_old_configure_assignment(var, depends_if(valid_compiler)(
- lambda x: list(x.wrapper) + [x.compiler] + list(x.flags)))
- # Set CC_TYPE/CC_VERSION/HOST_CC_TYPE/HOST_CC_VERSION to allow
- # old-configure to do some of its still existing checks.
- if language == 'C':
- set_config(
- '%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
- add_old_configure_assignment(
- '%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
- add_old_configure_assignment(
- '%s_VERSION' % var, delayed_getattr(valid_compiler, 'version'))
- valid_compiler = compiler_class(valid_compiler)
- def compiler_error():
- raise FatalCheckError('Failed compiling a simple %s source with %s'
- % (language, what))
- valid_compiler.try_compile(check_msg='%s works' % what,
- onerror=compiler_error)
- # Set CPP/CXXCPP for both the build system and old-configure. We don't
- # need to check this works for preprocessing, because we already relied
- # on $CC -E/$CXX -E doing preprocessing work to validate the compiler
- # in the first place.
- if host_or_target == target:
- pp_var = {
- 'C': 'CPP',
- 'C++': 'CXXCPP',
- }[language]
- preprocessor = depends_if(valid_compiler)(
- lambda x: list(x.wrapper) + [x.compiler, '-E'] + list(x.flags))
- set_config(pp_var, preprocessor)
- add_old_configure_assignment(pp_var, preprocessor)
- return valid_compiler
- c_compiler = compiler('C', target)
- cxx_compiler = compiler('C++', target, c_compiler=c_compiler)
- host_c_compiler = compiler('C', host, other_compiler=c_compiler)
- host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler,
- other_compiler=cxx_compiler,
- other_c_compiler=c_compiler)
- # Generic compiler-based conditions.
- non_msvc_compiler = depends(c_compiler)(lambda info: info.type != 'msvc')
- building_with_gcc = depends(c_compiler)(lambda info: info.type == 'gcc')
- include('compile-checks.configure')
- @depends(have_64_bit,
- try_compile(body='static_assert(sizeof(void *) == 8, "")',
- check_msg='for 64-bit OS'))
- def check_have_64_bit(have_64_bit, compiler_have_64_bit):
- if have_64_bit != compiler_have_64_bit:
- configure_error('The target compiler does not agree with configure '
- 'about the target bitness.')
- @depends(c_compiler)
- def default_debug_flags(compiler_info):
- # Debug info is ON by default.
- if compiler_info.type in ('msvc', 'clang-cl'):
- return '-Zi'
- return '-g'
- option(env='MOZ_DEBUG_FLAGS',
- nargs=1,
- help='Debug compiler flags')
- imply_option('--enable-debug-symbols',
- depends_if('--enable-debug')(lambda v: v))
- js_option('--enable-debug-symbols',
- nargs='?',
- default=True,
- help='Enable debug symbols using the given compiler flags')
- set_config('MOZ_DEBUG_SYMBOLS',
- depends_if('--enable-debug-symbols')(lambda _: True))
- @depends('MOZ_DEBUG_FLAGS', '--enable-debug-symbols', default_debug_flags)
- def debug_flags(env_debug_flags, enable_debug_flags, default_debug_flags):
- # If MOZ_DEBUG_FLAGS is set, and --enable-debug-symbols is set to a value,
- # --enable-debug-symbols takes precedence. Note, the value of
- # --enable-debug-symbols may be implied by --enable-debug.
- if len(enable_debug_flags):
- return enable_debug_flags[0]
- if env_debug_flags:
- return env_debug_flags[0]
- return default_debug_flags
- set_config('MOZ_DEBUG_FLAGS', debug_flags)
- add_old_configure_assignment('MOZ_DEBUG_FLAGS', debug_flags)
- # Some standard library headers (notably bionic on Android) declare standard
- # functions (e.g. getchar()) and also #define macros for those standard
- # functions. libc++ deals with this by doing something like the following
- # (explanatory comments added):
- #
- # #ifdef FUNC
- # // Capture the definition of FUNC.
- # inline _LIBCPP_INLINE_VISIBILITY int __libcpp_FUNC(...) { return FUNC(...); }
- # #undef FUNC
- # // Use a real inline definition.
- # inline _LIBCPP_INLINE_VISIBILITY int FUNC(...) { return _libcpp_FUNC(...); }
- # #endif
- #
- # _LIBCPP_INLINE_VISIBILITY is typically defined as:
- #
- # __attribute__((__visibility__("hidden"), __always_inline__))
- #
- # Unfortunately, this interacts badly with our system header wrappers, as the:
- #
- # #pragma GCC visibility push(default)
- #
- # that they do prior to including the actual system header is treated by the
- # compiler as an explicit declaration of visibility on every function declared
- # in the header. Therefore, when the libc++ code above is encountered, it is
- # as though the compiler has effectively seen:
- #
- # int FUNC(...) __attribute__((__visibility__("default")));
- # int FUNC(...) __attribute__((__visibility__("hidden")));
- #
- # and the compiler complains about the mismatched visibility declarations.
- #
- # However, libc++ will only define _LIBCPP_INLINE_VISIBILITY if there is no
- # existing definition. We can therefore define it to the empty string (since
- # we are properly managing visibility ourselves) and avoid this whole mess.
- # Note that we don't need to do this with gcc, as libc++ detects gcc and
- # effectively does the same thing we are doing here.
- @depends(c_compiler, target)
- def libcxx_inline_visibility(c_compiler, target):
- if c_compiler.type == 'clang' and target.os == 'Android':
- return ''
- set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
- set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
- @depends(c_compiler, target, check_build_environment)
- def visibility_flags(c_compiler, target, env):
- if target.os != 'WINNT':
- if target.kernel == 'Darwin':
- return ('-fvisibility=hidden', '-fvisibility-inlines-hidden')
- return ('-I%s/system_wrappers' % os.path.join(env.dist),
- '-include',
- '%s/config/gcc_hidden.h' % env.topsrcdir)
- @depends(target, visibility_flags)
- def wrap_system_includes(target, visibility_flags):
- if visibility_flags and target.kernel != 'Darwin':
- return True
- set_define('HAVE_VISIBILITY_HIDDEN_ATTRIBUTE',
- depends(visibility_flags)(lambda v: bool(v) or None))
- set_define('HAVE_VISIBILITY_ATTRIBUTE',
- depends(visibility_flags)(lambda v: bool(v) or None))
- set_config('WRAP_SYSTEM_INCLUDES', wrap_system_includes)
- set_config('VISIBILITY_FLAGS', visibility_flags)
- include('windows.configure')
|