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 js_option(env='MOZILLA_OFFICIAL',
73 help='Build an official release')
75 @depends('MOZILLA_OFFICIAL')
76 def mozilla_official(official):
80 set_config('MOZILLA_OFFICIAL', mozilla_official)
81 set_define('MOZILLA_OFFICIAL', mozilla_official)
82 add_old_configure_assignment('MOZILLA_OFFICIAL', mozilla_official)
84 @depends(enable_tests)
85 def gtest_has_rtti(value):
89 set_define('GTEST_HAS_RTTI', gtest_has_rtti)
91 @depends(target, enable_tests)
92 def linux_gtest_defines(target, enable_tests):
93 if enable_tests and target.os == 'Android':
94 return namespace(os_linux_android=True,
95 use_own_tr1_tuple=True,
98 set_define('GTEST_OS_LINUX_ANDROID',
99 linux_gtest_defines.os_linux_android)
100 set_define('GTEST_USE_OWN_TR1_TUPLE',
101 linux_gtest_defines.use_own_tr1_tuple)
102 set_define('GTEST_HAS_CLONE',
103 linux_gtest_defines.has_clone)
105 js_option('--enable-debug',
107 help='Enable building with developer debug info '
108 '(using the given compiler flags).')
110 @depends('--enable-debug')
111 def moz_debug(debug):
115 set_config('MOZ_DEBUG', moz_debug)
116 set_define('MOZ_DEBUG', moz_debug)
117 # Override any value MOZ_DEBUG may have from the environment when passing it
118 # down to old-configure.
119 add_old_configure_assignment('MOZ_DEBUG',
120 depends('--enable-debug')(lambda x: bool(x)))
122 js_option('--enable-rust-debug',
123 default=depends(when='--enable-debug')(lambda: True),
124 help='{Build|Do not build} Rust code with debug assertions turned '
127 @depends(when='--enable-rust-debug')
131 set_config('MOZ_DEBUG_RUST', debug_rust)
132 set_define('MOZ_DEBUG_RUST', debug_rust)
134 include('build/moz.configure/pkg.configure')
135 # Make this assignment here rather than in pkg.configure to avoid
136 # requiring this file in unit tests.
137 add_old_configure_assignment('PKG_CONFIG', pkg_config)
139 include('build/moz.configure/toolchain.configure',
140 when='--enable-compile-environment')
141 include('build/moz.configure/memory.configure',
142 when='--enable-compile-environment')
143 include('build/moz.configure/headers.configure',
144 when='--enable-compile-environment')
145 include('build/moz.configure/warnings.configure',
146 when='--enable-compile-environment')
147 include('build/moz.configure/flags.configure',
148 when='--enable-compile-environment')
149 # rust.configure is included by js/moz.configure.
151 js_option('--enable-valgrind',
152 help='Enable Valgrind integration hooks')
154 valgrind_h = check_header('valgrind/valgrind.h', when='--enable-valgrind')
156 @depends('--enable-valgrind', valgrind_h)
157 def check_valgrind(valgrind, valgrind_h):
160 die('--enable-valgrind specified but Valgrind is not installed')
163 set_define('MOZ_VALGRIND', check_valgrind)
164 set_config('MOZ_VALGRIND', check_valgrind)
166 @depends(target, host)
167 def is_openbsd(target, host):
168 return target.kernel == 'OpenBSD' or host.kernel == 'OpenBSD'
170 option(env='SO_VERSION', nargs=1, default='1.0', when=is_openbsd,
171 help='Shared library version for OpenBSD systems')
173 @depends('SO_VERSION', when=is_openbsd)
174 def so_version(value):
178 def library_name_info_template(host_or_target):
179 assert host_or_target in {host, target}
181 host: host_c_compiler,
185 @depends(host_or_target, compiler, so_version)
186 def library_name_info_impl(host_or_target, compiler, so_version):
187 if host_or_target.kernel == 'WINNT':
188 # There aren't artifacts for mingw builds, so it's OK that the
189 # results are inaccurate in that case.
190 if compiler and compiler.type not in ('msvc', 'clang-cl'):
192 dll=namespace(prefix='', suffix='.dll'),
193 lib=namespace(prefix='lib', suffix='a'),
194 import_lib=namespace(prefix='lib', suffix='a'),
195 rust_lib=namespace(prefix='', suffix='lib'),
196 obj=namespace(prefix='', suffix='o'),
200 dll=namespace(prefix='', suffix='.dll'),
201 lib=namespace(prefix='', suffix='lib'),
202 import_lib=namespace(prefix='', suffix='lib'),
203 rust_lib=namespace(prefix='', suffix='lib'),
204 obj=namespace(prefix='', suffix='obj'),
207 elif host_or_target.kernel == 'Darwin':
209 dll=namespace(prefix='lib', suffix='.dylib'),
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 so = '.so.%s' % so_version
221 dll=namespace(prefix='lib', suffix=so),
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 return library_name_info_impl
230 host_library_name_info = library_name_info_template(host)
231 library_name_info = library_name_info_template(target)
233 set_config('DLL_PREFIX', library_name_info.dll.prefix)
234 set_config('DLL_SUFFIX', library_name_info.dll.suffix)
235 set_config('HOST_DLL_PREFIX', host_library_name_info.dll.prefix)
236 set_config('HOST_DLL_SUFFIX', host_library_name_info.dll.suffix)
237 set_config('LIB_PREFIX', library_name_info.lib.prefix)
238 set_config('LIB_SUFFIX', library_name_info.lib.suffix)
239 set_config('RUST_LIB_PREFIX', library_name_info.rust_lib.prefix)
240 set_config('RUST_LIB_SUFFIX', library_name_info.rust_lib.suffix)
241 set_config('OBJ_SUFFIX', library_name_info.obj.suffix)
242 # Lots of compilation tests depend on this variable being present.
243 add_old_configure_assignment('OBJ_SUFFIX', library_name_info.obj.suffix)
244 set_config('IMPORT_LIB_SUFFIX', library_name_info.import_lib.suffix)
245 set_define('MOZ_DLL_PREFIX', depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s))
246 set_define('MOZ_DLL_SUFFIX', depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s))
248 # Depends on host_library_name_info, so needs to go here.
249 include('build/moz.configure/bindgen.configure',
250 when='--enable-compile-environment')
251 include(include_project_configure)
254 @imports(_from='mozbuild.backend', _import='backends')
255 def build_backends_choices(_):
256 return tuple(backends)
259 @deprecated_option('--enable-build-backend', nargs='+',
260 choices=build_backends_choices)
261 def build_backend(backends):
263 return tuple('+%s' % b for b in backends)
265 imply_option('--build-backends', build_backend)
268 @depends('--enable-artifact-builds', '--disable-compile-environment',
269 '--enable-build-backend', '--help')
271 def build_backend_defaults(artifact_builds, compile_environment, requested_backends,
273 if 'Tup' in requested_backends:
274 # As a special case, if Tup was requested, do not combine it with any
275 # Make based backend by default.
277 elif artifact_builds:
278 all_backends = ['FasterMake+RecursiveMake']
280 all_backends = ['RecursiveMake', 'FasterMake']
281 # Normally, we'd use target.os == 'WINNT', but a dependency on target
282 # would require target to depend on --help, as well as host and shell,
283 # and this is not a can of worms we can open at the moment.
284 if sys.platform == 'win32' and compile_environment:
285 all_backends.append('VisualStudio')
286 return tuple(all_backends) or None
288 option('--build-backends', nargs='+', default=build_backend_defaults,
289 choices=build_backends_choices, help='Build backends to generate')
291 @depends('--build-backends')
292 def build_backends(backends):
295 set_config('BUILD_BACKENDS', build_backends)
298 @depends(check_build_environment, build_backends)
300 def check_objdir_backend_reuse(build_env, backends):
301 # "Make based" might be RecursiveMake or a hybrid backend, so "Make" is
302 # intentionally vague for use with the substring match below.
303 incompatible_backends = (
307 for backend_file in glob.iglob(os.path.join(build_env.topobjdir,
308 'backend.*Backend')):
309 for prev, curr in incompatible_backends:
310 if prev in backend_file and any(curr in b for b in backends):
311 die("The active objdir, %s, was previously "
312 "used to build with a %s based backend. "
313 "Change objdirs (by setting MOZ_OBJDIR in "
314 "your mozconfig) or clobber to continue.\n",
315 build_env.topobjdir, prev)
318 option('--disable-gtest-in-build',
319 help='Force disable building the gtest libxul during the build.',
320 when='--enable-compile-environment')
322 # Determine whether to build the gtest xul. This happens in automation
323 # on Desktop platforms with the exception of Windows PGO, where linking
324 # xul-gtest.dll takes too long.
325 @depends('MOZ_PGO', build_project, target, 'MOZ_AUTOMATION', '--disable-gtest-in-build',
326 enable_tests, when='--enable-compile-environment')
327 def build_gtest(pgo, build_project, target, automation, enabled, enable_tests):
328 if not enable_tests or not enabled:
330 if (automation and build_project == 'browser' and
331 not (pgo and target.os == 'WINNT')):
334 set_config('LINK_GTEST_DURING_COMPILE', build_gtest)
337 # ==============================================================
338 option('--enable-ui-locale', default='en-US',
339 help='Select the user interface locale (default: en-US)')
341 set_config('MOZ_UI_LOCALE', depends('--enable-ui-locale')(lambda x: x))
343 # clang-plugin location
344 # ==============================================================
345 @depends(host_library_name_info, check_build_environment,
346 when='--enable-clang-plugin')
347 def clang_plugin_path(library_name_info, build_env):
348 topobjdir = build_env.topobjdir
349 if topobjdir.endswith('/js/src'):
350 topobjdir = topobjdir[:-7]
351 return os.path.abspath(
352 os.path.join(topobjdir, 'build', 'clang-plugin',
353 '%sclang-plugin%s' % (library_name_info.dll.prefix,
354 library_name_info.dll.suffix))
357 add_old_configure_assignment('CLANG_PLUGIN', clang_plugin_path)
361 # ==============================================================
362 awk = check_prog('AWK', ('gawk', 'mawk', 'nawk', 'awk'))
364 # Until the AWK variable is not necessary in old-configure
366 def awk_for_old_configure(value):
369 add_old_configure_assignment('AWK', awk_for_old_configure)
373 # ==============================================================
374 perl = check_prog('PERL', ('perl5', 'perl'))
376 # Until the PERL variable is not necessary in old-configure
378 def perl_for_old_configure(value):
381 add_old_configure_assignment('PERL', perl_for_old_configure)
384 def perl_version_check(min_version):
386 @checking('for minimum required perl version >= %s' % min_version)
387 def get_perl_version(perl):
388 return Version(check_cmd_output(
389 perl, '-e', 'print $]',
390 onerror=lambda: die('Failed to get perl version.')
393 @depends(get_perl_version)
394 def check_perl_version(version):
395 if version < min_version:
396 die('Perl %s or higher is required.', min_version)
399 @checking('for full perl installation')
400 @imports('subprocess')
401 def has_full_perl_installation(perl):
402 ret = subprocess.call(
403 [perl, '-e', 'use Config; exit(!-d $Config{archlib})'])
406 @depends(has_full_perl_installation)
407 def require_full_perl_installation(has_full_perl_installation):
408 if not has_full_perl_installation:
409 die('Cannot find Config.pm or $Config{archlib}. '
410 'A full perl installation is required.')
412 perl_version_check('5.006')
416 # ==============================================================
417 option(env='MAKE', nargs=1, help='Path to GNU make')
419 @depends('MAKE', host)
420 def possible_makes(make, host):
422 if host.kernel == 'WINNT':
423 candidates.append('mingw32-make')
425 candidates.append(make[0])
426 if host.kernel == 'WINNT':
427 candidates.extend(('make', 'gmake'))
429 candidates.extend(('gmake', 'make'))
432 check_prog('GMAKE', possible_makes)
434 @depends(build_backends, build_project)
435 def tup_include(build_backends, build_project):
436 # We need to check the rustc version when building with tup, but
437 # rustc_info isn't available when configuring js (and build_backends isn't
438 # available from project-specific configure), so as a workaround we only
439 # include the file when we know we'll need it. This can be removed when
440 # we globally require a rustc recent enough to build with tup.
441 if build_project not in ('browser', 'mobile/android'):
443 for backend in build_backends:
445 return 'build/moz.configure/tup.configure'
450 # ==============================================================
452 option(env='WATCHMAN', nargs=1, help='Path to the watchman program')
455 @checking('for watchman', callback=lambda w: w.path if w else 'not found')
458 prog = find_program('watchman')
463 # `watchman version` will talk to the Watchman daemon service.
464 # This can hang due to permissions problems. e.g.
465 # https://github.com/facebook/watchman/issues/376. So use
466 # `watchman --version` to prevent a class of failures.
467 out = check_cmd_output(prog, '--version', onerror=lambda: None)
471 return namespace(path=prog, version=Version(out.strip()))
473 @depends_if(watchman)
474 @checking('for watchman version')
475 def watchman_version(w):
478 set_config('WATCHMAN', watchman.path)
480 @depends_all(hg_version, hg_config, watchman)
481 @checking('for watchman Mercurial integration')
483 def watchman_hg(hg_version, hg_config, watchman):
484 if hg_version < Version('3.8'):
485 return 'no (Mercurial 3.8+ required)'
488 mode_disabled = False
490 for k in ('extensions.fsmonitor', 'extensions.hgext.fsmonitor'):
491 if k in hg_config and hg_config[k] != '!':
494 mode_disabled = hg_config.get('fsmonitor.mode') == 'off'
497 return 'no (fsmonitor extension not enabled)'
499 return 'no (fsmonitor.mode=off disables fsmonitor)'
503 # Miscellaneous programs
504 # ==============================================================
505 check_prog('XARGS', ('xargs',))
508 def extra_programs(target):
509 if target.kernel == 'Darwin':
511 DSYMUTIL=('dsymutil', 'llvm-dsymutil'),
512 MKFSHFS=('newfs_hfs', 'mkfs.hfsplus'),
513 HFS_TOOL=('hfsplus',)
515 if target.os == 'GNU' and target.kernel == 'Linux':
516 return namespace(RPMBUILD=('rpmbuild',))
518 check_prog('DSYMUTIL', extra_programs.DSYMUTIL,
520 check_prog('MKFSHFS', extra_programs.MKFSHFS,
522 check_prog('HFS_TOOL', extra_programs.HFS_TOOL,
524 check_prog('RPMBUILD', extra_programs.RPMBUILD,
530 def makensis_progs(target):
531 if target.kernel != 'WINNT':
541 # Look for nsis installed by msys environment. But only the 32-bit version.
542 # We use an absolute path and insert as the first entry so it is preferred
543 # over a 64-bit exe that may be in PATH.
544 if 'MSYSTEM_PREFIX' in os.environ:
545 prefix = os.path.dirname(os.environ['MSYSTEM_PREFIX'])
546 candidates.insert(0, os.path.join(prefix, 'mingw32', 'bin', 'makensis.exe'))
548 return tuple(candidates)
550 nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
552 # Make sure the version of makensis is up to date.
554 @checking('for NSIS version')
556 def nsis_version(nsis):
557 nsis_min_version = '3.0b1'
558 out = check_cmd_output(nsis, '-version',
559 onerror=lambda: die('Failed to get nsis version.'))
560 m = re.search(r'(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?', out)
563 raise FatalCheckError('Unknown version of makensis')
564 ver = Version(m.group(0))
566 # Versions comparisons don't quite work well with beta versions, so ensure
567 # it works for the non-beta version.
568 if ver < nsis_min_version and (ver >= '3.0a' or ver < '3'):
569 raise FatalCheckError('To build the installer you must have NSIS'
570 ' version %s or greater in your path'
575 # And that makensis is 32-bit (but only on Windows).
576 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == 'WINNT'))
577 @checking('for 32-bit NSIS')
578 def nsis_binary_type(nsis):
579 bin_type = windows_binary_type(nsis)
580 if bin_type != 'win32':
581 raise FatalCheckError('%s is not a 32-bit Windows application' % nsis)
585 # And any flags we have to give to makensis
587 def nsis_flags(host):
588 if host.kernel != 'WINNT':
592 set_config('MAKENSISU_FLAGS', nsis_flags)
594 check_prog('7Z', ('7z', '7za'), allow_missing=True, when=target_is_windows)
596 # Fallthrough to autoconf-based configure
597 include('build/moz.configure/old.configure')
599 @depends(check_build_environment, build_project)
600 @imports('__sandbox__')
602 def config_status_deps(build_env, build_project):
604 topsrcdir = build_env.topsrcdir
605 topobjdir = build_env.topobjdir
607 if not build_env.topobjdir.endswith('js/src'):
609 os.path.join(topsrcdir, build_project, 'confvars.sh'),
610 os.path.join(topobjdir, '.mozconfig.json'),
613 # mozconfig changes may impact js configure.
614 extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')]
616 return list(__sandbox__._all_paths) + extra_deps + [
617 os.path.join(topsrcdir, 'CLOBBER'),
618 os.path.join(topsrcdir, 'configure'),
619 os.path.join(topsrcdir, 'js', 'src', 'configure'),
620 os.path.join(topsrcdir, 'configure.in'),
621 os.path.join(topsrcdir, 'js', 'src', 'configure.in'),
622 os.path.join(topsrcdir, 'nsprpub', 'configure'),
623 os.path.join(topsrcdir, 'config', 'milestone.txt'),
624 os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
625 os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
626 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'),
627 os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
628 os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
629 os.path.join(topsrcdir, 'aclocal.m4'),
630 os.path.join(topsrcdir, 'old-configure.in'),
631 os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
632 os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
633 ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
635 set_config('CONFIG_STATUS_DEPS', config_status_deps)
636 # Please do not add anything after setting config_dep_paths.