Source code

Revision control

Other Tools

# -*- 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
# Note:
# - Gecko-specific options and rules should go in toolkit/moz.configure.
# - Firefox-specific options and rules should go in browser/moz.configure.
# - Fennec-specific options and rules should go in
# mobile/android/moz.configure.
# - Spidermonkey-specific options and rules should go in js/moz.configure.
# - etc.
option('--enable-artifact-builds', env='MOZ_ARTIFACT_BUILDS',
help='Download and use prebuilt binary artifacts.')
def artifact_builds(value):
if value:
return True
set_config('MOZ_ARTIFACT_BUILDS', artifact_builds)
depends(artifact_builds)(lambda v: False if v is None else None),
option('--enable-artifact-build-symbols', nargs='?', choices=('full',),
help='Download symbols when artifact builds are enabled.')
@depends('--enable-artifact-build-symbols', 'MOZ_AUTOMATION', target)
def enable_artifact_build_symbols(value, automation, target):
if len(value):
return value[0]
if bool(value):
if target.os == 'Android' and not automation:
return 'full'
return True
return None
def imply_disable_compile_environment(value):
if value:
return False
help='For builds that do not support symbols in the normal fashion,'
' generate and copy them into the resulting build archive.')
set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
imply_option('--enable-compile-environment', imply_disable_compile_environment)
help='Disable compiler/library checks')
def compile_environment(compile_env):
if compile_env:
return True
set_config('COMPILE_ENVIRONMENT', compile_environment)
add_old_configure_assignment('COMPILE_ENVIRONMENT', compile_environment)
help='Do not build test libraries & programs')
def enable_tests(value):
if value:
return True
set_config('ENABLE_TESTS', enable_tests)
set_define('ENABLE_TESTS', enable_tests)
def gtest_has_rtti(value):
if value:
return '0'
set_define('GTEST_HAS_RTTI', gtest_has_rtti)
@depends(target, enable_tests)
def linux_gtest_defines(target, enable_tests):
if enable_tests and target.os == 'Android':
return namespace(os_linux_android=True,
help='Enable building with developer debug info '
'(using the given compiler flags).')
def moz_debug(debug):
if debug:
return bool(debug)
set_config('MOZ_DEBUG', moz_debug)
set_define('MOZ_DEBUG', moz_debug)
# Override any value MOZ_DEBUG may have from the environment when passing it
# down to old-configure.
depends('--enable-debug')(lambda x: bool(x)))
js_option('--with-debug-label', nargs='+',
help='Debug DEBUG_<value> for each comma-separated value given')
@depends(moz_debug, '--with-debug-label')
def debug_defines(debug, labels):
if debug:
return ['DEBUG'] + ['DEBUG_%s' % label for label in labels]
return ['NDEBUG', 'TRIMMED']
set_config('MOZ_DEBUG_DEFINES', debug_defines)
default=depends(when='--enable-debug')(lambda: True),
help='{Build|Do not build} Rust code with debug assertions turned '
def debug_rust():
return True
set_config('MOZ_DEBUG_RUST', debug_rust)
set_define('MOZ_DEBUG_RUST', debug_rust)
js_option(env='MOZ_PGO', help='Build with profile guided optimizations')
set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
wine = check_prog(
'WINE', ['wine64', 'wine'], allow_missing=True,
when=depends(target, host)(
lambda t, h: t.kernel == 'WINNT' and h.kernel != 'WINNT'))
# Make this assignment here rather than in pkg.configure to avoid
# requiring this file in unit tests.
add_old_configure_assignment('PKG_CONFIG', pkg_config)
# rust.configure is included by js/moz.configure.
help='Enable Valgrind integration hooks')
valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
@depends('--enable-valgrind', valgrind_h)
def check_valgrind(valgrind, valgrind_h):
if valgrind:
if not valgrind_h:
die('--enable-valgrind specified but Valgrind is not installed')
return True
set_define('MOZ_VALGRIND', check_valgrind)
set_config('MOZ_VALGRIND', check_valgrind)
@depends(target, host)
def is_openbsd(target, host):
return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
help='Shared library version for OpenBSD systems')
@depends('SO_VERSION', when=is_openbsd)
def so_version(value):
return value
def library_name_info_template(host_or_target):
assert host_or_target in {host, target}
compiler = {
host: host_c_compiler,
target: c_compiler,
@depends(host_or_target, compiler, so_version)
def library_name_info_impl(host_or_target, compiler, so_version):
if host_or_target.kernel == 'WINNT':
# There aren't artifacts for mingw builds, so it's OK that the
# results are inaccurate in that case.
if compiler and compiler.type != 'clang-cl':
return namespace(
dll=namespace(prefix='', suffix='.dll'),
lib=namespace(prefix='lib', suffix='a'),
import_lib=namespace(prefix='lib', suffix='a'),
rust_lib=namespace(prefix='', suffix='lib'),
obj=namespace(prefix='', suffix='o'),
return namespace(
dll=namespace(prefix='', suffix='.dll'),
lib=namespace(prefix='', suffix='lib'),
import_lib=namespace(prefix='', suffix='lib'),
rust_lib=namespace(prefix='', suffix='lib'),
obj=namespace(prefix='', suffix='obj'),
elif host_or_target.kernel == 'Darwin':
return namespace(
dll=namespace(prefix='lib', suffix='.dylib'),
lib=namespace(prefix='lib', suffix='a'),
import_lib=namespace(prefix=None, suffix=''),
rust_lib=namespace(prefix='lib', suffix='a'),
obj=namespace(prefix='', suffix='o'),
elif so_version:
so = '.so.%s' % so_version
so = '.so'
return namespace(
dll=namespace(prefix='lib', suffix=so),
lib=namespace(prefix='lib', suffix='a'),
import_lib=namespace(prefix=None, suffix=''),
rust_lib=namespace(prefix='lib', suffix='a'),
obj=namespace(prefix='', suffix='o'),
return library_name_info_impl
host_library_name_info = library_name_info_template(host)
library_name_info = library_name_info_template(target)
set_config('DLL_PREFIX', library_name_info.dll.prefix)
set_config('DLL_SUFFIX', library_name_info.dll.suffix)
set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
set_config('LIB_PREFIX', library_name_info.lib.prefix)
set_config('LIB_SUFFIX', library_name_info.lib.suffix)
set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
# Lots of compilation tests depend on this variable being present.
add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
set_config('WASM_OBJ_SUFFIX', 'wasm')
# Make `profiling` available to this file even when js/moz.configure
# doesn't end up included.
profiling = dependable(False)
# Same for js_standalone
js_standalone = dependable(False)
# Same for fold_libs
fold_libs = dependable(False)
@imports(_from='mozbuild.backend', _import='backends')
def build_backends_choices(_):
return tuple(backends)
@deprecated_option('--enable-build-backend', nargs='+',
def build_backend(backends):
if backends:
return tuple('+%s' % b for b in backends)
imply_option('--build-backends', build_backend)
@depends('--enable-artifact-builds', '--disable-compile-environment',
'--enable-build-backend', '--enable-project', '--enable-application',
def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
project, application, _):
if application:
project = application[0]
elif project:
project = project[0]
if 'Tup' in requested_backends:
# As a special case, if Tup was requested, do not combine it with any
# Make based backend by default.
all_backends = []
elif artifact_builds:
all_backends = ['FasterMake+RecursiveMake']
all_backends = ['RecursiveMake', 'FasterMake']
# Normally, we'd use target.os == 'WINNT', but a dependency on target
# would require target to depend on --help, as well as host and shell,
# and this is not a can of worms we can open at the moment.
if sys.platform == 'win32' and compile_environment and project != 'mobile/android':
return tuple(all_backends) or None
option('--build-backends', nargs='+', default=build_backend_defaults,
choices=build_backends_choices, help='Build backends to generate')
def build_backends(backends):
return backends
set_config('BUILD_BACKENDS', build_backends)
@depends(check_build_environment, build_backends)
def check_objdir_backend_reuse(build_env, backends):
# "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
# intentionally vague for use with the substring match below.
incompatible_backends = (
('Tup', 'Make'),
('Make', 'Tup')
for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
for prev, curr in incompatible_backends:
if prev in backend_file and any(curr in b for b in backends):
die("The active objdir, %s, was previously "
"used to build with a %s based backend. "
"Change objdirs (by setting MOZ_OBJDIR in "
"your mozconfig) or clobber to continue.\n",
build_env.topobjdir, prev)
help='Force disable building the gtest libxul during the build.',
# Determine whether to build the gtest xul. This happens in automation
# on Android and Desktop platforms with the exception of:
# - Windows PGO, where linking xul-gtest.dll takes too long;
# - Android other than x86_64, where gtest is not required.
@depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
enable_tests, when='--enable-compile-environment')
def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
if not enable_tests or not enabled:
return None
if (automation and build_project in ('browser', 'comm/mail', 'mobile/android') and
not ((pgo and target.os == 'WINNT') or (target.os == 'Android' and target.cpu != 'x86_64'))):
return True
set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
# Localization
# ==============================================================
option('--enable-ui-locale', default='en-US',
help='Select the user interface locale (default: en-US)')
set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
# clang-plugin location
# ==============================================================
@depends(host_library_name_info, check_build_environment,
def clang_plugin_path(library_name_info, build_env):
topobjdir = build_env.topobjdir
if topobjdir.endswith('/js/src'):
topobjdir = topobjdir[:-7]
return os.path.abspath(
os.path.join(topobjdir, 'build', 'clang-plugin',
'%sclang-plugin%s' % (library_name_info.dll.prefix,
add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
# Awk detection
# ==============================================================
awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
# Until the AWK variable is not necessary in old-configure
def awk_for_old_configure(value):
return value
add_old_configure_assignment('AWK', awk_for_old_configure)
# Perl detection
# ==============================================================
perl = check_prog('PERL', ('perl5', 'perl'))
# Until the PERL variable is not necessary in old-configure
def perl_for_old_configure(value):
return value
add_old_configure_assignment('PERL', perl_for_old_configure)
def perl_version_check(min_version):
@checking('for minimum required perl version >= %s' % min_version)
def get_perl_version(perl):
return Version(check_cmd_output(
perl, '-e', 'print $]',
onerror=lambda: die('Failed to get perl version.')
def check_perl_version(version):
if version < min_version:
die('Perl %s or higher is required.', min_version)
@checking('for full perl installation')
def has_full_perl_installation(perl):
ret =
[perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
return ret == 0
def require_full_perl_installation(has_full_perl_installation):
if not has_full_perl_installation:
die('Cannot find or $Config{archlib}. '
'A full perl installation is required.')
# GNU make detection
# ==============================================================
option(env='MAKE', nargs=1, help='Path to GNU make')
@depends('MAKE', host)
def possible_makes(make, host):
candidates = []
if host.kernel == 'WINNT':
if make:
if host.kernel == 'WINNT':
candidates.extend(('make', 'gmake'))
candidates.extend(('gmake', 'make'))
return candidates
check_prog('GMAKE', possible_makes)
# watchman detection
# ==============================================================
option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
@depends(host, 'WATCHMAN')
@checking('for watchman', callback=lambda w: w.path if w else 'not found')
def watchman(host, prog):
# On Windows, `watchman` is only supported on 64-bit hosts.
if host.os == 'WINNT' and host.cpu != 'x86_64':
if not prog:
prog = find_program('watchman')
if not prog:
# `watchman version` will talk to the Watchman daemon service.
# This can hang due to permissions problems. e.g.
# `watchman --version` to prevent a class of failures.
out = check_cmd_output(prog, '--version', onerror=lambda: None)
if out is None:
return namespace(path=prog, version=Version(out.strip()))
@checking('for watchman version')
def watchman_version(w):
return w.version
set_config('WATCHMAN', watchman.path)
@depends_all(hg_version, hg_config, watchman)
@checking('for watchman Mercurial integration')
def watchman_hg(hg_version, hg_config, watchman):
if hg_version < Version('3.8'):
return 'no (Mercurial 3.8+ required)'
ext_enabled = False
mode_disabled = False
for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
if k in hg_config and hg_config[k] != '!':
ext_enabled = True
mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
if not ext_enabled:
return 'no (fsmonitor extension not enabled)'
if mode_disabled:
return 'no (fsmonitor.mode=off disables fsmonitor)'
return True
# Miscellaneous programs
# ==============================================================
check_prog('XARGS', ('xargs',))
def extra_programs(target):
if target.kernel == 'Darwin':
return namespace(
DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
if target.os == 'GNU' and target.kernel == 'Linux':
return namespace(RPMBUILD=('rpmbuild',))
check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
check_prog('MKFSHFS', extra_programs.MKFSHFS,
check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
check_prog('RPMBUILD', extra_programs.RPMBUILD,
def makensis_progs(target):
if target.kernel != 'WINNT':
candidates = [
# Look for nsis installed by msys environment. But only the 32-bit version.
# We use an absolute path and insert as the first entry so it is preferred
# over a 64-bit exe that may be in PATH.
if 'MSYSTEM_PREFIX' in os.environ:
prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
return tuple(candidates)
nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
# Make sure the version of makensis is up to date.
@depends(nsis, wine)
@checking('for NSIS version')
def nsis_version(nsis, wine):
if not nsis:
return None
nsis_min_version = '3.0b1'
onerror = lambda: die('Failed to get nsis version.')
if wine and nsis.lower().endswith('.exe'):
out = check_cmd_output(wine, nsis, '-version', onerror=onerror)
out = check_cmd_output(nsis, '-version', onerror=onerror)
m ='(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
if not m:
raise FatalCheckError('Unknown version of makensis')
ver = Version(
# Versions comparisons don't quite work well with beta versions, so ensure
# it works for the non-beta version.
if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
raise FatalCheckError('To build the installer you must have NSIS'
' version %s or greater in your path'
% nsis_min_version)
return ver
# And that makensis is 32-bit (but only on Windows).
@depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
@checking('for 32-bit NSIS')
def nsis_binary_type(nsis):
bin_type = windows_binary_type(nsis)
if bin_type != 'win32':
raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
return 'yes'
# And any flags we have to give to makensis
def nsis_flags(host):
if host.kernel != 'WINNT':
return '-nocd'
return ''
set_config('MAKENSISU_FLAGS', nsis_flags)
check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
check_prog('UPX', ('upx',), allow_missing=True, when=target_is_windows)
@depends(host_c_compiler, c_compiler, bindgen_config_paths)
def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
clang = None
for compiler in (host_c_compiler, c_compiler):
if compiler and compiler.type == 'clang':
clang = compiler.compiler
elif compiler and compiler.type == 'clang-cl':
clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
if not clang and bindgen_config_paths:
clang = bindgen_config_paths.clang_path
llvm_objdump = 'llvm-objdump'
if clang:
out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
onerror=lambda: None)
if out:
llvm_objdump = out.rstrip()
return (llvm_objdump,)
llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
js_option('--enable-dtrace', help='Build with dtrace support')
dtrace = check_header('sys/sdt.h', when='--enable-dtrace',
onerror=lambda: die('dtrace enabled but sys/sdt.h not found'))
set_config('HAVE_DTRACE', True, when=dtrace)
set_define('INCLUDE_MOZILLA_DTRACE', True, when=dtrace)
add_old_configure_assignment('enable_dtrace', 'yes', when=dtrace)
js_option('--disable-icf', help='Disable Identical Code Folding')
'MOZ_DISABLE_ICF', '1', when=depends('--enable-icf')(lambda x: not x))
@depends(compile_environment, target)
def may_strip(compile_environment, target):
return compile_environment and target.kernel != 'WINNT'
js_option('--enable-strip', when=may_strip, help='Enable stripping of libs & executables')
set_config('ENABLE_STRIP', True, when='--enable-strip')
js_option('--disable-install-strip', when=may_strip,
help='Enable stripping of libs & executables when packaging')
# The nested depends is because depending on --enable-install-strip needs the
# `when=may_strip`, but we also need to test when may_strip is False.
@depends(depends('--enable-install-strip', when=may_strip)(lambda x: x), may_strip)
def pkg_skip_strip(install_strip, may_strip):
return not install_strip or not may_strip
set_config('PKG_SKIP_STRIP', True, when=pkg_skip_strip)
@depends('--enable-strip', '--enable-install-strip', when=may_strip)
def strip(strip, install_strip):
return strip or install_strip
js_option(env='STRIP_FLAGS', nargs=1, when=strip, help='Flags for the strip command')
@depends('STRIP_FLAGS', profiling, target, when=strip)
def strip_flags(flags, profiling, target):
if flags:
return flags[0].split()
if profiling:
# Only strip debug info and symbols when profiling is enabled, keeping
# local symbols.
if target.kernel == 'Darwin':
return ['-S']
return ['--strip-debug']
# Otherwise strip everything we can, which happens without flags on non-Darwin.
# On Darwin, it tries to strip things it can't, so we need to limit its scope.
elif target.kernel == 'Darwin':
return ['-x', '-S']
set_config('STRIP_FLAGS', strip_flags)
@depends(js_standalone, target)
def system_zlib_default(js_standalone, target):
return js_standalone and target.kernel != 'WINNT'
js_option('--with-system-zlib', nargs='?', default=system_zlib_default,
help='{Use|Do not use} system libz')
def deprecated_system_zlib_path(value):
if len(value) == 1:
die('--with-system-zlib=PATH is not supported anymore. Please use '
'--with-system-zlib and set any necessary pkg-config environment variable.')
pkg_check_modules('MOZ_ZLIB', 'zlib >= 1.2.3', when='--with-system-zlib')
set_config('MOZ_SYSTEM_ZLIB', True, when='--with-system-zlib')
add_old_configure_assignment('MOZ_SYSTEM_ZLIB', True, when='--with-system-zlib')
# Please do not add configure checks from here on.
# Fallthrough to autoconf-based configure
# JS Subconfigure.
include('js/sub.configure', when=compile_environment & toolkit)
@depends(check_build_environment, build_project)
@imports(_from='os.path', _import='exists')
def config_status_deps(build_env, build_project):
topsrcdir = build_env.topsrcdir
topobjdir = build_env.topobjdir
if not topobjdir.endswith('js/src'):
extra_deps = [os.path.join(topobjdir, '.mozconfig.json')]
# mozconfig changes may impact js configure.
extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
confvars = os.path.join(topsrcdir, build_project, '')
if exists(confvars):
return list(__sandbox__._all_paths) + extra_deps + [
os.path.join(topsrcdir, 'CLOBBER'),
os.path.join(topsrcdir, 'configure'),
os.path.join(topsrcdir, 'js', 'src', 'configure'),
os.path.join(topsrcdir, ''),
os.path.join(topsrcdir, 'js', 'src', ''),
os.path.join(topsrcdir, 'nsprpub', 'configure'),
os.path.join(topsrcdir, 'config', 'milestone.txt'),
os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', ''),
os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
os.path.join(topsrcdir, 'aclocal.m4'),
os.path.join(topsrcdir, ''),
os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
os.path.join(topsrcdir, 'js', 'src', ''),
] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
set_config('CONFIG_STATUS_DEPS', config_status_deps)
# Please do not add anything after setting config_dep_paths.