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 include('build/moz.configure/pkg.configure')
123 # Make this assignment here rather than in pkg.configure to avoid
124 # requiring this file in unit tests.
125 add_old_configure_assignment('PKG_CONFIG', pkg_config)
127 include('build/moz.configure/toolchain.configure',
128 when='--enable-compile-environment')
129 include('build/moz.configure/memory.configure',
130 when='--enable-compile-environment')
131 include('build/moz.configure/headers.configure',
132 when='--enable-compile-environment')
133 include('build/moz.configure/warnings.configure',
134 when='--enable-compile-environment')
135 include('build/moz.configure/flags.configure',
136 when='--enable-compile-environment')
137 # rust.configure is included by js/moz.configure.
139 js_option('--enable-valgrind',
140 help='Enable Valgrind integration hooks')
142 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
144 @depends('--enable-valgrind', valgrind_h)
145 def check_valgrind(valgrind, valgrind_h):
148 die('--enable-valgrind specified but Valgrind is not installed')
151 set_define('MOZ_VALGRIND', check_valgrind)
152 set_config('MOZ_VALGRIND', check_valgrind)
154 @depends(target, host)
155 def is_openbsd(target, host):
156 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
158 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
159 help='Shared library version for OpenBSD systems')
161 @depends('SO_VERSION', when=is_openbsd)
162 def so_version(value):
166 def library_name_info_template(host_or_target):
167 assert host_or_target in {host, target}
169 host: host_c_compiler,
173 @depends(host_or_target, compiler, so_version)
174 def library_name_info_impl(host_or_target, compiler, so_version):
175 if host_or_target.kernel == 'WINNT':
176 # There aren't artifacts for mingw builds, so it's OK that the
177 # results are inaccurate in that case.
178 if compiler and compiler.type not in ('msvc', 'clang-cl'):
180 dll=namespace(prefix='', suffix='.dll'),
181 lib=namespace(prefix='lib', suffix='a'),
182 import_lib=namespace(prefix='lib', suffix='a'),
183 rust_lib=namespace(prefix='', suffix='lib'),
184 obj=namespace(prefix='', suffix='o'),
188 dll=namespace(prefix='', suffix='.dll'),
189 lib=namespace(prefix='', suffix='lib'),
190 import_lib=namespace(prefix='', suffix='lib'),
191 rust_lib=namespace(prefix='', suffix='lib'),
192 obj=namespace(prefix='', suffix='obj'),
195 elif host_or_target.kernel == 'Darwin':
197 dll=namespace(prefix='lib', suffix='.dylib'),
198 lib=namespace(prefix='lib', suffix='a'),
199 import_lib=namespace(prefix=None, suffix=''),
200 rust_lib=namespace(prefix='lib', suffix='a'),
201 obj=namespace(prefix='', suffix='o'),
204 so = '.so.%s' % so_version
209 dll=namespace(prefix='lib', suffix=so),
210 lib=namespace(prefix='lib', suffix='a'),
211 import_lib=namespace(prefix=None, suffix=''),
212 rust_lib=namespace(prefix='lib', suffix='a'),
213 obj=namespace(prefix='', suffix='o'),
216 return library_name_info_impl
218 host_library_name_info = library_name_info_template(host)
219 library_name_info = library_name_info_template(target)
221 set_config('DLL_PREFIX', library_name_info.dll.prefix)
222 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
223 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
224 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
225 set_config('LIB_PREFIX', library_name_info.lib.prefix)
226 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
227 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
228 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
229 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
230 # Lots of compilation tests depend on this variable being present.
231 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
232 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
233 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
234 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
236 # Depends on host_library_name_info, so needs to go here.
237 include('build/moz.configure/bindgen.configure',
238 when='--enable-compile-environment')
239 include(include_project_configure)
242 @imports(_from='mozbuild.backend', _import='backends')
243 def build_backends_choices(_):
244 return tuple(backends)
247 @deprecated_option('--enable-build-backend', nargs='+',
248 choices=build_backends_choices)
249 def build_backend(backends):
251 return tuple('+%s' % b for b in backends)
253 imply_option('--build-backends', build_backend)
256 @depends('--enable-artifact-builds', '--disable-compile-environment',
257 '--enable-build-backend', '--help')
259 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
261 if 'Tup' in requested_backends:
262 # As a special case, if Tup was requested, do not combine it with any
263 # Make based backend by default.
265 elif artifact_builds:
266 all_backends = ['FasterMake+RecursiveMake']
268 all_backends = ['RecursiveMake', 'FasterMake']
269 # Normally, we'd use target.os == 'WINNT', but a dependency on target
270 # would require target to depend on --help, as well as host and shell,
271 # and this is not a can of worms we can open at the moment.
272 if sys.platform == 'win32' and compile_environment:
273 all_backends.append('VisualStudio')
274 return tuple(all_backends) or None
276 option('--build-backends', nargs='+', default=build_backend_defaults,
277 choices=build_backends_choices, help='Build backends to generate')
279 @depends('--build-backends')
280 def build_backends(backends):
283 set_config('BUILD_BACKENDS', build_backends)
286 @depends(check_build_environment, build_backends)
288 def check_objdir_backend_reuse(build_env, backends):
289 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
290 # intentionally vague for use with the substring match below.
291 incompatible_backends = (
295 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
296 'backend.*Backend')):
297 for prev, curr in incompatible_backends:
298 if prev in backend_file and any(curr in b for b in backends):
299 die("The active objdir, %s, was previously "
300 "used to build with a %s based backend. "
301 "Change objdirs (by setting MOZ_OBJDIR in "
302 "your mozconfig) or clobber to continue.\n",
303 build_env.topobjdir, prev)
306 option('--disable-gtest-in-build',
307 help='Force disable building the gtest libxul during the build.',
308 when='--enable-compile-environment')
310 # Determine whether to build the gtest xul. This happens in automation
311 # on Desktop platforms with the exception of Windows PGO, where linking
312 # xul-gtest.dll takes too long.
313 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
314 enable_tests, when='--enable-compile-environment')
315 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
316 if not enable_tests or not enabled:
318 if (automation and build_project == 'browser' and
319 not (pgo and target.os == 'WINNT')):
322 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
325 # ==============================================================
326 option('--enable-ui-locale', default='en-US',
327 help='Select the user interface locale (default: en-US)')
329 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
331 # clang-plugin location
332 # ==============================================================
333 @depends(host_library_name_info, check_build_environment,
334 when='--enable-clang-plugin')
335 def clang_plugin_path(library_name_info, build_env):
336 topobjdir = build_env.topobjdir
337 if topobjdir.endswith('/js/src'):
338 topobjdir = topobjdir[:-7]
339 return os.path.abspath(
340 os.path.join(topobjdir, 'build', 'clang-plugin',
341 '%sclang-plugin%s' % (library_name_info.dll.prefix,
342 library_name_info.dll.suffix))
345 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
349 # ==============================================================
350 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
352 # Until the AWK variable is not necessary in old-configure
354 def awk_for_old_configure(value):
357 add_old_configure_assignment('AWK', awk_for_old_configure)
361 # ==============================================================
362 perl = check_prog('PERL', ('perl5', 'perl'))
364 # Until the PERL variable is not necessary in old-configure
366 def perl_for_old_configure(value):
369 add_old_configure_assignment('PERL', perl_for_old_configure)
372 def perl_version_check(min_version):
374 @checking('for minimum required perl version >= %s' % min_version)
375 def get_perl_version(perl):
376 return Version(check_cmd_output(
377 perl, '-e', 'print $]',
378 onerror=lambda: die('Failed to get perl version.')
381 @depends(get_perl_version)
382 def check_perl_version(version):
383 if version < min_version:
384 die('Perl %s or higher is required.', min_version)
387 @checking('for full perl installation')
388 @imports('subprocess')
389 def has_full_perl_installation(perl):
390 ret = subprocess.call(
391 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
394 @depends(has_full_perl_installation)
395 def require_full_perl_installation(has_full_perl_installation):
396 if not has_full_perl_installation:
397 die('Cannot find Config.pm or $Config{archlib}. '
398 'A full perl installation is required.')
400 perl_version_check('5.006')
404 # ==============================================================
405 option(env='MAKE', nargs=1, help='Path to GNU make')
407 @depends('MAKE', host)
408 def possible_makes(make, host):
410 if host.kernel == 'WINNT':
411 candidates.append('mingw32-make')
413 candidates.append(make[0])
414 if host.kernel == 'WINNT':
415 candidates.extend(('make', 'gmake'))
417 candidates.extend(('gmake', 'make'))
420 check_prog('GMAKE', possible_makes)
422 @depends(build_backends, build_project)
423 def tup_include(build_backends, build_project):
424 # We need to check the rustc version when building with tup, but
425 # rustc_info isn't available when configuring js (and build_backends isn't
426 # available from project-specific configure), so as a workaround we only
427 # include the file when we know we'll need it. This can be removed when
428 # we globally require a rustc recent enough to build with tup.
429 if build_project not in ('browser', 'mobile/android'):
431 for backend in build_backends:
433 return 'build/moz.configure/tup.configure'
438 # ==============================================================
440 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
443 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
446 prog = find_program('watchman')
451 # `watchman version` will talk to the Watchman daemon service.
452 # This can hang due to permissions problems. e.g.
453 # https://github.com/facebook/watchman/issues/376. So use
454 # `watchman --version` to prevent a class of failures.
455 out = check_cmd_output(prog, '--version', onerror=lambda: None)
459 return namespace(path=prog, version=Version(out.strip()))
461 @depends_if(watchman)
462 @checking('for watchman version')
463 def watchman_version(w):
466 set_config('WATCHMAN', watchman.path)
468 @depends_all(hg_version, hg_config, watchman)
469 @checking('for watchman Mercurial integration')
471 def watchman_hg(hg_version, hg_config, watchman):
472 if hg_version < Version('3.8'):
473 return 'no (Mercurial 3.8+ required)'
476 mode_disabled = False
478 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
479 if k in hg_config and hg_config[k] != '!':
482 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
485 return 'no (fsmonitor extension not enabled)'
487 return 'no (fsmonitor.mode=off disables fsmonitor)'
491 # Miscellaneous programs
492 # ==============================================================
493 check_prog('XARGS', ('xargs',))
496 def extra_programs(target):
497 if target.kernel == 'Darwin':
499 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
500 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
501 HFS_TOOL=('hfsplus',)
503 if target.os == 'GNU' and target.kernel == 'Linux':
504 return namespace(RPMBUILD=('rpmbuild',))
506 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
508 check_prog('MKFSHFS', extra_programs.MKFSHFS,
510 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
512 check_prog('RPMBUILD', extra_programs.RPMBUILD,
518 def makensis_progs(target):
519 if target.kernel != 'WINNT':
529 # Look for nsis installed by msys environment. But only the 32-bit version.
530 # We use an absolute path and insert as the first entry so it is preferred
531 # over a 64-bit exe that may be in PATH.
532 if 'MSYSTEM_PREFIX' in os.environ:
533 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
534 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
536 return tuple(candidates)
538 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
540 # Make sure the version of makensis is up to date.
542 @checking('for NSIS version')
544 def nsis_version(nsis):
545 nsis_min_version = '3.0b1'
546 out = check_cmd_output(nsis, '-version',
547 onerror=lambda: die('Failed to get nsis version.'))
548 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
551 raise FatalCheckError('Unknown version of makensis')
552 ver = Version(m.group(0))
554 # Versions comparisons don't quite work well with beta versions, so ensure
555 # it works for the non-beta version.
556 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
557 raise FatalCheckError('To build the installer you must have NSIS'
558 ' version %s or greater in your path'
563 # And that makensis is 32-bit (but only on Windows).
564 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
565 @checking('for 32-bit NSIS')
566 def nsis_binary_type(nsis):
567 bin_type = windows_binary_type(nsis)
568 if bin_type != 'win32':
569 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
573 # And any flags we have to give to makensis
575 def nsis_flags(host):
576 if host.kernel != 'WINNT':
580 set_config('MAKENSISU_FLAGS', nsis_flags)
582 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
584 # Fallthrough to autoconf-based configure
585 include('build/moz.configure/old.configure')
587 @depends(check_build_environment, build_project)
588 @imports('__sandbox__')
590 def config_status_deps(build_env, build_project):
592 topsrcdir = build_env.topsrcdir
593 topobjdir = build_env.topobjdir
595 if not build_env.topobjdir.endswith('js/src'):
597 os.path.join(topsrcdir, build_project, 'confvars.sh'),
598 os.path.join(topobjdir, '.mozconfig.json'),
601 # mozconfig changes may impact js configure.
602 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
604 return list(__sandbox__._all_paths) + extra_deps + [
605 os.path.join(topsrcdir, 'CLOBBER'),
606 os.path.join(topsrcdir, 'configure'),
607 os.path.join(topsrcdir, 'js', 'src', 'configure'),
608 os.path.join(topsrcdir, 'configure.in'),
609 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
610 os.path.join(topsrcdir, 'nsprpub', 'configure'),
611 os.path.join(topsrcdir, 'config', 'milestone.txt'),
612 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
613 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
614 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
615 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
616 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
617 os.path.join(topsrcdir, 'aclocal.m4'),
618 os.path.join(topsrcdir, 'old-configure.in'),
619 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
620 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
621 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
623 set_config('CONFIG_STATUS_DEPS', config_status_deps)
624 # Please do not add anything after setting config_dep_paths.