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 set_config('MOZ_ARTIFACT_BUILD_SYMBOLS',
35 depends('--enable-artifact-build-symbols')(
36 lambda v: v[0] if len(v) else (bool(v) or None)))
38 @depends('--enable-artifact-builds')
39 def imply_disable_compile_environment(value):
43 option(env='MOZ_COPY_PDBS',
44 help='For builds that do not support symbols in the normal fashion,'
45 ' generate and copy them into the resulting build archive.')
47 set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
49 imply_option('--enable-compile-environment', imply_disable_compile_environment)
51 option('--disable-compile-environment',
52 help='Disable compiler/library checks')
54 @depends('--disable-compile-environment')
55 def compile_environment(compile_env):
59 set_config('COMPILE_ENVIRONMENT', compile_environment)
60 add_old_configure_assignment('COMPILE_ENVIRONMENT', compile_environment)
62 js_option('--disable-tests',
63 help='Do not build test libraries & programs')
65 @depends('--disable-tests')
66 def enable_tests(value):
70 set_config('ENABLE_TESTS', enable_tests)
71 set_define('ENABLE_TESTS', enable_tests)
73 @depends(enable_tests)
74 def gtest_has_rtti(value):
78 set_define('GTEST_HAS_RTTI', gtest_has_rtti)
80 @depends(target, enable_tests)
81 def linux_gtest_defines(target, enable_tests):
82 if enable_tests and target.os == 'Android':
83 return namespace(os_linux_android=True,
84 use_own_tr1_tuple=True,
87 set_define('GTEST_OS_LINUX_ANDROID',
88 linux_gtest_defines.os_linux_android)
89 set_define('GTEST_USE_OWN_TR1_TUPLE',
90 linux_gtest_defines.use_own_tr1_tuple)
91 set_define('GTEST_HAS_CLONE',
92 linux_gtest_defines.has_clone)
94 js_option('--enable-debug',
96 help='Enable building with developer debug info '
97 '(using the given compiler flags).')
99 @depends('--enable-debug')
100 def moz_debug(debug):
104 set_config('MOZ_DEBUG', moz_debug)
105 set_define('MOZ_DEBUG', moz_debug)
106 # Override any value MOZ_DEBUG may have from the environment when passing it
107 # down to old-configure.
108 add_old_configure_assignment('MOZ_DEBUG',
109 depends('--enable-debug')(lambda x: bool(x)))
111 js_option('--enable-rust-debug',
112 default=depends(when='--enable-debug')(lambda: True),
113 help='{Build|Do not build} Rust code with debug assertions turned '
116 @depends(when='--enable-rust-debug')
120 set_config('MOZ_DEBUG_RUST', debug_rust)
121 set_define('MOZ_DEBUG_RUST', debug_rust)
123 js_option(env='MOZ_PGO', help='Build with profile guided optimizations')
125 set_config('MOZ_PGO', depends('MOZ_PGO')(lambda x: bool(x)))
127 include('build/moz.configure/toolchain.configure',
128 when='--enable-compile-environment')
130 include('build/moz.configure/pkg.configure')
131 # Make this assignment here rather than in pkg.configure to avoid
132 # requiring this file in unit tests.
133 add_old_configure_assignment('PKG_CONFIG', pkg_config)
135 include('build/moz.configure/memory.configure',
136 when='--enable-compile-environment')
137 include('build/moz.configure/headers.configure',
138 when='--enable-compile-environment')
139 include('build/moz.configure/warnings.configure',
140 when='--enable-compile-environment')
141 include('build/moz.configure/flags.configure',
142 when='--enable-compile-environment')
143 # rust.configure is included by js/moz.configure.
145 js_option('--enable-valgrind',
146 help='Enable Valgrind integration hooks')
148 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
150 @depends('--enable-valgrind', valgrind_h)
151 def check_valgrind(valgrind, valgrind_h):
154 die('--enable-valgrind specified but Valgrind is not installed')
157 set_define('MOZ_VALGRIND', check_valgrind)
158 set_config('MOZ_VALGRIND', check_valgrind)
160 @depends(target, host)
161 def is_openbsd(target, host):
162 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
164 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
165 help='Shared library version for OpenBSD systems')
167 @depends('SO_VERSION', when=is_openbsd)
168 def so_version(value):
172 def library_name_info_template(host_or_target):
173 assert host_or_target in {host, target}
175 host: host_c_compiler,
179 @depends(host_or_target, compiler, so_version)
180 def library_name_info_impl(host_or_target, compiler, so_version):
181 if host_or_target.kernel == 'WINNT':
182 # There aren't artifacts for mingw builds, so it's OK that the
183 # results are inaccurate in that case.
184 if compiler and compiler.type != 'clang-cl':
186 dll=namespace(prefix='', suffix='.dll'),
187 lib=namespace(prefix='lib', suffix='a'),
188 import_lib=namespace(prefix='lib', suffix='a'),
189 rust_lib=namespace(prefix='', suffix='lib'),
190 obj=namespace(prefix='', suffix='o'),
194 dll=namespace(prefix='', suffix='.dll'),
195 lib=namespace(prefix='', suffix='lib'),
196 import_lib=namespace(prefix='', suffix='lib'),
197 rust_lib=namespace(prefix='', suffix='lib'),
198 obj=namespace(prefix='', suffix='obj'),
201 elif host_or_target.kernel == 'Darwin':
203 dll=namespace(prefix='lib', suffix='.dylib'),
204 lib=namespace(prefix='lib', suffix='a'),
205 import_lib=namespace(prefix=None, suffix=''),
206 rust_lib=namespace(prefix='lib', suffix='a'),
207 obj=namespace(prefix='', suffix='o'),
210 so = '.so.%s' % so_version
215 dll=namespace(prefix='lib', suffix=so),
216 lib=namespace(prefix='lib', suffix='a'),
217 import_lib=namespace(prefix=None, suffix=''),
218 rust_lib=namespace(prefix='lib', suffix='a'),
219 obj=namespace(prefix='', suffix='o'),
222 return library_name_info_impl
224 host_library_name_info = library_name_info_template(host)
225 library_name_info = library_name_info_template(target)
227 set_config('DLL_PREFIX', library_name_info.dll.prefix)
228 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
229 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
230 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
231 set_config('LIB_PREFIX', library_name_info.lib.prefix)
232 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
233 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
234 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
235 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
236 # Lots of compilation tests depend on this variable being present.
237 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
238 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
239 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
240 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
242 include(include_project_configure)
245 @imports(_from='mozbuild.backend', _import='backends')
246 def build_backends_choices(_):
247 return tuple(backends)
250 @deprecated_option('--enable-build-backend', nargs='+',
251 choices=build_backends_choices)
252 def build_backend(backends):
254 return tuple('+%s' % b for b in backends)
256 imply_option('--build-backends', build_backend)
259 @depends('--enable-artifact-builds', '--disable-compile-environment',
260 '--enable-build-backend', '--help')
262 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
264 if 'Tup' in requested_backends:
265 # As a special case, if Tup was requested, do not combine it with any
266 # Make based backend by default.
268 elif artifact_builds:
269 all_backends = ['FasterMake+RecursiveMake']
271 all_backends = ['RecursiveMake', 'FasterMake']
272 # Normally, we'd use target.os == 'WINNT', but a dependency on target
273 # would require target to depend on --help, as well as host and shell,
274 # and this is not a can of worms we can open at the moment.
275 if sys.platform == 'win32' and compile_environment:
276 all_backends.append('VisualStudio')
277 return tuple(all_backends) or None
279 option('--build-backends', nargs='+', default=build_backend_defaults,
280 choices=build_backends_choices, help='Build backends to generate')
282 @depends('--build-backends')
283 def build_backends(backends):
286 set_config('BUILD_BACKENDS', build_backends)
289 @depends(check_build_environment, build_backends)
291 def check_objdir_backend_reuse(build_env, backends):
292 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
293 # intentionally vague for use with the substring match below.
294 incompatible_backends = (
298 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
299 'backend.*Backend')):
300 for prev, curr in incompatible_backends:
301 if prev in backend_file and any(curr in b for b in backends):
302 die("The active objdir, %s, was previously "
303 "used to build with a %s based backend. "
304 "Change objdirs (by setting MOZ_OBJDIR in "
305 "your mozconfig) or clobber to continue.\n",
306 build_env.topobjdir, prev)
309 option('--disable-gtest-in-build',
310 help='Force disable building the gtest libxul during the build.',
311 when='--enable-compile-environment')
313 # Determine whether to build the gtest xul. This happens in automation
314 # on Desktop platforms with the exception of Windows PGO, where linking
315 # xul-gtest.dll takes too long.
316 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
317 enable_tests, when='--enable-compile-environment')
318 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
319 if not enable_tests or not enabled:
321 if (automation and build_project == 'browser' and
322 not (pgo and target.os == 'WINNT')):
325 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
328 # ==============================================================
329 option('--enable-ui-locale', default='en-US',
330 help='Select the user interface locale (default: en-US)')
332 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
334 # clang-plugin location
335 # ==============================================================
336 @depends(host_library_name_info, check_build_environment,
337 when='--enable-clang-plugin')
338 def clang_plugin_path(library_name_info, build_env):
339 topobjdir = build_env.topobjdir
340 if topobjdir.endswith('/js/src'):
341 topobjdir = topobjdir[:-7]
342 return os.path.abspath(
343 os.path.join(topobjdir, 'build', 'clang-plugin',
344 '%sclang-plugin%s' % (library_name_info.dll.prefix,
345 library_name_info.dll.suffix))
348 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
352 # ==============================================================
353 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
355 # Until the AWK variable is not necessary in old-configure
357 def awk_for_old_configure(value):
360 add_old_configure_assignment('AWK', awk_for_old_configure)
364 # ==============================================================
365 perl = check_prog('PERL', ('perl5', 'perl'))
367 # Until the PERL variable is not necessary in old-configure
369 def perl_for_old_configure(value):
372 add_old_configure_assignment('PERL', perl_for_old_configure)
375 def perl_version_check(min_version):
377 @checking('for minimum required perl version >= %s' % min_version)
378 def get_perl_version(perl):
379 return Version(check_cmd_output(
380 perl, '-e', 'print $]',
381 onerror=lambda: die('Failed to get perl version.')
384 @depends(get_perl_version)
385 def check_perl_version(version):
386 if version < min_version:
387 die('Perl %s or higher is required.', min_version)
390 @checking('for full perl installation')
391 @imports('subprocess')
392 def has_full_perl_installation(perl):
393 ret = subprocess.call(
394 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
397 @depends(has_full_perl_installation)
398 def require_full_perl_installation(has_full_perl_installation):
399 if not has_full_perl_installation:
400 die('Cannot find Config.pm or $Config{archlib}. '
401 'A full perl installation is required.')
403 perl_version_check('5.006')
407 # ==============================================================
408 option(env='MAKE', nargs=1, help='Path to GNU make')
410 @depends('MAKE', host)
411 def possible_makes(make, host):
413 if host.kernel == 'WINNT':
414 candidates.append('mingw32-make')
416 candidates.append(make[0])
417 if host.kernel == 'WINNT':
418 candidates.extend(('make', 'gmake'))
420 candidates.extend(('gmake', 'make'))
423 check_prog('GMAKE', possible_makes)
425 @depends(build_backends, build_project)
426 def tup_include(build_backends, build_project):
427 # We need to check the rustc version when building with tup, but
428 # rustc_info isn't available when configuring js (and build_backends isn't
429 # available from project-specific configure), so as a workaround we only
430 # include the file when we know we'll need it. This can be removed when
431 # we globally require a rustc recent enough to build with tup.
432 if build_project not in ('browser', 'mobile/android'):
434 for backend in build_backends:
436 return 'build/moz.configure/tup.configure'
441 # ==============================================================
443 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
445 @depends(host, 'WATCHMAN')
446 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
447 def watchman(host, prog):
448 # On Windows, `watchman` is only supported on 64-bit hosts.
449 if host.os == 'WINNT' and host.cpu != 'x86_64':
453 prog = find_program('watchman')
458 # `watchman version` will talk to the Watchman daemon service.
459 # This can hang due to permissions problems. e.g.
460 # https://github.com/facebook/watchman/issues/376. So use
461 # `watchman --version` to prevent a class of failures.
462 out = check_cmd_output(prog, '--version', onerror=lambda: None)
466 return namespace(path=prog, version=Version(out.strip()))
468 @depends_if(watchman)
469 @checking('for watchman version')
470 def watchman_version(w):
473 set_config('WATCHMAN', watchman.path)
475 @depends_all(hg_version, hg_config, watchman)
476 @checking('for watchman Mercurial integration')
478 def watchman_hg(hg_version, hg_config, watchman):
479 if hg_version < Version('3.8'):
480 return 'no (Mercurial 3.8+ required)'
483 mode_disabled = False
485 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
486 if k in hg_config and hg_config[k] != '!':
489 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
492 return 'no (fsmonitor extension not enabled)'
494 return 'no (fsmonitor.mode=off disables fsmonitor)'
498 # Miscellaneous programs
499 # ==============================================================
500 check_prog('XARGS', ('xargs',))
503 def extra_programs(target):
504 if target.kernel == 'Darwin':
506 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
507 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
508 HFS_TOOL=('hfsplus',)
510 if target.os == 'GNU' and target.kernel == 'Linux':
511 return namespace(RPMBUILD=('rpmbuild',))
513 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
515 check_prog('MKFSHFS', extra_programs.MKFSHFS,
517 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
519 check_prog('RPMBUILD', extra_programs.RPMBUILD,
525 def makensis_progs(target):
526 if target.kernel != 'WINNT':
536 # Look for nsis installed by msys environment. But only the 32-bit version.
537 # We use an absolute path and insert as the first entry so it is preferred
538 # over a 64-bit exe that may be in PATH.
539 if 'MSYSTEM_PREFIX' in os.environ:
540 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
541 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
543 return tuple(candidates)
545 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
547 # Make sure the version of makensis is up to date.
549 @checking('for NSIS version')
551 def nsis_version(nsis):
552 nsis_min_version = '3.0b1'
553 out = check_cmd_output(nsis, '-version',
554 onerror=lambda: die('Failed to get nsis version.'))
555 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
558 raise FatalCheckError('Unknown version of makensis')
559 ver = Version(m.group(0))
561 # Versions comparisons don't quite work well with beta versions, so ensure
562 # it works for the non-beta version.
563 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
564 raise FatalCheckError('To build the installer you must have NSIS'
565 ' version %s or greater in your path'
570 # And that makensis is 32-bit (but only on Windows).
571 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
572 @checking('for 32-bit NSIS')
573 def nsis_binary_type(nsis):
574 bin_type = windows_binary_type(nsis)
575 if bin_type != 'win32':
576 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
580 # And any flags we have to give to makensis
582 def nsis_flags(host):
583 if host.kernel != 'WINNT':
587 set_config('MAKENSISU_FLAGS', nsis_flags)
589 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
592 @depends(host_c_compiler, c_compiler, bindgen_config_paths)
593 def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths):
595 for compiler in (host_c_compiler, c_compiler):
596 if compiler and compiler.type == 'clang':
597 clang = compiler.compiler
599 elif compiler and compiler.type == 'clang-cl':
600 clang = os.path.join(os.path.dirname(compiler.compiler), 'clang')
603 if not clang and bindgen_config_paths:
604 clang = bindgen_config_paths.clang_path
605 llvm_objdump = 'llvm-objdump'
607 out = check_cmd_output(clang, '--print-prog-name=llvm-objdump',
608 onerror=lambda: None)
610 llvm_objdump = out.rstrip()
611 return (llvm_objdump,)
614 llvm_objdump = check_prog('LLVM_OBJDUMP', llvm_objdump, what='llvm-objdump',
615 when='--enable-compile-environment',
616 paths=toolchain_search_path)
618 add_old_configure_assignment('LLVM_OBJDUMP', llvm_objdump)
621 # Please do not add configure checks from here on.
623 # Fallthrough to autoconf-based configure
624 include('build/moz.configure/old.configure')
627 include('js/sub.configure', when=compile_environment & toolkit)
630 @depends(check_build_environment, build_project)
631 @imports('__sandbox__')
633 def config_status_deps(build_env, build_project):
635 topsrcdir = build_env.topsrcdir
636 topobjdir = build_env.topobjdir
638 if not build_env.topobjdir.endswith('js/src'):
640 os.path.join(topsrcdir, build_project, 'confvars.sh'),
641 os.path.join(topobjdir, '.mozconfig.json'),
644 # mozconfig changes may impact js configure.
645 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
647 return list(__sandbox__._all_paths) + extra_deps + [
648 os.path.join(topsrcdir, 'CLOBBER'),
649 os.path.join(topsrcdir, 'configure'),
650 os.path.join(topsrcdir, 'js', 'src', 'configure'),
651 os.path.join(topsrcdir, 'configure.in'),
652 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
653 os.path.join(topsrcdir, 'nsprpub', 'configure'),
654 os.path.join(topsrcdir, 'config', 'milestone.txt'),
655 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
656 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
657 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
658 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
659 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
660 os.path.join(topsrcdir, 'aclocal.m4'),
661 os.path.join(topsrcdir, 'old-configure.in'),
662 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
663 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
664 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
666 set_config('CONFIG_STATUS_DEPS', config_status_deps)
667 # Please do not add anything after setting config_dep_paths.