2016-03-24 02:36:23 +03:00
|
|
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
|
|
|
# vim: set filetype=python:
|
|
|
|
# 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/.
|
|
|
|
|
|
|
|
# yasm detection
|
|
|
|
# ==============================================================
|
|
|
|
yasm = check_prog('YASM', ['yasm'], allow_missing=True)
|
|
|
|
|
2016-03-24 09:26:32 +03:00
|
|
|
@depends_if(yasm)
|
2016-03-24 02:36:23 +03:00
|
|
|
@checking('yasm version')
|
|
|
|
def yasm_version(yasm):
|
2016-05-18 00:40:03 +03:00
|
|
|
version = check_cmd_output(
|
|
|
|
yasm, '--version',
|
|
|
|
onerror=lambda: die('Failed to get yasm version.')
|
|
|
|
).splitlines()[0].split()[1]
|
|
|
|
return version
|
2016-03-24 02:36:23 +03:00
|
|
|
|
|
|
|
# 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)
|
2016-03-25 15:14:59 +03:00
|
|
|
|
|
|
|
|
2016-04-02 05:23:40 +03:00
|
|
|
# Android NDK
|
|
|
|
# ==============================================================
|
|
|
|
|
|
|
|
@depends('--disable-compile-environment', build_project, '--help')
|
|
|
|
def android_ndk_include(compile_env, build_project, _):
|
|
|
|
if compile_env and build_project in ('mobile/android', 'js'):
|
|
|
|
return 'android-ndk.configure'
|
|
|
|
|
|
|
|
include(android_ndk_include)
|
|
|
|
|
|
|
|
|
2016-04-21 02:11:32 +03:00
|
|
|
# MacOS deployment target version
|
|
|
|
# ==============================================================
|
|
|
|
# This needs to happen before any compilation test is done.
|
|
|
|
|
|
|
|
option('--enable-macos-target', env='MACOSX_DEPLOYMENT_TARGET', nargs=1,
|
2016-05-03 19:58:15 +03:00
|
|
|
default='10.7', help='Set the minimum MacOS version needed at runtime')
|
2016-04-21 02:11:32 +03:00
|
|
|
|
|
|
|
@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)
|
|
|
|
|
|
|
|
|
2016-03-25 15:14:59 +03:00
|
|
|
# Compiler wrappers
|
|
|
|
# ==============================================================
|
2016-04-05 04:56:42 +03:00
|
|
|
# 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')
|
2016-03-25 15:14:59 +03:00
|
|
|
|
2016-04-05 04:56:42 +03:00
|
|
|
option('--with-ccache', env='CCACHE', nargs='?',
|
|
|
|
help='Enable compiling with ccache')
|
2016-03-25 15:14:59 +03:00
|
|
|
|
|
|
|
@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)
|
2016-03-27 05:40:13 +03:00
|
|
|
@imports(_from='mozbuild.shellutil', _import='split', _as='shell_split')
|
2016-03-25 15:14:59 +03:00
|
|
|
def compiler_wrapper(wrapper, ccache):
|
2016-04-05 08:05:59 +03:00
|
|
|
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
|
|
|
|
|
2016-03-25 15:14:59 +03:00
|
|
|
if ccache:
|
|
|
|
if wrapper:
|
2016-04-05 08:05:59 +03:00
|
|
|
return tuple([ccache] + wrapper)
|
2016-03-25 15:14:59 +03:00
|
|
|
else:
|
|
|
|
return (ccache,)
|
|
|
|
elif wrapper:
|
2016-04-05 08:05:59 +03:00
|
|
|
return tuple(wrapper)
|
2016-03-25 15:14:59 +03:00
|
|
|
|
|
|
|
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)
|
2016-03-30 08:47:13 +03:00
|
|
|
|
|
|
|
|
|
|
|
# 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 value[0]
|
|
|
|
# Special case x86-64 <-> x86 cross compiling until we have the right tests
|
|
|
|
# in moz.configure land.
|
|
|
|
if cross_compiling and not all(i.cpu in ('x86_64', 'x86')
|
|
|
|
for i in (target, host)):
|
|
|
|
return '%s-' % target.toolchain
|
|
|
|
|
2016-04-02 05:23:40 +03:00
|
|
|
set_config('TOOLCHAIN_PREFIX', toolchain_prefix)
|
2016-03-30 08:47:13 +03:00
|
|
|
add_old_configure_assignment('TOOLCHAIN_PREFIX', toolchain_prefix)
|
2016-04-05 04:56:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
# Compilers
|
|
|
|
# ==============================================================
|
|
|
|
@imports('os')
|
|
|
|
@imports('subprocess')
|
|
|
|
@imports(_from='mozbuild.configure.util', _import='LineIO')
|
|
|
|
@imports(_from='tempfile', _import='mkstemp')
|
2016-04-06 05:32:03 +03:00
|
|
|
def try_preprocess(compiler, language, source):
|
2016-04-05 04:56:42 +03:00
|
|
|
suffix = {
|
|
|
|
'C': '.c',
|
|
|
|
'C++': '.cpp',
|
|
|
|
}[language]
|
|
|
|
|
|
|
|
fd, path = mkstemp(prefix='conftest.', suffix=suffix)
|
|
|
|
try:
|
2016-04-06 05:32:03 +03:00
|
|
|
source = source.encode('ascii', 'replace')
|
2016-04-05 04:56:42 +03:00
|
|
|
|
|
|
|
log.debug('Creating `%s` with content:', path)
|
|
|
|
with LineIO(lambda l: log.debug('| %s', l)) as out:
|
|
|
|
out.write(source)
|
|
|
|
|
|
|
|
os.write(fd, source)
|
|
|
|
os.close(fd)
|
|
|
|
cmd = compiler + ['-E', path]
|
2016-05-18 00:40:03 +03:00
|
|
|
return check_cmd_output(*cmd)
|
2016-04-05 04:56:42 +03:00
|
|
|
finally:
|
|
|
|
os.remove(path)
|
|
|
|
|
|
|
|
|
2016-04-06 05:32:03 +03:00
|
|
|
@imports(_from='mozbuild.configure.constants', _import='CompilerType')
|
|
|
|
@imports(_from='textwrap', _import='dedent')
|
2016-04-06 11:18:07 +03:00
|
|
|
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.
|
2016-04-19 09:09:10 +03:00
|
|
|
# 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.4).
|
|
|
|
# Normally, we'd use __has_feature, but there are unfortunately no C++11
|
|
|
|
# differences in clang 3.4. However, it supports the 2013-08-28 draft of
|
|
|
|
# the ISO WG21 SG10 feature test macro recommendations, and thus exposes
|
|
|
|
# new __cpp_* macros that older clang versions didn't.
|
|
|
|
# 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.
|
2016-04-06 05:32:03 +03:00
|
|
|
check = dedent('''\
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#if defined(__clang__)
|
2016-04-06 11:18:07 +03:00
|
|
|
%COMPILER clang-cl
|
2016-04-19 09:55:36 +03:00
|
|
|
%VERSION _MSC_FULL_VER
|
2016-04-06 05:32:03 +03:00
|
|
|
#else
|
2016-04-06 11:18:07 +03:00
|
|
|
%COMPILER msvc
|
|
|
|
%VERSION _MSC_FULL_VER
|
2016-04-06 05:32:03 +03:00
|
|
|
#endif
|
|
|
|
#elif defined(__clang__)
|
2016-04-06 11:18:07 +03:00
|
|
|
%COMPILER clang
|
2016-04-19 09:09:10 +03:00
|
|
|
# if !__cplusplus || __cpp_static_assert
|
2016-04-06 11:18:07 +03:00
|
|
|
%VERSION __clang_major__.__clang_minor__.__clang_patchlevel__
|
2016-04-19 09:09:10 +03:00
|
|
|
# endif
|
2016-04-06 05:32:03 +03:00
|
|
|
#elif defined(__GNUC__)
|
2016-04-06 11:18:07 +03:00
|
|
|
%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
|
2016-04-06 05:32:03 +03:00
|
|
|
#endif
|
|
|
|
''')
|
|
|
|
|
|
|
|
result = try_preprocess(compiler, language, check)
|
|
|
|
|
2016-04-06 11:18:07 +03:00
|
|
|
if not result:
|
|
|
|
raise FatalCheckError(
|
|
|
|
'Unknown compiler or compiler not supported.')
|
|
|
|
|
|
|
|
data = {}
|
|
|
|
for line in result.splitlines():
|
|
|
|
if line.startswith('%'):
|
|
|
|
k, _, v = line.partition(' ')
|
|
|
|
k = k.lstrip('%')
|
|
|
|
data[k] = v.replace(' ', '')
|
|
|
|
log.debug('%s = %s', k, data[k])
|
|
|
|
|
2016-04-19 10:03:07 +03:00
|
|
|
try:
|
|
|
|
type = CompilerType(data['COMPILER'])
|
|
|
|
except:
|
2016-04-06 11:18:07 +03:00
|
|
|
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'))
|
|
|
|
|
2016-04-19 10:03:07 +03:00
|
|
|
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)
|
|
|
|
|
2016-04-06 11:18:07 +03:00
|
|
|
return namespace(
|
2016-04-19 10:03:07 +03:00
|
|
|
type=type,
|
|
|
|
version=version,
|
2016-04-06 11:18:07 +03:00
|
|
|
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):
|
|
|
|
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++' and info.language_version != 201103:
|
|
|
|
if info.type in ('clang-cl', 'clang', 'gcc'):
|
|
|
|
append_flag('-std=gnu++11')
|
|
|
|
|
2016-04-19 09:55:36 +03:00
|
|
|
# We force clang-cl to emulate Visual C++ 2013 Update 3 with fallback to
|
|
|
|
# cl.exe.
|
2016-04-19 10:03:07 +03:00
|
|
|
if info.type == 'clang-cl' and info.version != '18.00.30723':
|
2016-04-19 09:55:36 +03:00
|
|
|
# Those flags are direct clang-cl flags that don't need -Xclang, add
|
|
|
|
# them directly.
|
|
|
|
flags.append('-fms-compatibility-version=18.00.30723')
|
|
|
|
flags.append('-fallback')
|
|
|
|
|
2016-04-22 03:24:32 +03:00
|
|
|
return namespace(
|
|
|
|
type=info.type,
|
|
|
|
version=info.version,
|
|
|
|
flags=flags,
|
|
|
|
)
|
2016-04-06 05:32:03 +03:00
|
|
|
|
|
|
|
|
2016-04-05 04:56:42 +03:00
|
|
|
@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, host, toolchain_prefix)
|
|
|
|
def default_c_compilers(host_or_target, host, toolchain_prefix):
|
|
|
|
if host_or_target.kernel == 'WINNT':
|
|
|
|
return ('cl', 'clang-cl', 'gcc', 'clang')
|
|
|
|
if host_or_target.kernel == 'Darwin':
|
|
|
|
return ('clang',)
|
|
|
|
if host_or_target != host: # cross compilation
|
|
|
|
return ('%sgcc' % toolchain_prefix, 'gcc', '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
|
2016-04-22 02:00:11 +03:00
|
|
|
def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
|
|
|
other_c_compiler=None):
|
2016-04-05 04:56:42 +03:00
|
|
|
'''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.
|
2016-04-22 02:00:11 +03:00
|
|
|
When the language is 'C++', `c_compiler` is the result of the `compiler`
|
2016-04-05 04:56:42 +03:00
|
|
|
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`.
|
2016-04-22 02:00:11 +03:00
|
|
|
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`.
|
2016-04-05 04:56:42 +03:00
|
|
|
'''
|
|
|
|
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
|
2016-04-22 02:00:11 +03:00
|
|
|
assert language == 'C' or host_or_target == target or other_c_compiler
|
2016-04-05 04:56:42 +03:00
|
|
|
|
|
|
|
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):],
|
|
|
|
)
|
|
|
|
|
2016-04-22 02:00:11 +03:00
|
|
|
# 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.
|
|
|
|
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):
|
2016-04-05 04:56:42 +03:00
|
|
|
if value:
|
|
|
|
return value
|
2016-04-22 02:00:11 +03:00
|
|
|
c_compiler, other_c_compiler = args if args else (None, None)
|
|
|
|
if not cross_compiling and c_compiler == other_c_compiler:
|
2016-04-05 04:56:42 +03:00
|
|
|
return other_compiler
|
|
|
|
|
|
|
|
# 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'))
|
|
|
|
|
|
|
|
@depends(compiler, provided_compiler, compiler_wrapper)
|
2016-04-06 11:18:07 +03:00
|
|
|
@checking('whether %s can be used' % what, lambda x: bool(x))
|
2016-04-05 04:56:42 +03:00
|
|
|
@imports(_from='mozbuild.shellutil', _import='quote')
|
|
|
|
def valid_compiler(compiler, provided_compiler, compiler_wrapper):
|
|
|
|
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)))
|
|
|
|
|
2016-04-22 03:24:32 +03:00
|
|
|
info = check_compiler(wrapper + [compiler] + flags, language)
|
2016-04-19 08:48:19 +03:00
|
|
|
|
|
|
|
# Check that the additional flags we got are enough to not require any
|
|
|
|
# more flags.
|
2016-04-22 03:24:32 +03:00
|
|
|
if info.flags:
|
|
|
|
flags += info.flags
|
|
|
|
info = check_compiler(wrapper + [compiler] + flags, language)
|
2016-04-19 08:48:19 +03:00
|
|
|
|
2016-04-22 03:24:32 +03:00
|
|
|
if info.flags:
|
2016-04-19 08:48:19 +03:00
|
|
|
raise FatalCheckError(
|
|
|
|
'Unknown compiler or compiler not supported.')
|
|
|
|
|
2016-04-19 09:09:10 +03:00
|
|
|
# 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.
|
2016-04-22 03:24:32 +03:00
|
|
|
if info.type == 'gcc' and info.version < '4.8.0':
|
2016-04-19 09:09:10 +03:00
|
|
|
raise FatalCheckError(
|
|
|
|
'Only GCC 4.8 or newer is supported (found version %s).'
|
2016-04-22 03:24:32 +03:00
|
|
|
% info.version)
|
2016-04-19 09:09:10 +03:00
|
|
|
|
|
|
|
# If you want to bump the version check here search for
|
|
|
|
# __cpp_static_assert above, and see the associated comment.
|
2016-04-22 03:24:32 +03:00
|
|
|
if info.type == 'clang' and not info.version:
|
2016-04-19 09:09:10 +03:00
|
|
|
raise FatalCheckError(
|
|
|
|
'Only clang/llvm 3.4 or newer is supported.')
|
|
|
|
|
2016-04-22 03:24:32 +03:00
|
|
|
if info.type == 'msvc':
|
|
|
|
if info.version < '18.00.30723' or (
|
|
|
|
'19' < info.version < '19.00.23506'):
|
2016-04-19 09:09:10 +03:00
|
|
|
raise FatalCheckError(
|
|
|
|
'This version (%s) of the MSVC compiler is not '
|
|
|
|
'supported.\n'
|
|
|
|
'You must install Visual C++ 2013 Update 3, Visual '
|
|
|
|
'C++ 2015 Update 1, or newer in order to build.\n'
|
|
|
|
'See https://developer.mozilla.org/en/'
|
2016-04-22 03:24:32 +03:00
|
|
|
'Windows_Build_Prerequisites' % info.version)
|
2016-04-19 09:09:10 +03:00
|
|
|
|
2016-04-06 11:18:07 +03:00
|
|
|
return namespace(
|
|
|
|
wrapper=wrapper,
|
|
|
|
compiler=compiler,
|
2016-04-19 08:48:19 +03:00
|
|
|
flags=flags,
|
2016-04-22 03:24:32 +03:00
|
|
|
type=info.type,
|
|
|
|
version=info.version,
|
2016-04-06 11:18:07 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
@depends(valid_compiler)
|
|
|
|
@checking('%s version' % what)
|
|
|
|
def compiler_version(compiler):
|
|
|
|
return compiler.version
|
2016-04-05 04:56:42 +03:00
|
|
|
|
|
|
|
if language == 'C++':
|
|
|
|
@depends(valid_compiler, c_compiler)
|
2016-04-20 07:56:55 +03:00
|
|
|
def valid_compiler(compiler, c_compiler):
|
2016-04-05 04:56:42 +03:00
|
|
|
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)
|
2016-04-20 07:56:55 +03:00
|
|
|
return compiler
|
2016-04-05 04:56:42 +03:00
|
|
|
|
|
|
|
# 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':
|
|
|
|
add_old_configure_assignment(
|
|
|
|
'%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
|
|
|
|
add_old_configure_assignment(
|
|
|
|
'%s_VERSION' % var, delayed_getattr(valid_compiler, 'version'))
|
|
|
|
|
|
|
|
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,
|
2016-04-22 02:00:11 +03:00
|
|
|
other_compiler=cxx_compiler,
|
|
|
|
other_c_compiler=c_compiler)
|