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',
32 help='Download symbols when artifact builds are enabled.')
34 set_config('MOZ_ARTIFACT_BUILD_SYMBOLS',
35 depends_if('--enable-artifact-build-symbols')(lambda _: True))
37 @depends('--enable-artifact-builds')
38 def imply_disable_compile_environment(value):
42 option(env='MOZ_COPY_PDBS',
43 help='For builds that do not support symbols in the normal fashion,'
44 ' generate and copy them into the resulting build archive.')
46 set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
48 imply_option('--enable-compile-environment', imply_disable_compile_environment)
50 option('--disable-compile-environment',
51 help='Disable compiler/library checks')
53 @depends('--disable-compile-environment')
54 def compile_environment(compile_env):
58 set_config('COMPILE_ENVIRONMENT', compile_environment)
59 add_old_configure_assignment('COMPILE_ENVIRONMENT', compile_environment)
61 js_option('--disable-tests',
62 help='Do not build test libraries & programs')
64 @depends('--disable-tests')
65 def enable_tests(value):
69 set_config('ENABLE_TESTS', enable_tests)
70 set_define('ENABLE_TESTS', enable_tests)
72 @depends(enable_tests)
73 def gtest_has_rtti(value):
77 set_define('GTEST_HAS_RTTI', gtest_has_rtti)
79 @depends(target, enable_tests)
80 def linux_gtest_defines(target, enable_tests):
81 if enable_tests and target.os == 'Android':
82 return namespace(os_linux_android=True,
83 use_own_tr1_tuple=True,
86 set_define('GTEST_OS_LINUX_ANDROID',
87 linux_gtest_defines.os_linux_android)
88 set_define('GTEST_USE_OWN_TR1_TUPLE',
89 linux_gtest_defines.use_own_tr1_tuple)
90 set_define('GTEST_HAS_CLONE',
91 linux_gtest_defines.has_clone)
93 js_option('--enable-debug',
95 help='Enable building with developer debug info '
96 '(using the given compiler flags).')
98 @depends('--enable-debug')
103 set_config('MOZ_DEBUG', moz_debug)
104 set_define('MOZ_DEBUG', moz_debug)
105 # Override any value MOZ_DEBUG may have from the environment when passing it
106 # down to old-configure.
107 add_old_configure_assignment('MOZ_DEBUG',
108 depends('--enable-debug')(lambda x: bool(x)))
110 js_option('--enable-rust-debug',
111 default=depends(when='--enable-debug')(lambda: True),
112 help='{Build|Do not build} Rust code with debug assertions turned '
115 @depends(when='--enable-rust-debug')
119 set_config('MOZ_DEBUG_RUST', debug_rust)
120 set_define('MOZ_DEBUG_RUST', debug_rust)
122 js_option(env='MOZ_PGO', help='Build with profile guided optimizations')
124 set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
126 include('build/moz.configure/toolchain.configure',
127 when='--enable-compile-environment')
129 include('build/moz.configure/pkg.configure')
130 # Make this assignment here rather than in pkg.configure to avoid
131 # requiring this file in unit tests.
132 add_old_configure_assignment('PKG_CONFIG', pkg_config)
134 include('build/moz.configure/memory.configure',
135 when='--enable-compile-environment')
136 include('build/moz.configure/headers.configure',
137 when='--enable-compile-environment')
138 include('build/moz.configure/warnings.configure',
139 when='--enable-compile-environment')
140 include('build/moz.configure/flags.configure',
141 when='--enable-compile-environment')
142 # rust.configure is included by js/moz.configure.
144 js_option('--enable-valgrind',
145 help='Enable Valgrind integration hooks')
147 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
149 @depends('--enable-valgrind', valgrind_h)
150 def check_valgrind(valgrind, valgrind_h):
153 die('--enable-valgrind specified but Valgrind is not installed')
156 set_define('MOZ_VALGRIND', check_valgrind)
157 set_config('MOZ_VALGRIND', check_valgrind)
159 @depends(target, host)
160 def is_openbsd(target, host):
161 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
163 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
164 help='Shared library version for OpenBSD systems')
166 @depends('SO_VERSION', when=is_openbsd)
167 def so_version(value):
171 def library_name_info_template(host_or_target):
172 assert host_or_target in {host, target}
174 host: host_c_compiler,
178 @depends(host_or_target, compiler, so_version)
179 def library_name_info_impl(host_or_target, compiler, so_version):
180 if host_or_target.kernel == 'WINNT':
181 # There aren't artifacts for mingw builds, so it's OK that the
182 # results are inaccurate in that case.
183 if compiler and compiler.type not in ('msvc', 'clang-cl'):
185 dll=namespace(prefix='', suffix='.dll'),
186 lib=namespace(prefix='lib', suffix='a'),
187 import_lib=namespace(prefix='lib', suffix='a'),
188 rust_lib=namespace(prefix='', suffix='lib'),
189 obj=namespace(prefix='', suffix='o'),
193 dll=namespace(prefix='', suffix='.dll'),
194 lib=namespace(prefix='', suffix='lib'),
195 import_lib=namespace(prefix='', suffix='lib'),
196 rust_lib=namespace(prefix='', suffix='lib'),
197 obj=namespace(prefix='', suffix='obj'),
200 elif host_or_target.kernel == 'Darwin':
202 dll=namespace(prefix='lib', suffix='.dylib'),
203 lib=namespace(prefix='lib', suffix='a'),
204 import_lib=namespace(prefix=None, suffix=''),
205 rust_lib=namespace(prefix='lib', suffix='a'),
206 obj=namespace(prefix='', suffix='o'),
209 so = '.so.%s' % so_version
214 dll=namespace(prefix='lib', suffix=so),
215 lib=namespace(prefix='lib', suffix='a'),
216 import_lib=namespace(prefix=None, suffix=''),
217 rust_lib=namespace(prefix='lib', suffix='a'),
218 obj=namespace(prefix='', suffix='o'),
221 return library_name_info_impl
223 host_library_name_info = library_name_info_template(host)
224 library_name_info = library_name_info_template(target)
226 set_config('DLL_PREFIX', library_name_info.dll.prefix)
227 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
228 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
229 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
230 set_config('LIB_PREFIX', library_name_info.lib.prefix)
231 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
232 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
233 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
234 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
235 # Lots of compilation tests depend on this variable being present.
236 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
237 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
238 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
239 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
241 include(include_project_configure)
244 @imports(_from='mozbuild.backend', _import='backends')
245 def build_backends_choices(_):
246 return tuple(backends)
249 @deprecated_option('--enable-build-backend', nargs='+',
250 choices=build_backends_choices)
251 def build_backend(backends):
253 return tuple('+%s' % b for b in backends)
255 imply_option('--build-backends', build_backend)
258 @depends('--enable-artifact-builds', '--disable-compile-environment',
259 '--enable-build-backend', '--help')
261 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
263 if 'Tup' in requested_backends:
264 # As a special case, if Tup was requested, do not combine it with any
265 # Make based backend by default.
267 elif artifact_builds:
268 all_backends = ['FasterMake+RecursiveMake']
270 all_backends = ['RecursiveMake', 'FasterMake']
271 # Normally, we'd use target.os == 'WINNT', but a dependency on target
272 # would require target to depend on --help, as well as host and shell,
273 # and this is not a can of worms we can open at the moment.
274 if sys.platform == 'win32' and compile_environment:
275 all_backends.append('VisualStudio')
276 return tuple(all_backends) or None
278 option('--build-backends', nargs='+', default=build_backend_defaults,
279 choices=build_backends_choices, help='Build backends to generate')
281 @depends('--build-backends')
282 def build_backends(backends):
285 set_config('BUILD_BACKENDS', build_backends)
288 @depends(check_build_environment, build_backends)
290 def check_objdir_backend_reuse(build_env, backends):
291 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
292 # intentionally vague for use with the substring match below.
293 incompatible_backends = (
297 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
298 'backend.*Backend')):
299 for prev, curr in incompatible_backends:
300 if prev in backend_file and any(curr in b for b in backends):
301 die("The active objdir, %s, was previously "
302 "used to build with a %s based backend. "
303 "Change objdirs (by setting MOZ_OBJDIR in "
304 "your mozconfig) or clobber to continue.\n",
305 build_env.topobjdir, prev)
308 option('--disable-gtest-in-build',
309 help='Force disable building the gtest libxul during the build.',
310 when='--enable-compile-environment')
312 # Determine whether to build the gtest xul. This happens in automation
313 # on Desktop platforms with the exception of Windows PGO, where linking
314 # xul-gtest.dll takes too long.
315 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
316 enable_tests, when='--enable-compile-environment')
317 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
318 if not enable_tests or not enabled:
320 if (automation and build_project == 'browser' and
321 not (pgo and target.os == 'WINNT')):
324 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
327 # ==============================================================
328 option('--enable-ui-locale', default='en-US',
329 help='Select the user interface locale (default: en-US)')
331 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
333 # clang-plugin location
334 # ==============================================================
335 @depends(host_library_name_info, check_build_environment,
336 when='--enable-clang-plugin')
337 def clang_plugin_path(library_name_info, build_env):
338 topobjdir = build_env.topobjdir
339 if topobjdir.endswith('/js/src'):
340 topobjdir = topobjdir[:-7]
341 return os.path.abspath(
342 os.path.join(topobjdir, 'build', 'clang-plugin',
343 '%sclang-plugin%s' % (library_name_info.dll.prefix,
344 library_name_info.dll.suffix))
347 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
351 # ==============================================================
352 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
354 # Until the AWK variable is not necessary in old-configure
356 def awk_for_old_configure(value):
359 add_old_configure_assignment('AWK', awk_for_old_configure)
363 # ==============================================================
364 perl = check_prog('PERL', ('perl5', 'perl'))
366 # Until the PERL variable is not necessary in old-configure
368 def perl_for_old_configure(value):
371 add_old_configure_assignment('PERL', perl_for_old_configure)
374 def perl_version_check(min_version):
376 @checking('for minimum required perl version >= %s' % min_version)
377 def get_perl_version(perl):
378 return Version(check_cmd_output(
379 perl, '-e', 'print $]',
380 onerror=lambda: die('Failed to get perl version.')
383 @depends(get_perl_version)
384 def check_perl_version(version):
385 if version < min_version:
386 die('Perl %s or higher is required.', min_version)
389 @checking('for full perl installation')
390 @imports('subprocess')
391 def has_full_perl_installation(perl):
392 ret = subprocess.call(
393 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
396 @depends(has_full_perl_installation)
397 def require_full_perl_installation(has_full_perl_installation):
398 if not has_full_perl_installation:
399 die('Cannot find Config.pm or $Config{archlib}. '
400 'A full perl installation is required.')
402 perl_version_check('5.006')
406 # ==============================================================
407 option(env='MAKE', nargs=1, help='Path to GNU make')
409 @depends('MAKE', host)
410 def possible_makes(make, host):
412 if host.kernel == 'WINNT':
413 candidates.append('mingw32-make')
415 candidates.append(make[0])
416 if host.kernel == 'WINNT':
417 candidates.extend(('make', 'gmake'))
419 candidates.extend(('gmake', 'make'))
422 check_prog('GMAKE', possible_makes)
424 @depends(build_backends, build_project)
425 def tup_include(build_backends, build_project):
426 # We need to check the rustc version when building with tup, but
427 # rustc_info isn't available when configuring js (and build_backends isn't
428 # available from project-specific configure), so as a workaround we only
429 # include the file when we know we'll need it. This can be removed when
430 # we globally require a rustc recent enough to build with tup.
431 if build_project not in ('browser', 'mobile/android'):
433 for backend in build_backends:
435 return 'build/moz.configure/tup.configure'
440 # ==============================================================
442 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
444 @depends(host, 'WATCHMAN')
445 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
446 def watchman(host, prog):
447 # On Windows, `watchman` is only supported on 64-bit hosts.
448 if host.os == 'WINNT' and host.cpu != 'x86_64':
452 prog = find_program('watchman')
457 # `watchman version` will talk to the Watchman daemon service.
458 # This can hang due to permissions problems. e.g.
459 # https://github.com/facebook/watchman/issues/376. So use
460 # `watchman --version` to prevent a class of failures.
461 out = check_cmd_output(prog, '--version', onerror=lambda: None)
465 return namespace(path=prog, version=Version(out.strip()))
467 @depends_if(watchman)
468 @checking('for watchman version')
469 def watchman_version(w):
472 set_config('WATCHMAN', watchman.path)
474 @depends_all(hg_version, hg_config, watchman)
475 @checking('for watchman Mercurial integration')
477 def watchman_hg(hg_version, hg_config, watchman):
478 if hg_version < Version('3.8'):
479 return 'no (Mercurial 3.8+ required)'
482 mode_disabled = False
484 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
485 if k in hg_config and hg_config[k] != '!':
488 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
491 return 'no (fsmonitor extension not enabled)'
493 return 'no (fsmonitor.mode=off disables fsmonitor)'
497 # Miscellaneous programs
498 # ==============================================================
499 check_prog('XARGS', ('xargs',))
502 def extra_programs(target):
503 if target.kernel == 'Darwin':
505 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
506 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
507 HFS_TOOL=('hfsplus',)
509 if target.os == 'GNU' and target.kernel == 'Linux':
510 return namespace(RPMBUILD=('rpmbuild',))
512 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
514 check_prog('MKFSHFS', extra_programs.MKFSHFS,
516 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
518 check_prog('RPMBUILD', extra_programs.RPMBUILD,
524 def makensis_progs(target):
525 if target.kernel != 'WINNT':
535 # Look for nsis installed by msys environment. But only the 32-bit version.
536 # We use an absolute path and insert as the first entry so it is preferred
537 # over a 64-bit exe that may be in PATH.
538 if 'MSYSTEM_PREFIX' in os.environ:
539 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
540 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
542 return tuple(candidates)
544 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
546 # Make sure the version of makensis is up to date.
548 @checking('for NSIS version')
550 def nsis_version(nsis):
551 nsis_min_version = '3.0b1'
552 out = check_cmd_output(nsis, '-version',
553 onerror=lambda: die('Failed to get nsis version.'))
554 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
557 raise FatalCheckError('Unknown version of makensis')
558 ver = Version(m.group(0))
560 # Versions comparisons don't quite work well with beta versions, so ensure
561 # it works for the non-beta version.
562 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
563 raise FatalCheckError('To build the installer you must have NSIS'
564 ' version %s or greater in your path'
569 # And that makensis is 32-bit (but only on Windows).
570 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
571 @checking('for 32-bit NSIS')
572 def nsis_binary_type(nsis):
573 bin_type = windows_binary_type(nsis)
574 if bin_type != 'win32':
575 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
579 # And any flags we have to give to makensis
581 def nsis_flags(host):
582 if host.kernel != 'WINNT':
586 set_config('MAKENSISU_FLAGS', nsis_flags)
588 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
591 @depends(c_compiler, bindgen_config_paths)
592 def llvm_objdump(c_compiler, bindgen_config_paths):
594 if c_compiler and c_compiler.type == 'clang':
595 clang = c_compiler.compiler
596 elif c_compiler and c_compiler.type == 'clang-cl':
597 clang = os.path.join(os.path.dirname(c_compiler.compiler), 'clang')
598 elif bindgen_config_paths:
599 clang = bindgen_config_paths.clang_path
600 llvm_objdump = 'llvm-objdump'
602 out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
603 onerror=lambda: None)
605 llvm_objdump = out.rstrip()
606 return (llvm_objdump,)
609 llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
610 when='--enable-compile-environment')
612 add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
615 # Please do not add configure checks from here on.
617 # Fallthrough to autoconf-based configure
618 include('build/moz.configure/old.configure')
621 include('js/sub.configure', when=compile_environment & toolkit)
624 @depends(check_build_environment, build_project)
625 @imports('__sandbox__')
627 def config_status_deps(build_env, build_project):
629 topsrcdir = build_env.topsrcdir
630 topobjdir = build_env.topobjdir
632 if not build_env.topobjdir.endswith('js/src'):
634 os.path.join(topsrcdir, build_project, 'confvars.sh'),
635 os.path.join(topobjdir, '.mozconfig.json'),
638 # mozconfig changes may impact js configure.
639 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
641 return list(__sandbox__._all_paths) + extra_deps + [
642 os.path.join(topsrcdir, 'CLOBBER'),
643 os.path.join(topsrcdir, 'configure'),
644 os.path.join(topsrcdir, 'js', 'src', 'configure'),
645 os.path.join(topsrcdir, 'configure.in'),
646 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
647 os.path.join(topsrcdir, 'nsprpub', 'configure'),
648 os.path.join(topsrcdir, 'config', 'milestone.txt'),
649 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
650 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
651 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
652 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
653 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
654 os.path.join(topsrcdir, 'aclocal.m4'),
655 os.path.join(topsrcdir, 'old-configure.in'),
656 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
657 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
658 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
660 set_config('CONFIG_STATUS_DEPS', config_status_deps)
661 # Please do not add anything after setting config_dep_paths.