1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2 # vim: set filetype=python:
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 include('build/moz.configure/init.configure')
10 # - Gecko-specific options and rules should go in toolkit/moz.configure.
11 # - Firefox-specific options and rules should go in browser/moz.configure.
12 # - Fennec-specific options and rules should go in
13 # mobile/android/moz.configure.
14 # - Spidermonkey-specific options and rules should go in js/moz.configure.
17 option('--enable-artifact-builds', env='MOZ_ARTIFACT_BUILDS',
18 help='Download and use prebuilt binary artifacts.')
20 @depends('--enable-artifact-builds')
21 def artifact_builds(value):
25 set_config('MOZ_ARTIFACT_BUILDS', artifact_builds)
27 imply_option('--enable-artifact-build-symbols',
28 depends(artifact_builds)(lambda v: False if v is None else None),
29 reason='--disable-artifact-builds')
31 option('--enable-artifact-build-symbols', nargs='?', choices=('full',),
32 help='Download symbols when artifact builds are enabled.')
34 @depends('--enable-artifact-build-symbols', 'MOZ_AUTOMATION', target)
35 def enable_artifact_build_symbols(value, automation, target):
39 if target.os == 'Android' and not automation:
44 set_config('MOZ_ARTIFACT_BUILD_SYMBOLS',
45 enable_artifact_build_symbols)
47 @depends('--enable-artifact-builds')
48 def imply_disable_compile_environment(value):
52 option(env='MOZ_COPY_PDBS',
53 help='For builds that do not support symbols in the normal fashion,'
54 ' generate and copy them into the resulting build archive.')
56 set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
58 imply_option('--enable-compile-environment', imply_disable_compile_environment)
60 option('--disable-compile-environment',
61 help='Disable compiler/library checks')
63 @depends('--disable-compile-environment')
64 def compile_environment(compile_env):
68 set_config('COMPILE_ENVIRONMENT', compile_environment)
69 add_old_configure_assignment('COMPILE_ENVIRONMENT', compile_environment)
71 js_option('--disable-tests',
72 help='Do not build test libraries & programs')
74 @depends('--disable-tests')
75 def enable_tests(value):
79 set_config('ENABLE_TESTS', enable_tests)
80 set_define('ENABLE_TESTS', enable_tests)
82 @depends(enable_tests)
83 def gtest_has_rtti(value):
87 set_define('GTEST_HAS_RTTI', gtest_has_rtti)
89 @depends(target, enable_tests)
90 def linux_gtest_defines(target, enable_tests):
91 if enable_tests and target.os == 'Android':
92 return namespace(os_linux_android=True,
93 use_own_tr1_tuple=True,
96 set_define('GTEST_OS_LINUX_ANDROID',
97 linux_gtest_defines.os_linux_android)
98 set_define('GTEST_USE_OWN_TR1_TUPLE',
99 linux_gtest_defines.use_own_tr1_tuple)
100 set_define('GTEST_HAS_CLONE',
101 linux_gtest_defines.has_clone)
103 js_option('--enable-debug',
105 help='Enable building with developer debug info '
106 '(using the given compiler flags).')
108 @depends('--enable-debug')
109 def moz_debug(debug):
113 set_config('MOZ_DEBUG', moz_debug)
114 set_define('MOZ_DEBUG', moz_debug)
115 # Override any value MOZ_DEBUG may have from the environment when passing it
116 # down to old-configure.
117 add_old_configure_assignment('MOZ_DEBUG',
118 depends('--enable-debug')(lambda x: bool(x)))
120 js_option('--enable-rust-debug',
121 default=depends(when='--enable-debug')(lambda: True),
122 help='{Build|Do not build} Rust code with debug assertions turned '
125 @depends(when='--enable-rust-debug')
129 set_config('MOZ_DEBUG_RUST', debug_rust)
130 set_define('MOZ_DEBUG_RUST', debug_rust)
132 js_option(env='MOZ_PGO', help='Build with profile guided optimizations')
134 set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
136 include('build/moz.configure/toolchain.configure',
137 when='--enable-compile-environment')
139 include('build/moz.configure/pkg.configure')
140 # Make this assignment here rather than in pkg.configure to avoid
141 # requiring this file in unit tests.
142 add_old_configure_assignment('PKG_CONFIG', pkg_config)
144 include('build/moz.configure/memory.configure',
145 when='--enable-compile-environment')
146 include('build/moz.configure/headers.configure',
147 when='--enable-compile-environment')
148 include('build/moz.configure/warnings.configure',
149 when='--enable-compile-environment')
150 include('build/moz.configure/flags.configure',
151 when='--enable-compile-environment')
152 # rust.configure is included by js/moz.configure.
154 js_option('--enable-valgrind',
155 help='Enable Valgrind integration hooks')
157 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
159 @depends('--enable-valgrind', valgrind_h)
160 def check_valgrind(valgrind, valgrind_h):
163 die('--enable-valgrind specified but Valgrind is not installed')
166 set_define('MOZ_VALGRIND', check_valgrind)
167 set_config('MOZ_VALGRIND', check_valgrind)
169 @depends(target, host)
170 def is_openbsd(target, host):
171 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
173 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
174 help='Shared library version for OpenBSD systems')
176 @depends('SO_VERSION', when=is_openbsd)
177 def so_version(value):
181 def library_name_info_template(host_or_target):
182 assert host_or_target in {host, target}
184 host: host_c_compiler,
188 @depends(host_or_target, compiler, so_version)
189 def library_name_info_impl(host_or_target, compiler, so_version):
190 if host_or_target.kernel == 'WINNT':
191 # There aren't artifacts for mingw builds, so it's OK that the
192 # results are inaccurate in that case.
193 if compiler and compiler.type != 'clang-cl':
195 dll=namespace(prefix='', suffix='.dll'),
196 lib=namespace(prefix='lib', suffix='a'),
197 import_lib=namespace(prefix='lib', suffix='a'),
198 rust_lib=namespace(prefix='', suffix='lib'),
199 obj=namespace(prefix='', suffix='o'),
203 dll=namespace(prefix='', suffix='.dll'),
204 lib=namespace(prefix='', suffix='lib'),
205 import_lib=namespace(prefix='', suffix='lib'),
206 rust_lib=namespace(prefix='', suffix='lib'),
207 obj=namespace(prefix='', suffix='obj'),
210 elif host_or_target.kernel == 'Darwin':
212 dll=namespace(prefix='lib', suffix='.dylib'),
213 lib=namespace(prefix='lib', suffix='a'),
214 import_lib=namespace(prefix=None, suffix=''),
215 rust_lib=namespace(prefix='lib', suffix='a'),
216 obj=namespace(prefix='', suffix='o'),
219 so = '.so.%s' % so_version
224 dll=namespace(prefix='lib', suffix=so),
225 lib=namespace(prefix='lib', suffix='a'),
226 import_lib=namespace(prefix=None, suffix=''),
227 rust_lib=namespace(prefix='lib', suffix='a'),
228 obj=namespace(prefix='', suffix='o'),
231 return library_name_info_impl
233 host_library_name_info = library_name_info_template(host)
234 library_name_info = library_name_info_template(target)
236 set_config('DLL_PREFIX', library_name_info.dll.prefix)
237 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
238 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
239 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
240 set_config('LIB_PREFIX', library_name_info.lib.prefix)
241 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
242 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
243 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
244 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
245 # Lots of compilation tests depend on this variable being present.
246 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
247 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
248 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
249 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
250 set_config('WASM_OBJ_SUFFIX', 'wasm')
252 include(include_project_configure)
255 @imports(_from='mozbuild.backend', _import='backends')
256 def build_backends_choices(_):
257 return tuple(backends)
260 @deprecated_option('--enable-build-backend', nargs='+',
261 choices=build_backends_choices)
262 def build_backend(backends):
264 return tuple('+%s' % b for b in backends)
266 imply_option('--build-backends', build_backend)
269 @depends('--enable-artifact-builds', '--disable-compile-environment',
270 '--enable-build-backend', '--enable-project', '--enable-application',
273 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
274 project, application, _):
276 project = application[0]
280 if 'Tup' in requested_backends:
281 # As a special case, if Tup was requested, do not combine it with any
282 # Make based backend by default.
284 elif artifact_builds:
285 all_backends = ['FasterMake+RecursiveMake']
287 all_backends = ['RecursiveMake', 'FasterMake']
288 # Normally, we'd use target.os == 'WINNT', but a dependency on target
289 # would require target to depend on --help, as well as host and shell,
290 # and this is not a can of worms we can open at the moment.
291 if sys.platform == 'win32' and compile_environment and project != 'mobile/android':
292 all_backends.append('VisualStudio')
293 return tuple(all_backends) or None
295 option('--build-backends', nargs='+', default=build_backend_defaults,
296 choices=build_backends_choices, help='Build backends to generate')
298 @depends('--build-backends')
299 def build_backends(backends):
302 set_config('BUILD_BACKENDS', build_backends)
305 @depends(check_build_environment, build_backends)
307 def check_objdir_backend_reuse(build_env, backends):
308 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
309 # intentionally vague for use with the substring match below.
310 incompatible_backends = (
314 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
315 'backend.*Backend')):
316 for prev, curr in incompatible_backends:
317 if prev in backend_file and any(curr in b for b in backends):
318 die("The active objdir, %s, was previously "
319 "used to build with a %s based backend. "
320 "Change objdirs (by setting MOZ_OBJDIR in "
321 "your mozconfig) or clobber to continue.\n",
322 build_env.topobjdir, prev)
325 option('--disable-gtest-in-build',
326 help='Force disable building the gtest libxul during the build.',
327 when='--enable-compile-environment')
329 # Determine whether to build the gtest xul. This happens in automation
330 # on Android and Desktop platforms with the exception of:
331 # - Windows PGO, where linking xul-gtest.dll takes too long;
332 # - Android other than x86_64, where gtest is not required.
333 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
334 enable_tests, when='--enable-compile-environment')
335 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
336 if not enable_tests or not enabled:
338 if (automation and build_project in ('browser', 'comm/mail', 'mobile/android') and
339 not ((pgo and target.os == 'WINNT') or (target.os == 'Android' and target.cpu != 'x86_64'))):
342 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
345 # ==============================================================
346 option('--enable-ui-locale', default='en-US',
347 help='Select the user interface locale (default: en-US)')
349 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
351 # clang-plugin location
352 # ==============================================================
353 @depends(host_library_name_info, check_build_environment,
354 when='--enable-clang-plugin')
355 def clang_plugin_path(library_name_info, build_env):
356 topobjdir = build_env.topobjdir
357 if topobjdir.endswith('/js/src'):
358 topobjdir = topobjdir[:-7]
359 return os.path.abspath(
360 os.path.join(topobjdir, 'build', 'clang-plugin',
361 '%sclang-plugin%s' % (library_name_info.dll.prefix,
362 library_name_info.dll.suffix))
365 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
369 # ==============================================================
370 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
372 # Until the AWK variable is not necessary in old-configure
374 def awk_for_old_configure(value):
377 add_old_configure_assignment('AWK', awk_for_old_configure)
381 # ==============================================================
382 perl = check_prog('PERL', ('perl5', 'perl'))
384 # Until the PERL variable is not necessary in old-configure
386 def perl_for_old_configure(value):
389 add_old_configure_assignment('PERL', perl_for_old_configure)
392 def perl_version_check(min_version):
394 @checking('for minimum required perl version >= %s' % min_version)
395 def get_perl_version(perl):
396 return Version(check_cmd_output(
397 perl, '-e', 'print $]',
398 onerror=lambda: die('Failed to get perl version.')
401 @depends(get_perl_version)
402 def check_perl_version(version):
403 if version < min_version:
404 die('Perl %s or higher is required.', min_version)
407 @checking('for full perl installation')
408 @imports('subprocess')
409 def has_full_perl_installation(perl):
410 ret = subprocess.call(
411 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
414 @depends(has_full_perl_installation)
415 def require_full_perl_installation(has_full_perl_installation):
416 if not has_full_perl_installation:
417 die('Cannot find Config.pm or $Config{archlib}. '
418 'A full perl installation is required.')
420 perl_version_check('5.006')
424 # ==============================================================
425 option(env='MAKE', nargs=1, help='Path to GNU make')
427 @depends('MAKE', host)
428 def possible_makes(make, host):
430 if host.kernel == 'WINNT':
431 candidates.append('mingw32-make')
433 candidates.append(make[0])
434 if host.kernel == 'WINNT':
435 candidates.extend(('make', 'gmake'))
437 candidates.extend(('gmake', 'make'))
440 check_prog('GMAKE', possible_makes)
442 @depends(build_backends, build_project)
443 def tup_include(build_backends, build_project):
444 # We need to check the rustc version when building with tup, but
445 # rustc_info isn't available when configuring js (and build_backends isn't
446 # available from project-specific configure), so as a workaround we only
447 # include the file when we know we'll need it. This can be removed when
448 # we globally require a rustc recent enough to build with tup.
449 if build_project not in ('browser', 'mobile/android'):
451 for backend in build_backends:
453 return 'build/moz.configure/tup.configure'
458 # ==============================================================
460 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
462 @depends(host, 'WATCHMAN')
463 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
464 def watchman(host, prog):
465 # On Windows, `watchman` is only supported on 64-bit hosts.
466 if host.os == 'WINNT' and host.cpu != 'x86_64':
470 prog = find_program('watchman')
475 # `watchman version` will talk to the Watchman daemon service.
476 # This can hang due to permissions problems. e.g.
477 # https://github.com/facebook/watchman/issues/376. So use
478 # `watchman --version` to prevent a class of failures.
479 out = check_cmd_output(prog, '--version', onerror=lambda: None)
483 return namespace(path=prog, version=Version(out.strip()))
485 @depends_if(watchman)
486 @checking('for watchman version')
487 def watchman_version(w):
490 set_config('WATCHMAN', watchman.path)
492 @depends_all(hg_version, hg_config, watchman)
493 @checking('for watchman Mercurial integration')
495 def watchman_hg(hg_version, hg_config, watchman):
496 if hg_version < Version('3.8'):
497 return 'no (Mercurial 3.8+ required)'
500 mode_disabled = False
502 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
503 if k in hg_config and hg_config[k] != '!':
506 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
509 return 'no (fsmonitor extension not enabled)'
511 return 'no (fsmonitor.mode=off disables fsmonitor)'
515 # Miscellaneous programs
516 # ==============================================================
517 check_prog('XARGS', ('xargs',))
520 def extra_programs(target):
521 if target.kernel == 'Darwin':
523 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
524 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
525 HFS_TOOL=('hfsplus',)
527 if target.os == 'GNU' and target.kernel == 'Linux':
528 return namespace(RPMBUILD=('rpmbuild',))
530 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
532 check_prog('MKFSHFS', extra_programs.MKFSHFS,
534 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
536 check_prog('RPMBUILD', extra_programs.RPMBUILD,
542 def makensis_progs(target):
543 if target.kernel != 'WINNT':
553 # Look for nsis installed by msys environment. But only the 32-bit version.
554 # We use an absolute path and insert as the first entry so it is preferred
555 # over a 64-bit exe that may be in PATH.
556 if 'MSYSTEM_PREFIX' in os.environ:
557 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
558 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
560 return tuple(candidates)
562 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
564 # Make sure the version of makensis is up to date.
566 @checking('for NSIS version')
568 def nsis_version(nsis):
569 nsis_min_version = '3.0b1'
570 out = check_cmd_output(nsis, '-version',
571 onerror=lambda: die('Failed to get nsis version.'))
572 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
575 raise FatalCheckError('Unknown version of makensis')
576 ver = Version(m.group(0))
578 # Versions comparisons don't quite work well with beta versions, so ensure
579 # it works for the non-beta version.
580 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
581 raise FatalCheckError('To build the installer you must have NSIS'
582 ' version %s or greater in your path'
587 # And that makensis is 32-bit (but only on Windows).
588 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
589 @checking('for 32-bit NSIS')
590 def nsis_binary_type(nsis):
591 bin_type = windows_binary_type(nsis)
592 if bin_type != 'win32':
593 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
597 # And any flags we have to give to makensis
599 def nsis_flags(host):
600 if host.kernel != 'WINNT':
604 set_config('MAKENSISU_FLAGS', nsis_flags)
606 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
609 @depends(host_c_compiler, c_compiler, bindgen_config_paths)
610 def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
612 for compiler in (host_c_compiler, c_compiler):
613 if compiler and compiler.type == 'clang':
614 clang = compiler.compiler
616 elif compiler and compiler.type == 'clang-cl':
617 clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
620 if not clang and bindgen_config_paths:
621 clang = bindgen_config_paths.clang_path
622 llvm_objdump = 'llvm-objdump'
624 out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
625 onerror=lambda: None)
627 llvm_objdump = out.rstrip()
628 return (llvm_objdump,)
631 llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
632 when='--enable-compile-environment',
633 paths=toolchain_search_path)
635 add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
638 option('--enable-forkserver', env='MOZ_ENABLE_FORKSERVER', help='Enable fork server')
640 @depends('--enable-forkserver', target)
641 def forkserver_flag(value, target):
642 if target.os == 'Android' or \
643 (target.os == 'GNU' and target.kernel == 'Linux') or \
644 target.os == 'FreeBSD':
648 set_config('MOZ_ENABLE_FORKSERVER', forkserver_flag)
649 set_define('MOZ_ENABLE_FORKSERVER', forkserver_flag, forkserver_flag)
652 # Please do not add configure checks from here on.
654 # Fallthrough to autoconf-based configure
655 include('build/moz.configure/old.configure')
658 include('js/sub.configure', when=compile_environment & toolkit)
661 @depends(check_build_environment, build_project)
662 @imports('__sandbox__')
664 @imports(_from='os.path', _import='exists')
665 def config_status_deps(build_env, build_project):
667 topsrcdir = build_env.topsrcdir
668 topobjdir = build_env.topobjdir
670 if not topobjdir.endswith('js/src'):
671 extra_deps = [os.path.join(topobjdir, '.mozconfig.json')]
673 # mozconfig changes may impact js configure.
674 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
676 confvars = os.path.join(topsrcdir, build_project, 'confvars.sh')
678 extra_deps.append(confvars)
680 return list(__sandbox__._all_paths) + extra_deps + [
681 os.path.join(topsrcdir, 'CLOBBER'),
682 os.path.join(topsrcdir, 'configure'),
683 os.path.join(topsrcdir, 'js', 'src', 'configure'),
684 os.path.join(topsrcdir, 'configure.in'),
685 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
686 os.path.join(topsrcdir, 'nsprpub', 'configure'),
687 os.path.join(topsrcdir, 'config', 'milestone.txt'),
688 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
689 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
690 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
691 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
692 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
693 os.path.join(topsrcdir, 'aclocal.m4'),
694 os.path.join(topsrcdir, 'old-configure.in'),
695 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
696 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
697 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
699 set_config('CONFIG_STATUS_DEPS', config_status_deps)
700 # Please do not add anything after setting config_dep_paths.