зеркало из https://github.com/mozilla/gecko-dev.git
370 строки
14 KiB
Python
370 строки
14 KiB
Python
# -*- Mode: python; 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/.
|
|
|
|
# cbindgen is needed by the style system build.
|
|
cbindgen = check_prog('CBINDGEN', ['cbindgen'], paths=toolchain_search_path,
|
|
when=depends(build_project)
|
|
(lambda build_project: build_project != 'js'))
|
|
|
|
|
|
@depends_if(cbindgen)
|
|
@checking('cbindgen version')
|
|
@imports(_from='textwrap', _import='dedent')
|
|
def cbindgen_version(cbindgen):
|
|
cbindgen_min_version = Version('0.6.8')
|
|
|
|
# cbindgen x.y.z
|
|
version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1])
|
|
|
|
if version < cbindgen_min_version:
|
|
die(dedent('''\
|
|
cbindgen version {} is too old. At least version {} is required.
|
|
|
|
Please update using 'cargo install cbindgen --force' or running
|
|
'./mach bootstrap', after removing the existing executable located at
|
|
{}.
|
|
'''.format(version, cbindgen_min_version, cbindgen)))
|
|
|
|
return version
|
|
|
|
|
|
# Bindgen can use rustfmt to format Rust file, but it's not required.
|
|
js_option(env='RUSTFMT', nargs=1, help='Path to the rustfmt program')
|
|
|
|
rustfmt = check_prog('RUSTFMT', ['rustfmt'], paths=toolchain_search_path,
|
|
input='RUSTFMT', allow_missing=True)
|
|
|
|
|
|
# We support setting up the appropriate options for bindgen via setting
|
|
# LLVM_CONFIG or by providing explicit configure options. The Windows
|
|
# installer of LLVM/Clang doesn't provide llvm-config, so we need both
|
|
# methods to support all of our tier-1 platforms.
|
|
@depends(host)
|
|
@imports('os')
|
|
def llvm_config_paths(host):
|
|
llvm_supported_versions = ['6.0', '5.0', '4.0', '3.9']
|
|
llvm_config_progs = []
|
|
for version in llvm_supported_versions:
|
|
llvm_config_progs += [
|
|
'llvm-config-%s' % version,
|
|
'llvm-config-mp-%s' % version, # MacPorts' chosen naming scheme.
|
|
'llvm-config%s' % version.replace('.', ''),
|
|
]
|
|
llvm_config_progs.append('llvm-config')
|
|
|
|
# Homebrew on macOS doesn't make clang available on PATH, so we have to
|
|
# look for it in non-standard places.
|
|
if host.kernel == 'Darwin':
|
|
brew = find_program('brew')
|
|
if brew:
|
|
brew_config = check_cmd_output(brew, 'config').strip()
|
|
|
|
for line in brew_config.splitlines():
|
|
if line.startswith('HOMEBREW_PREFIX'):
|
|
fields = line.split(None, 2)
|
|
prefix = fields[1] if len(fields) == 2 else ''
|
|
path = ['opt', 'llvm', 'bin', 'llvm-config']
|
|
llvm_config_progs.append(os.path.join(prefix, *path))
|
|
break
|
|
|
|
# Also add in the location to which `mach bootstrap` or
|
|
# `mach artifact toolchain` installs clang.
|
|
mozbuild_state_dir = os.environ.get('MOZBUILD_STATE_PATH',
|
|
os.path.expanduser(os.path.join('~', '.mozbuild')))
|
|
bootstrap_llvm_config = os.path.join(mozbuild_state_dir, 'clang', 'bin', 'llvm-config')
|
|
|
|
llvm_config_progs.append(bootstrap_llvm_config)
|
|
|
|
return llvm_config_progs
|
|
|
|
js_option(env='LLVM_CONFIG', nargs=1, help='Path to llvm-config')
|
|
|
|
llvm_config = check_prog('LLVM_CONFIG', llvm_config_paths, input='LLVM_CONFIG',
|
|
what='llvm-config', allow_missing=True)
|
|
|
|
js_option('--with-libclang-path', nargs=1,
|
|
help='Absolute path to a directory containing Clang/LLVM libraries for bindgen (version 3.9.x or above)')
|
|
js_option('--with-clang-path', nargs=1,
|
|
help='Absolute path to a Clang binary for bindgen (version 3.9.x or above)')
|
|
|
|
def invoke_llvm_config(llvm_config, *options):
|
|
'''Invoke llvm_config with the given options and return the first line of
|
|
output.'''
|
|
lines = check_cmd_output(llvm_config, *options).splitlines()
|
|
return lines[0]
|
|
|
|
@imports(_from='textwrap', _import='dedent')
|
|
def check_minimum_llvm_config_version(llvm_config):
|
|
version = Version(invoke_llvm_config(llvm_config, '--version'))
|
|
min_version = Version('3.9.0')
|
|
if version < min_version:
|
|
die(dedent('''\
|
|
llvm installation {} is incompatible with bindgen.
|
|
|
|
Please install version {} or greater of Clang + LLVM
|
|
and ensure that the 'llvm-config' from that
|
|
installation is first on your path.
|
|
|
|
You can verify this by typing 'llvm-config --version'.
|
|
'''.format(version, min_version)))
|
|
|
|
@depends(llvm_config, '--with-libclang-path', '--with-clang-path',
|
|
host_library_name_info, host, build_project)
|
|
@imports('os.path')
|
|
@imports('glob')
|
|
@imports(_from='textwrap', _import='dedent')
|
|
def bindgen_config_paths(llvm_config, libclang_path, clang_path,
|
|
library_name_info, host, build_project):
|
|
def search_for_libclang(path):
|
|
# Try to ensure that the clang shared library that bindgen is going
|
|
# to look for is actually present. The files that we search for
|
|
# mirror the logic in clang-sys/build.rs.
|
|
libclang_choices = []
|
|
if host.os == 'WINNT':
|
|
libclang_choices.append('libclang.dll')
|
|
libclang_choices.append('%sclang%s' % (library_name_info.dll.prefix,
|
|
library_name_info.dll.suffix))
|
|
if host.kernel == 'Linux':
|
|
libclang_choices.append('libclang.so.1')
|
|
|
|
if host.os == 'OpenBSD':
|
|
libclang_choices = glob.glob(path + '/libclang.so.*.*')
|
|
|
|
# At least one of the choices must be found.
|
|
for choice in libclang_choices:
|
|
libclang = os.path.join(path, choice)
|
|
if os.path.exists(libclang):
|
|
return (True, None)
|
|
else:
|
|
return (False, list(set(libclang_choices)))
|
|
|
|
# XXX: we want this code to be run for both Gecko and JS, but we don't
|
|
# necessarily want to force a bindgen/Rust dependency on JS just yet.
|
|
# Actually, we don't want to force an error if we're not building the
|
|
# browser generally. We therefore whitelist the projects that require
|
|
# bindgen facilities at this point and leave it at that.
|
|
bindgen_projects = ('browser', 'mobile/android')
|
|
|
|
if not libclang_path and not clang_path:
|
|
# We must have LLVM_CONFIG in this case.
|
|
if not llvm_config:
|
|
if build_project not in bindgen_projects:
|
|
return namespace()
|
|
|
|
die(dedent('''\
|
|
Could not find LLVM/Clang installation for compiling bindgen.
|
|
Please specify the 'LLVM_CONFIG' environment variable
|
|
(recommended), pass the '--with-libclang-path' and '--with-clang-path'
|
|
options to configure, or put 'llvm-config' in your PATH. Altering your
|
|
PATH may expose 'clang' as well, potentially altering your compiler,
|
|
which may not be what you intended.'''))
|
|
|
|
check_minimum_llvm_config_version(llvm_config)
|
|
libclang_arg = '--bindir' if host.os == 'WINNT' else '--libdir'
|
|
libclang_path = invoke_llvm_config(llvm_config, libclang_arg)
|
|
clang_path = os.path.join(invoke_llvm_config(llvm_config, '--bindir'),
|
|
'clang')
|
|
libclang_path = normsep(libclang_path)
|
|
clang_path = normsep(clang_path)
|
|
|
|
# Debian-based distros, at least, can have llvm-config installed
|
|
# but not have other packages installed. Since the user is trying
|
|
# to use their system packages, we can't be more specific about what
|
|
# they need.
|
|
clang_resolved = find_program(clang_path)
|
|
if not clang_resolved:
|
|
die(dedent('''\
|
|
The file {} returned by `llvm-config {}` does not exist.
|
|
clang is required to build Firefox. Please install the
|
|
necessary packages, or run `mach bootstrap`.
|
|
'''.format(clang_path, '--bindir')))
|
|
|
|
if not os.path.exists(libclang_path):
|
|
die(dedent('''\
|
|
The directory {} returned by `llvm-config {}` does not exist.
|
|
clang is required to build Firefox. Please install the
|
|
necessary packages, or run `mach bootstrap`.
|
|
'''.format(libclang_path, libclang_arg)))
|
|
|
|
(found, searched) = search_for_libclang(libclang_path)
|
|
if not found:
|
|
die(dedent('''\
|
|
Could not find the clang shared library in the path {}
|
|
returned by `llvm-config {}` (searched for files {}).
|
|
clang is required to build Firefox. Please install the
|
|
necessary packages, or run `mach bootstrap`.
|
|
'''.format(libclang_path, libclang_arg, searched)))
|
|
|
|
return namespace(
|
|
libclang_path=libclang_path,
|
|
clang_path=clang_resolved,
|
|
)
|
|
|
|
if (not libclang_path and clang_path) or \
|
|
(libclang_path and not clang_path):
|
|
if build_project not in bindgen_projects:
|
|
return namespace()
|
|
|
|
die(dedent('''\
|
|
You must provide both of --with-libclang-path and --with-clang-path
|
|
or neither of them.'''))
|
|
|
|
libclang_path = libclang_path[0]
|
|
clang_path = clang_path[0]
|
|
|
|
if not os.path.exists(libclang_path) or \
|
|
not os.path.isdir(libclang_path):
|
|
die(dedent('''\
|
|
The argument to --with-libclang-path is not a directory: {}
|
|
'''.format(libclang_path)))
|
|
|
|
(found, searched) = search_for_libclang(libclang_path)
|
|
if not found:
|
|
die(dedent('''\
|
|
Could not find the clang shared library in the path {}
|
|
specified by --with-libclang-path (searched for files {}).
|
|
'''.format(libclang_path, searched)))
|
|
|
|
clang_resolved = find_program(clang_path)
|
|
if not clang_resolved:
|
|
die(dedent('''\
|
|
The argument to --with-clang-path is not a file: {}
|
|
'''.format(clang_path)))
|
|
|
|
return namespace(
|
|
libclang_path=libclang_path,
|
|
clang_path=clang_resolved,
|
|
)
|
|
|
|
set_config('MOZ_LIBCLANG_PATH', bindgen_config_paths.libclang_path)
|
|
set_config('MOZ_CLANG_PATH', bindgen_config_paths.clang_path)
|
|
|
|
|
|
@depends(host, target, target_is_unix, c_compiler, bindgen_cflags_android)
|
|
def basic_bindgen_cflags(host, target, is_unix, compiler_info, android_cflags):
|
|
args = [
|
|
'-x', 'c++', '-std=gnu++14', '-fno-sized-deallocation',
|
|
'-DTRACING=1', '-DIMPL_LIBXUL', '-DMOZILLA_INTERNAL_API',
|
|
'-DRUST_BINDGEN'
|
|
]
|
|
|
|
if is_unix:
|
|
args += ['-DOS_POSIX=1']
|
|
|
|
if target.os == 'Android':
|
|
args += android_cflags
|
|
|
|
def handle_cpu(obj):
|
|
if 'cpu' in obj and target.cpu in obj['cpu']:
|
|
return obj['cpu'][target.cpu]
|
|
return []
|
|
|
|
if target.os == 'WINNT' and host.raw_os.startswith('gnu'):
|
|
args += handle_cpu({
|
|
'cpu': {
|
|
'x86': ['--target=i686-pc-mingw32'],
|
|
'x86_64': ['--target=x86_64-w64-mingw32'],
|
|
},
|
|
})
|
|
|
|
os_dict = {
|
|
'Android': {
|
|
'default': ['-DOS_ANDROID=1'],
|
|
'cpu': {
|
|
'aarch64': ['--target=aarch64-linux-android'],
|
|
'arm': ['--target=armv7-linux-androideabi'],
|
|
'x86': ['--target=i686-linux-android'],
|
|
'x86_64': ['--target=x86_64-linux-android'],
|
|
},
|
|
},
|
|
'DragonFly': {
|
|
'default': ['-DOS_BSD=1', '-DOS_DRAGONFLY=1'],
|
|
},
|
|
'FreeBSD': {
|
|
'default': ['-DOS_BSD=1', '-DOS_FREEBSD=1'],
|
|
},
|
|
'GNU': {
|
|
'default': ['-DOS_LINUX=1'],
|
|
'cpu': {
|
|
'x86': ['-m32'],
|
|
'x86_64': ['-m64'],
|
|
},
|
|
},
|
|
'NetBSD': {
|
|
'default': ['-DOS_BSD=1', '-DOS_NETBSD=1'],
|
|
},
|
|
'OpenBSD': {
|
|
'default': ['-DOS_BSD=1', '-DOS_OPENBSD=1'],
|
|
},
|
|
'OSX': {
|
|
'default': [
|
|
'-DOS_MACOSX=1',
|
|
'-stdlib=libc++',
|
|
# To disable the fixup bindgen applies which adds search
|
|
# paths from clang command line in order to avoid potential
|
|
# conflict with -stdlib=libc++.
|
|
'--target=x86_64-apple-darwin',
|
|
],
|
|
},
|
|
'SunOS': {
|
|
'default': ['-DOS_SOLARIS=1'],
|
|
},
|
|
'WINNT': {
|
|
'default': [
|
|
'-DOS_WIN=1',
|
|
'-DWIN32=1',
|
|
],
|
|
'compiler': {
|
|
'msvc': {
|
|
'default': [
|
|
# To enable the builtin __builtin_offsetof so that CRT wouldn't
|
|
# use reinterpret_cast in offsetof() which is not allowed inside
|
|
# static_assert().
|
|
'-D_CRT_USE_BUILTIN_OFFSETOF',
|
|
# Enable hidden attribute (which is not supported by MSVC and
|
|
# thus not enabled by default with a MSVC-compatibile build)
|
|
# to exclude hidden symbols from the generated file.
|
|
'-DHAVE_VISIBILITY_HIDDEN_ATTRIBUTE=1',
|
|
],
|
|
'cpu': {
|
|
'x86': ['--target=i686-pc-win32'],
|
|
'x86_64': ['--target=x86_64-pc-win32'],
|
|
'aarch64': ['--target=aarch64-pc-windows-msvc'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}.get(target.os, {})
|
|
|
|
if 'default' in os_dict:
|
|
args += os_dict['default']
|
|
|
|
args += handle_cpu(os_dict)
|
|
if 'compiler' in os_dict and compiler_info and compiler_info in os_dict['compiler']:
|
|
compiler_dict = os_dict['compiler'].get(compiler_info)
|
|
if 'default' in compiler_dict:
|
|
args += compiler_dict['default']
|
|
args += handle_cpu(compiler_dict)
|
|
|
|
return args
|
|
|
|
|
|
js_option(env='BINDGEN_CFLAGS',
|
|
nargs=1,
|
|
help='Options bindgen should pass to the C/C++ parser')
|
|
|
|
|
|
@depends(basic_bindgen_cflags, 'BINDGEN_CFLAGS')
|
|
@checking('bindgen cflags', lambda s: s if s else 'no')
|
|
def bindgen_cflags(base_flags, extra_flags):
|
|
flags = base_flags
|
|
if extra_flags and len(extra_flags):
|
|
flags += extra_flags[0].split()
|
|
return ' '.join(flags)
|
|
|
|
|
|
add_old_configure_assignment('_BINDGEN_CFLAGS', bindgen_cflags)
|