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)))
138 'WINE', ['wine64', 'wine'], allow_missing=True,
139 when=depends(target, host)(
140 lambda t, h: t.kernel == 'WINNT' and h.kernel == 'Linux'))
143 include('build/moz.configure/toolchain.configure',
144 when='--enable-compile-environment')
146 include('build/moz.configure/pkg.configure')
147 # Make this assignment here rather than in pkg.configure to avoid
148 # requiring this file in unit tests.
149 add_old_configure_assignment('PKG_CONFIG', pkg_config)
151 include('build/moz.configure/memory.configure',
152 when='--enable-compile-environment')
153 include('build/moz.configure/headers.configure',
154 when='--enable-compile-environment')
155 include('build/moz.configure/warnings.configure',
156 when='--enable-compile-environment')
157 include('build/moz.configure/flags.configure',
158 when='--enable-compile-environment')
159 # rust.configure is included by js/moz.configure.
161 js_option('--enable-valgrind',
162 help='Enable Valgrind integration hooks')
164 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
166 @depends('--enable-valgrind', valgrind_h)
167 def check_valgrind(valgrind, valgrind_h):
170 die('--enable-valgrind specified but Valgrind is not installed')
173 set_define('MOZ_VALGRIND', check_valgrind)
174 set_config('MOZ_VALGRIND', check_valgrind)
176 @depends(target, host)
177 def is_openbsd(target, host):
178 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
180 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
181 help='Shared library version for OpenBSD systems')
183 @depends('SO_VERSION', when=is_openbsd)
184 def so_version(value):
188 def library_name_info_template(host_or_target):
189 assert host_or_target in {host, target}
191 host: host_c_compiler,
195 @depends(host_or_target, compiler, so_version)
196 def library_name_info_impl(host_or_target, compiler, so_version):
197 if host_or_target.kernel == 'WINNT':
198 # There aren't artifacts for mingw builds, so it's OK that the
199 # results are inaccurate in that case.
200 if compiler and compiler.type != 'clang-cl':
202 dll=namespace(prefix='', suffix='.dll'),
203 lib=namespace(prefix='lib', suffix='a'),
204 import_lib=namespace(prefix='lib', suffix='a'),
205 rust_lib=namespace(prefix='', suffix='lib'),
206 obj=namespace(prefix='', suffix='o'),
210 dll=namespace(prefix='', suffix='.dll'),
211 lib=namespace(prefix='', suffix='lib'),
212 import_lib=namespace(prefix='', suffix='lib'),
213 rust_lib=namespace(prefix='', suffix='lib'),
214 obj=namespace(prefix='', suffix='obj'),
217 elif host_or_target.kernel == 'Darwin':
219 dll=namespace(prefix='lib', suffix='.dylib'),
220 lib=namespace(prefix='lib', suffix='a'),
221 import_lib=namespace(prefix=None, suffix=''),
222 rust_lib=namespace(prefix='lib', suffix='a'),
223 obj=namespace(prefix='', suffix='o'),
226 so = '.so.%s' % so_version
231 dll=namespace(prefix='lib', suffix=so),
232 lib=namespace(prefix='lib', suffix='a'),
233 import_lib=namespace(prefix=None, suffix=''),
234 rust_lib=namespace(prefix='lib', suffix='a'),
235 obj=namespace(prefix='', suffix='o'),
238 return library_name_info_impl
240 host_library_name_info = library_name_info_template(host)
241 library_name_info = library_name_info_template(target)
243 set_config('DLL_PREFIX', library_name_info.dll.prefix)
244 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
245 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
246 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
247 set_config('LIB_PREFIX', library_name_info.lib.prefix)
248 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
249 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
250 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
251 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
252 # Lots of compilation tests depend on this variable being present.
253 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
254 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
255 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
256 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
257 set_config('WASM_OBJ_SUFFIX', 'wasm')
259 include(include_project_configure)
262 @imports(_from='mozbuild.backend', _import='backends')
263 def build_backends_choices(_):
264 return tuple(backends)
267 @deprecated_option('--enable-build-backend', nargs='+',
268 choices=build_backends_choices)
269 def build_backend(backends):
271 return tuple('+%s' % b for b in backends)
273 imply_option('--build-backends', build_backend)
276 @depends('--enable-artifact-builds', '--disable-compile-environment',
277 '--enable-build-backend', '--enable-project', '--enable-application',
280 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
281 project, application, _):
283 project = application[0]
287 if 'Tup' in requested_backends:
288 # As a special case, if Tup was requested, do not combine it with any
289 # Make based backend by default.
291 elif artifact_builds:
292 all_backends = ['FasterMake+RecursiveMake']
294 all_backends = ['RecursiveMake', 'FasterMake']
295 # Normally, we'd use target.os == 'WINNT', but a dependency on target
296 # would require target to depend on --help, as well as host and shell,
297 # and this is not a can of worms we can open at the moment.
298 if sys.platform == 'win32' and compile_environment and project != 'mobile/android':
299 all_backends.append('VisualStudio')
300 return tuple(all_backends) or None
302 option('--build-backends', nargs='+', default=build_backend_defaults,
303 choices=build_backends_choices, help='Build backends to generate')
305 @depends('--build-backends')
306 def build_backends(backends):
309 set_config('BUILD_BACKENDS', build_backends)
312 @depends(check_build_environment, build_backends)
314 def check_objdir_backend_reuse(build_env, backends):
315 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
316 # intentionally vague for use with the substring match below.
317 incompatible_backends = (
321 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
322 'backend.*Backend')):
323 for prev, curr in incompatible_backends:
324 if prev in backend_file and any(curr in b for b in backends):
325 die("The active objdir, %s, was previously "
326 "used to build with a %s based backend. "
327 "Change objdirs (by setting MOZ_OBJDIR in "
328 "your mozconfig) or clobber to continue.\n",
329 build_env.topobjdir, prev)
332 option('--disable-gtest-in-build',
333 help='Force disable building the gtest libxul during the build.',
334 when='--enable-compile-environment')
336 # Determine whether to build the gtest xul. This happens in automation
337 # on Android and Desktop platforms with the exception of:
338 # - Windows PGO, where linking xul-gtest.dll takes too long;
339 # - Android other than x86_64, where gtest is not required.
340 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
341 enable_tests, when='--enable-compile-environment')
342 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
343 if not enable_tests or not enabled:
345 if (automation and build_project in ('browser', 'comm/mail', 'mobile/android') and
346 not ((pgo and target.os == 'WINNT') or (target.os == 'Android' and target.cpu != 'x86_64'))):
349 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
352 # ==============================================================
353 option('--enable-ui-locale', default='en-US',
354 help='Select the user interface locale (default: en-US)')
356 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
358 # clang-plugin location
359 # ==============================================================
360 @depends(host_library_name_info, check_build_environment,
361 when='--enable-clang-plugin')
362 def clang_plugin_path(library_name_info, build_env):
363 topobjdir = build_env.topobjdir
364 if topobjdir.endswith('/js/src'):
365 topobjdir = topobjdir[:-7]
366 return os.path.abspath(
367 os.path.join(topobjdir, 'build', 'clang-plugin',
368 '%sclang-plugin%s' % (library_name_info.dll.prefix,
369 library_name_info.dll.suffix))
372 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
376 # ==============================================================
377 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
379 # Until the AWK variable is not necessary in old-configure
381 def awk_for_old_configure(value):
384 add_old_configure_assignment('AWK', awk_for_old_configure)
388 # ==============================================================
389 perl = check_prog('PERL', ('perl5', 'perl'))
391 # Until the PERL variable is not necessary in old-configure
393 def perl_for_old_configure(value):
396 add_old_configure_assignment('PERL', perl_for_old_configure)
399 def perl_version_check(min_version):
401 @checking('for minimum required perl version >= %s' % min_version)
402 def get_perl_version(perl):
403 return Version(check_cmd_output(
404 perl, '-e', 'print $]',
405 onerror=lambda: die('Failed to get perl version.')
408 @depends(get_perl_version)
409 def check_perl_version(version):
410 if version < min_version:
411 die('Perl %s or higher is required.', min_version)
414 @checking('for full perl installation')
415 @imports('subprocess')
416 def has_full_perl_installation(perl):
417 ret = subprocess.call(
418 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
421 @depends(has_full_perl_installation)
422 def require_full_perl_installation(has_full_perl_installation):
423 if not has_full_perl_installation:
424 die('Cannot find Config.pm or $Config{archlib}. '
425 'A full perl installation is required.')
427 perl_version_check('5.006')
431 # ==============================================================
432 option(env='MAKE', nargs=1, help='Path to GNU make')
434 @depends('MAKE', host)
435 def possible_makes(make, host):
437 if host.kernel == 'WINNT':
438 candidates.append('mingw32-make')
440 candidates.append(make[0])
441 if host.kernel == 'WINNT':
442 candidates.extend(('make', 'gmake'))
444 candidates.extend(('gmake', 'make'))
447 check_prog('GMAKE', possible_makes)
449 @depends(build_backends, build_project)
450 def tup_include(build_backends, build_project):
451 # We need to check the rustc version when building with tup, but
452 # rustc_info isn't available when configuring js (and build_backends isn't
453 # available from project-specific configure), so as a workaround we only
454 # include the file when we know we'll need it. This can be removed when
455 # we globally require a rustc recent enough to build with tup.
456 if build_project not in ('browser', 'mobile/android'):
458 for backend in build_backends:
460 return 'build/moz.configure/tup.configure'
465 # ==============================================================
467 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
469 @depends(host, 'WATCHMAN')
470 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
471 def watchman(host, prog):
472 # On Windows, `watchman` is only supported on 64-bit hosts.
473 if host.os == 'WINNT' and host.cpu != 'x86_64':
477 prog = find_program('watchman')
482 # `watchman version` will talk to the Watchman daemon service.
483 # This can hang due to permissions problems. e.g.
484 # https://github.com/facebook/watchman/issues/376. So use
485 # `watchman --version` to prevent a class of failures.
486 out = check_cmd_output(prog, '--version', onerror=lambda: None)
490 return namespace(path=prog, version=Version(out.strip()))
492 @depends_if(watchman)
493 @checking('for watchman version')
494 def watchman_version(w):
497 set_config('WATCHMAN', watchman.path)
499 @depends_all(hg_version, hg_config, watchman)
500 @checking('for watchman Mercurial integration')
502 def watchman_hg(hg_version, hg_config, watchman):
503 if hg_version < Version('3.8'):
504 return 'no (Mercurial 3.8+ required)'
507 mode_disabled = False
509 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
510 if k in hg_config and hg_config[k] != '!':
513 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
516 return 'no (fsmonitor extension not enabled)'
518 return 'no (fsmonitor.mode=off disables fsmonitor)'
522 # Miscellaneous programs
523 # ==============================================================
524 check_prog('XARGS', ('xargs',))
527 def extra_programs(target):
528 if target.kernel == 'Darwin':
530 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
531 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
532 HFS_TOOL=('hfsplus',)
534 if target.os == 'GNU' and target.kernel == 'Linux':
535 return namespace(RPMBUILD=('rpmbuild',))
537 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
539 check_prog('MKFSHFS', extra_programs.MKFSHFS,
541 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
543 check_prog('RPMBUILD', extra_programs.RPMBUILD,
549 def makensis_progs(target):
550 if target.kernel != 'WINNT':
560 # Look for nsis installed by msys environment. But only the 32-bit version.
561 # We use an absolute path and insert as the first entry so it is preferred
562 # over a 64-bit exe that may be in PATH.
563 if 'MSYSTEM_PREFIX' in os.environ:
564 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
565 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
567 return tuple(candidates)
569 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
571 # Make sure the version of makensis is up to date.
573 @checking('for NSIS version')
575 def nsis_version(nsis, wine):
578 nsis_min_version = '3.0b1'
579 onerror = lambda: die('Failed to get nsis version.')
580 if wine and nsis.lower().endswith('.exe'):
581 out = check_cmd_output(wine, nsis, '-version', onerror=onerror)
583 out = check_cmd_output(nsis, '-version', onerror=onerror)
585 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
588 raise FatalCheckError('Unknown version of makensis')
589 ver = Version(m.group(0))
591 # Versions comparisons don't quite work well with beta versions, so ensure
592 # it works for the non-beta version.
593 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
594 raise FatalCheckError('To build the installer you must have NSIS'
595 ' version %s or greater in your path'
600 # And that makensis is 32-bit (but only on Windows).
601 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
602 @checking('for 32-bit NSIS')
603 def nsis_binary_type(nsis):
604 bin_type = windows_binary_type(nsis)
605 if bin_type != 'win32':
606 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
610 # And any flags we have to give to makensis
612 def nsis_flags(host):
613 if host.kernel != 'WINNT':
617 set_config('MAKENSISU_FLAGS', nsis_flags)
619 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
620 check_prog('UPX', ('upx',), allow_missing=True, when=target_is_windows)
623 @depends(host_c_compiler, c_compiler, bindgen_config_paths)
624 def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
626 for compiler in (host_c_compiler, c_compiler):
627 if compiler and compiler.type == 'clang':
628 clang = compiler.compiler
630 elif compiler and compiler.type == 'clang-cl':
631 clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
634 if not clang and bindgen_config_paths:
635 clang = bindgen_config_paths.clang_path
636 llvm_objdump = 'llvm-objdump'
638 out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
639 onerror=lambda: None)
641 llvm_objdump = out.rstrip()
642 return (llvm_objdump,)
645 llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
646 when='--enable-compile-environment',
647 paths=toolchain_search_path)
649 add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
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.