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/lto-pgo.configure',
158 when='--enable-compile-environment')
159 include('build/moz.configure/flags.configure',
160 when='--enable-compile-environment')
161 # rust.configure is included by js/moz.configure.
163 js_option('--enable-valgrind',
164 help='Enable Valgrind integration hooks')
166 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
168 @depends('--enable-valgrind', valgrind_h)
169 def check_valgrind(valgrind, valgrind_h):
172 die('--enable-valgrind specified but Valgrind is not installed')
175 set_define('MOZ_VALGRIND', check_valgrind)
176 set_config('MOZ_VALGRIND', check_valgrind)
178 @depends(target, host)
179 def is_openbsd(target, host):
180 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
182 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
183 help='Shared library version for OpenBSD systems')
185 @depends('SO_VERSION', when=is_openbsd)
186 def so_version(value):
190 def library_name_info_template(host_or_target):
191 assert host_or_target in {host, target}
193 host: host_c_compiler,
197 @depends(host_or_target, compiler, so_version)
198 def library_name_info_impl(host_or_target, compiler, so_version):
199 if host_or_target.kernel == 'WINNT':
200 # There aren't artifacts for mingw builds, so it's OK that the
201 # results are inaccurate in that case.
202 if compiler and compiler.type != 'clang-cl':
204 dll=namespace(prefix='', suffix='.dll'),
205 lib=namespace(prefix='lib', suffix='a'),
206 import_lib=namespace(prefix='lib', suffix='a'),
207 rust_lib=namespace(prefix='', suffix='lib'),
208 obj=namespace(prefix='', suffix='o'),
212 dll=namespace(prefix='', suffix='.dll'),
213 lib=namespace(prefix='', suffix='lib'),
214 import_lib=namespace(prefix='', suffix='lib'),
215 rust_lib=namespace(prefix='', suffix='lib'),
216 obj=namespace(prefix='', suffix='obj'),
219 elif host_or_target.kernel == 'Darwin':
221 dll=namespace(prefix='lib', suffix='.dylib'),
222 lib=namespace(prefix='lib', suffix='a'),
223 import_lib=namespace(prefix=None, suffix=''),
224 rust_lib=namespace(prefix='lib', suffix='a'),
225 obj=namespace(prefix='', suffix='o'),
228 so = '.so.%s' % so_version
233 dll=namespace(prefix='lib', suffix=so),
234 lib=namespace(prefix='lib', suffix='a'),
235 import_lib=namespace(prefix=None, suffix=''),
236 rust_lib=namespace(prefix='lib', suffix='a'),
237 obj=namespace(prefix='', suffix='o'),
240 return library_name_info_impl
242 host_library_name_info = library_name_info_template(host)
243 library_name_info = library_name_info_template(target)
245 set_config('DLL_PREFIX', library_name_info.dll.prefix)
246 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
247 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
248 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
249 set_config('LIB_PREFIX', library_name_info.lib.prefix)
250 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
251 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
252 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
253 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
254 # Lots of compilation tests depend on this variable being present.
255 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
256 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
257 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
258 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
259 set_config('WASM_OBJ_SUFFIX', 'wasm')
261 include(include_project_configure)
264 @imports(_from='mozbuild.backend', _import='backends')
265 def build_backends_choices(_):
266 return tuple(backends)
269 @deprecated_option('--enable-build-backend', nargs='+',
270 choices=build_backends_choices)
271 def build_backend(backends):
273 return tuple('+%s' % b for b in backends)
275 imply_option('--build-backends', build_backend)
278 @depends('--enable-artifact-builds', '--disable-compile-environment',
279 '--enable-build-backend', '--enable-project', '--enable-application',
282 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
283 project, application, _):
285 project = application[0]
289 if 'Tup' in requested_backends:
290 # As a special case, if Tup was requested, do not combine it with any
291 # Make based backend by default.
293 elif artifact_builds:
294 all_backends = ['FasterMake+RecursiveMake']
296 all_backends = ['RecursiveMake', 'FasterMake']
297 # Normally, we'd use target.os == 'WINNT', but a dependency on target
298 # would require target to depend on --help, as well as host and shell,
299 # and this is not a can of worms we can open at the moment.
300 if sys.platform == 'win32' and compile_environment and project != 'mobile/android':
301 all_backends.append('VisualStudio')
302 return tuple(all_backends) or None
304 option('--build-backends', nargs='+', default=build_backend_defaults,
305 choices=build_backends_choices, help='Build backends to generate')
307 @depends('--build-backends')
308 def build_backends(backends):
311 set_config('BUILD_BACKENDS', build_backends)
314 @depends(check_build_environment, build_backends)
316 def check_objdir_backend_reuse(build_env, backends):
317 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
318 # intentionally vague for use with the substring match below.
319 incompatible_backends = (
323 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
324 'backend.*Backend')):
325 for prev, curr in incompatible_backends:
326 if prev in backend_file and any(curr in b for b in backends):
327 die("The active objdir, %s, was previously "
328 "used to build with a %s based backend. "
329 "Change objdirs (by setting MOZ_OBJDIR in "
330 "your mozconfig) or clobber to continue.\n",
331 build_env.topobjdir, prev)
334 option('--disable-gtest-in-build',
335 help='Force disable building the gtest libxul during the build.',
336 when='--enable-compile-environment')
338 # Determine whether to build the gtest xul. This happens in automation
339 # on Android and Desktop platforms with the exception of:
340 # - Windows PGO, where linking xul-gtest.dll takes too long;
341 # - Android other than x86_64, where gtest is not required.
342 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
343 enable_tests, when='--enable-compile-environment')
344 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
345 if not enable_tests or not enabled:
347 if (automation and build_project in ('browser', 'comm/mail', 'mobile/android') and
348 not ((pgo and target.os == 'WINNT') or (target.os == 'Android' and target.cpu != 'x86_64'))):
351 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
354 # ==============================================================
355 option('--enable-ui-locale', default='en-US',
356 help='Select the user interface locale (default: en-US)')
358 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
360 # clang-plugin location
361 # ==============================================================
362 @depends(host_library_name_info, check_build_environment,
363 when='--enable-clang-plugin')
364 def clang_plugin_path(library_name_info, build_env):
365 topobjdir = build_env.topobjdir
366 if topobjdir.endswith('/js/src'):
367 topobjdir = topobjdir[:-7]
368 return os.path.abspath(
369 os.path.join(topobjdir, 'build', 'clang-plugin',
370 '%sclang-plugin%s' % (library_name_info.dll.prefix,
371 library_name_info.dll.suffix))
374 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
378 # ==============================================================
379 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
381 # Until the AWK variable is not necessary in old-configure
383 def awk_for_old_configure(value):
386 add_old_configure_assignment('AWK', awk_for_old_configure)
390 # ==============================================================
391 perl = check_prog('PERL', ('perl5', 'perl'))
393 # Until the PERL variable is not necessary in old-configure
395 def perl_for_old_configure(value):
398 add_old_configure_assignment('PERL', perl_for_old_configure)
401 def perl_version_check(min_version):
403 @checking('for minimum required perl version >= %s' % min_version)
404 def get_perl_version(perl):
405 return Version(check_cmd_output(
406 perl, '-e', 'print $]',
407 onerror=lambda: die('Failed to get perl version.')
410 @depends(get_perl_version)
411 def check_perl_version(version):
412 if version < min_version:
413 die('Perl %s or higher is required.', min_version)
416 @checking('for full perl installation')
417 @imports('subprocess')
418 def has_full_perl_installation(perl):
419 ret = subprocess.call(
420 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
423 @depends(has_full_perl_installation)
424 def require_full_perl_installation(has_full_perl_installation):
425 if not has_full_perl_installation:
426 die('Cannot find Config.pm or $Config{archlib}. '
427 'A full perl installation is required.')
429 perl_version_check('5.006')
433 # ==============================================================
434 option(env='MAKE', nargs=1, help='Path to GNU make')
436 @depends('MAKE', host)
437 def possible_makes(make, host):
439 if host.kernel == 'WINNT':
440 candidates.append('mingw32-make')
442 candidates.append(make[0])
443 if host.kernel == 'WINNT':
444 candidates.extend(('make', 'gmake'))
446 candidates.extend(('gmake', 'make'))
449 check_prog('GMAKE', possible_makes)
451 @depends(build_backends, build_project)
452 def tup_include(build_backends, build_project):
453 # We need to check the rustc version when building with tup, but
454 # rustc_info isn't available when configuring js (and build_backends isn't
455 # available from project-specific configure), so as a workaround we only
456 # include the file when we know we'll need it. This can be removed when
457 # we globally require a rustc recent enough to build with tup.
458 if build_project not in ('browser', 'mobile/android'):
460 for backend in build_backends:
462 return 'build/moz.configure/tup.configure'
467 # ==============================================================
469 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
471 @depends(host, 'WATCHMAN')
472 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
473 def watchman(host, prog):
474 # On Windows, `watchman` is only supported on 64-bit hosts.
475 if host.os == 'WINNT' and host.cpu != 'x86_64':
479 prog = find_program('watchman')
484 # `watchman version` will talk to the Watchman daemon service.
485 # This can hang due to permissions problems. e.g.
486 # https://github.com/facebook/watchman/issues/376. So use
487 # `watchman --version` to prevent a class of failures.
488 out = check_cmd_output(prog, '--version', onerror=lambda: None)
492 return namespace(path=prog, version=Version(out.strip()))
494 @depends_if(watchman)
495 @checking('for watchman version')
496 def watchman_version(w):
499 set_config('WATCHMAN', watchman.path)
501 @depends_all(hg_version, hg_config, watchman)
502 @checking('for watchman Mercurial integration')
504 def watchman_hg(hg_version, hg_config, watchman):
505 if hg_version < Version('3.8'):
506 return 'no (Mercurial 3.8+ required)'
509 mode_disabled = False
511 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
512 if k in hg_config and hg_config[k] != '!':
515 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
518 return 'no (fsmonitor extension not enabled)'
520 return 'no (fsmonitor.mode=off disables fsmonitor)'
524 # Miscellaneous programs
525 # ==============================================================
526 check_prog('XARGS', ('xargs',))
529 def extra_programs(target):
530 if target.kernel == 'Darwin':
532 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
533 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
534 HFS_TOOL=('hfsplus',)
536 if target.os == 'GNU' and target.kernel == 'Linux':
537 return namespace(RPMBUILD=('rpmbuild',))
539 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
541 check_prog('MKFSHFS', extra_programs.MKFSHFS,
543 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
545 check_prog('RPMBUILD', extra_programs.RPMBUILD,
551 def makensis_progs(target):
552 if target.kernel != 'WINNT':
562 # Look for nsis installed by msys environment. But only the 32-bit version.
563 # We use an absolute path and insert as the first entry so it is preferred
564 # over a 64-bit exe that may be in PATH.
565 if 'MSYSTEM_PREFIX' in os.environ:
566 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
567 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
569 return tuple(candidates)
571 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
573 # Make sure the version of makensis is up to date.
575 @checking('for NSIS version')
577 def nsis_version(nsis, wine):
580 nsis_min_version = '3.0b1'
581 onerror = lambda: die('Failed to get nsis version.')
582 if wine and nsis.lower().endswith('.exe'):
583 out = check_cmd_output(wine, nsis, '-version', onerror=onerror)
585 out = check_cmd_output(nsis, '-version', onerror=onerror)
587 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
590 raise FatalCheckError('Unknown version of makensis')
591 ver = Version(m.group(0))
593 # Versions comparisons don't quite work well with beta versions, so ensure
594 # it works for the non-beta version.
595 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
596 raise FatalCheckError('To build the installer you must have NSIS'
597 ' version %s or greater in your path'
602 # And that makensis is 32-bit (but only on Windows).
603 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
604 @checking('for 32-bit NSIS')
605 def nsis_binary_type(nsis):
606 bin_type = windows_binary_type(nsis)
607 if bin_type != 'win32':
608 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
612 # And any flags we have to give to makensis
614 def nsis_flags(host):
615 if host.kernel != 'WINNT':
619 set_config('MAKENSISU_FLAGS', nsis_flags)
621 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
622 check_prog('UPX', ('upx',), allow_missing=True, when=target_is_windows)
625 @depends(host_c_compiler, c_compiler, bindgen_config_paths)
626 def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
628 for compiler in (host_c_compiler, c_compiler):
629 if compiler and compiler.type == 'clang':
630 clang = compiler.compiler
632 elif compiler and compiler.type == 'clang-cl':
633 clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
636 if not clang and bindgen_config_paths:
637 clang = bindgen_config_paths.clang_path
638 llvm_objdump = 'llvm-objdump'
640 out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
641 onerror=lambda: None)
643 llvm_objdump = out.rstrip()
644 return (llvm_objdump,)
647 llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
648 when='--enable-compile-environment',
649 paths=toolchain_search_path)
651 add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
654 # Please do not add configure checks from here on.
656 # Fallthrough to autoconf-based configure
657 include('build/moz.configure/old.configure')
660 include('js/sub.configure', when=compile_environment & toolkit)
663 @depends(check_build_environment, build_project)
664 @imports('__sandbox__')
666 @imports(_from='os.path', _import='exists')
667 def config_status_deps(build_env, build_project):
669 topsrcdir = build_env.topsrcdir
670 topobjdir = build_env.topobjdir
672 if not topobjdir.endswith('js/src'):
673 extra_deps = [os.path.join(topobjdir, '.mozconfig.json')]
675 # mozconfig changes may impact js configure.
676 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
678 confvars = os.path.join(topsrcdir, build_project, 'confvars.sh')
680 extra_deps.append(confvars)
682 return list(__sandbox__._all_paths) + extra_deps + [
683 os.path.join(topsrcdir, 'CLOBBER'),
684 os.path.join(topsrcdir, 'configure'),
685 os.path.join(topsrcdir, 'js', 'src', 'configure'),
686 os.path.join(topsrcdir, 'configure.in'),
687 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
688 os.path.join(topsrcdir, 'nsprpub', 'configure'),
689 os.path.join(topsrcdir, 'config', 'milestone.txt'),
690 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
691 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
692 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
693 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
694 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
695 os.path.join(topsrcdir, 'aclocal.m4'),
696 os.path.join(topsrcdir, 'old-configure.in'),
697 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
698 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
699 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
701 set_config('CONFIG_STATUS_DEPS', config_status_deps)
702 # Please do not add anything after setting config_dep_paths.