tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

moz.configure (31504B)


      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/.
      6 
      7 include("build/moz.configure/init.configure")
      8 
      9 # Note:
     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.
     15 # - etc.
     16 
     17 imply_option(
     18     "--enable-artifact-build-symbols",
     19     depends(artifact_builds)(lambda v: False if v is None else None),
     20     reason="--disable-artifact-builds",
     21 )
     22 
     23 option(
     24     "--enable-artifact-build-symbols",
     25     nargs="?",
     26     choices=("full",),
     27     help="Download symbols when artifact builds are enabled",
     28 )
     29 
     30 
     31 @depends("--enable-artifact-build-symbols", moz_automation, target)
     32 def enable_artifact_build_symbols(value, automation, target):
     33     if len(value):
     34         return value[0]
     35     if bool(value):
     36         if target.os == "Android" and not automation:
     37             return "full"
     38         return True
     39     return None
     40 
     41 
     42 set_config("MOZ_ARTIFACT_BUILD_SYMBOLS", enable_artifact_build_symbols)
     43 
     44 
     45 @depends("--enable-artifact-builds", build_project)
     46 def imply_disable_compile_environment(value, build_project):
     47     if value or build_project == "browser/extensions":
     48         return False
     49 
     50 
     51 option(
     52     env="MOZ_BUILD_HOOK",
     53     nargs=1,
     54     help="Path to the moz.build file that will be executed as if it were "
     55     "appended to every moz.build in the tree",
     56 )
     57 
     58 
     59 @depends_if("MOZ_BUILD_HOOK")
     60 @imports("os")
     61 def moz_build_hook(value):
     62     if not os.path.exists(value[0]):
     63         die(f"MOZ_BUILD_HOOK set to {value[0]} but the file doesn't exist")
     64     return os.path.abspath(value[0])
     65 
     66 
     67 set_config("MOZ_BUILD_HOOK", moz_build_hook)
     68 
     69 
     70 option(
     71     env="MOZ_COPY_PDBS",
     72     help="For builds that do not support symbols in the normal fashion,"
     73     " generate and copy them into the resulting build archive",
     74 )
     75 
     76 set_config("MOZ_COPY_PDBS", depends_if("MOZ_COPY_PDBS")(lambda _: True))
     77 
     78 imply_option(
     79     "--enable-compile-environment", imply_disable_compile_environment, reason="default"
     80 )
     81 
     82 option("--disable-compile-environment", help="Disable compiler/library checks")
     83 
     84 
     85 @depends("--disable-compile-environment")
     86 def compile_environment(compile_env):
     87     if compile_env:
     88         return True
     89 
     90 
     91 set_config("COMPILE_ENVIRONMENT", compile_environment)
     92 
     93 option("--disable-tests", help="Do not build test libraries & programs")
     94 
     95 
     96 @depends("--disable-tests")
     97 def enable_tests(value):
     98     if value:
     99         return True
    100 
    101 
    102 set_config("ENABLE_TESTS", enable_tests)
    103 set_define("ENABLE_TESTS", enable_tests)
    104 
    105 
    106 @depends(enable_tests)
    107 def gtest_has_rtti(value):
    108     if value:
    109         return "0"
    110 
    111 
    112 set_define("GTEST_HAS_RTTI", gtest_has_rtti)
    113 
    114 
    115 @depends(target, enable_tests)
    116 def linux_gtest_defines(target, enable_tests):
    117     if enable_tests and target.os == "Android":
    118         return namespace(os_linux_android=True, use_own_tr1_tuple=True, has_clone="0")
    119 
    120 
    121 set_define("GTEST_OS_LINUX_ANDROID", linux_gtest_defines.os_linux_android)
    122 set_define("GTEST_USE_OWN_TR1_TUPLE", linux_gtest_defines.use_own_tr1_tuple)
    123 set_define("GTEST_HAS_CLONE", linux_gtest_defines.has_clone)
    124 
    125 set_define("FMT_API", "MFBT_API")
    126 set_define("FMT_ENFORCE_COMPILE_STRING", 1)
    127 set_define("FMT_USE_EXCEPTIONS", 0)
    128 set_define("FMT_USE_WRITE_CONSOLE", 1)
    129 set_define("FMT_USE_LOCALE", 0)
    130 
    131 option(
    132     "--enable-debug",
    133     nargs="?",
    134     help="Enable building with developer debug info (using the given compiler flags)",
    135 )
    136 
    137 
    138 @depends("--enable-debug")
    139 def moz_debug(debug):
    140     if debug:
    141         return bool(debug)
    142 
    143 
    144 set_config("MOZ_DEBUG", moz_debug)
    145 set_define("MOZ_DEBUG", moz_debug)
    146 
    147 
    148 set_config(
    149     "MOZ_DIAGNOSTIC_ASSERT_ENABLED",
    150     True,
    151     when=moz_debug | milestone.is_early_beta_or_earlier,
    152 )
    153 set_define(
    154     "MOZ_DIAGNOSTIC_ASSERT_ENABLED",
    155     True,
    156     when=moz_debug | milestone.is_early_beta_or_earlier,
    157 )
    158 
    159 option(
    160     "--with-debug-label",
    161     nargs="+",
    162     help="Debug DEBUG_<value> for each comma-separated value given",
    163 )
    164 
    165 
    166 @depends(moz_debug, "--with-debug-label")
    167 def debug_defines(debug, labels):
    168     if debug:
    169         return ["DEBUG"] + ["DEBUG_%s" % label for label in labels]
    170     return ["NDEBUG", "TRIMMED"]
    171 
    172 
    173 set_config("MOZ_DEBUG_DEFINES", debug_defines)
    174 
    175 option(env="MOZ_PGO", help="Build with profile guided optimizations")
    176 
    177 set_config("MOZ_PGO", depends("MOZ_PGO")(lambda x: bool(x)))
    178 
    179 
    180 # Imply --enable-release when MOZILLA_OFFICIAL is set rather than adjusting the
    181 # default so that we can't have both MOZILLA_OFFICIAL and --disable-release set.
    182 imply_option("--enable-release", mozilla_official)
    183 
    184 option(
    185     "--enable-release",
    186     default=milestone.is_release_or_beta | moz_automation,
    187     help="{Build|Do not build} with more conservative, release "
    188     "engineering-oriented options.{ This may slow down builds.|}",
    189 )
    190 
    191 
    192 @depends("--enable-release")
    193 def developer_options(value):
    194     if not value:
    195         return True
    196 
    197 
    198 set_config("DEVELOPER_OPTIONS", developer_options)
    199 
    200 
    201 # hybrid build handling
    202 # ==============================================================
    203 
    204 option(
    205     "--disable-unified-build",
    206     help="Enable building modules in non unified context",
    207 )
    208 
    209 set_config("ENABLE_UNIFIED_BUILD", True, when="--disable-unified-build")
    210 
    211 
    212 include("build/moz.configure/bootstrap.configure")
    213 
    214 
    215 # The execution model of the configure sandbox doesn't allow for
    216 # check_prog to use bootstrap_search_path directly because check_prog
    217 # comes first, so we use a trick to allow it. Uses of check_prog
    218 # happening before here won't allow bootstrap.
    219 
    220 
    221 @template
    222 def check_prog(*args, **kwargs):
    223     kwargs["bootstrap_search_path"] = bootstrap_search_path
    224     return check_prog(*args, **kwargs)
    225 
    226 
    227 include("build/moz.configure/toolchain.configure", when="--enable-compile-environment")
    228 include("build/moz.configure/basebrowser-resources.configure")
    229 include("build/moz.configure/torbrowser-resources.configure")
    230 
    231 include("build/moz.configure/pkg.configure")
    232 include("build/moz.configure/memory.configure", when="--enable-compile-environment")
    233 include("build/moz.configure/headers.configure", when="--enable-compile-environment")
    234 include("build/moz.configure/libraries.configure", when="--enable-compile-environment")
    235 include("build/moz.configure/warnings.configure", when="--enable-compile-environment")
    236 include("build/moz.configure/flags.configure", when="--enable-compile-environment")
    237 include("build/moz.configure/default-flags.configure", when=~compile_environment)
    238 include("build/moz.configure/lto-pgo.configure", when="--enable-compile-environment")
    239 # rust.configure is included by js/moz.configure.
    240 
    241 
    242 option("--enable-valgrind", help="Enable Valgrind integration hooks")
    243 
    244 valgrind_h = check_header("valgrind/valgrind.h", when="--enable-valgrind")
    245 
    246 
    247 @depends("--enable-valgrind", valgrind_h)
    248 def check_valgrind(valgrind, valgrind_h):
    249     if valgrind:
    250         if not valgrind_h:
    251             die("--enable-valgrind specified but Valgrind is not installed")
    252         return True
    253 
    254 
    255 set_define("MOZ_VALGRIND", check_valgrind)
    256 set_config("MOZ_VALGRIND", check_valgrind)
    257 
    258 
    259 @depends(target, host)
    260 def is_openbsd(target, host):
    261     return target.kernel == "OpenBSD" or host.kernel == "OpenBSD"
    262 
    263 
    264 option(
    265     env="SO_VERSION",
    266     nargs=1,
    267     default="1.0",
    268     when=is_openbsd,
    269     help="Shared library version for OpenBSD systems",
    270 )
    271 
    272 
    273 @depends("SO_VERSION", when=is_openbsd)
    274 def so_version(value):
    275     return value
    276 
    277 
    278 @template
    279 def library_name_info_template(host_or_target):
    280     assert host_or_target in {host, target}
    281     windows_abi = {
    282         host: host_windows_abi,
    283         target: target_windows_abi,
    284     }[host_or_target]
    285 
    286     @depends(host_or_target, host_or_target.abi | windows_abi, so_version)
    287     def library_name_info_impl(host_or_target, windows_abi, so_version):
    288         if host_or_target.kernel == "WINNT":
    289             # There aren't artifacts for mingw builds, so it's OK that the
    290             # results are inaccurate in that case.
    291             if windows_abi and windows_abi != "msvc":
    292                 return namespace(
    293                     dll=namespace(prefix="", suffix=".dll"),
    294                     lib=namespace(prefix="lib", suffix="a"),
    295                     import_lib=namespace(prefix="lib", suffix="a"),
    296                     obj=namespace(prefix="", suffix="o"),
    297                 )
    298 
    299             return namespace(
    300                 dll=namespace(prefix="", suffix=".dll"),
    301                 lib=namespace(prefix="", suffix="lib"),
    302                 import_lib=namespace(prefix="", suffix="lib"),
    303                 obj=namespace(prefix="", suffix="obj"),
    304             )
    305 
    306         elif host_or_target.kernel == "Darwin":
    307             return namespace(
    308                 dll=namespace(prefix="lib", suffix=".dylib"),
    309                 lib=namespace(prefix="lib", suffix="a"),
    310                 import_lib=namespace(prefix=None, suffix=""),
    311                 obj=namespace(prefix="", suffix="o"),
    312             )
    313         elif so_version:
    314             so = ".so.%s" % so_version
    315         else:
    316             so = ".so"
    317 
    318         return namespace(
    319             dll=namespace(prefix="lib", suffix=so),
    320             lib=namespace(prefix="lib", suffix="a"),
    321             import_lib=namespace(prefix=None, suffix=""),
    322             obj=namespace(prefix="", suffix="o"),
    323         )
    324 
    325     return library_name_info_impl
    326 
    327 
    328 host_library_name_info = library_name_info_template(host)
    329 library_name_info = library_name_info_template(target)
    330 
    331 set_config("DLL_PREFIX", library_name_info.dll.prefix)
    332 set_config("DLL_SUFFIX", library_name_info.dll.suffix)
    333 set_config("HOST_DLL_PREFIX", host_library_name_info.dll.prefix)
    334 set_config("HOST_DLL_SUFFIX", host_library_name_info.dll.suffix)
    335 set_config("LIB_PREFIX", library_name_info.lib.prefix)
    336 set_config("LIB_SUFFIX", library_name_info.lib.suffix)
    337 set_config("OBJ_SUFFIX", library_name_info.obj.suffix)
    338 set_config("IMPORT_LIB_SUFFIX", library_name_info.import_lib.suffix)
    339 set_define(
    340     "MOZ_DLL_PREFIX", depends(library_name_info.dll.prefix)(lambda s: '"%s"' % s)
    341 )
    342 set_define(
    343     "MOZ_DLL_SUFFIX", depends(library_name_info.dll.suffix)(lambda s: '"%s"' % s)
    344 )
    345 set_config("HOST_LIB_PREFIX", host_library_name_info.lib.prefix)
    346 set_config("HOST_IMPORT_LIB_SUFFIX", host_library_name_info.import_lib.suffix)
    347 set_config("WASM_OBJ_SUFFIX", "wasm")
    348 
    349 
    350 @template
    351 def bin_suffix(host_or_target):
    352     return depends(host_or_target)(
    353         lambda host_or_target: ".exe" if host_or_target.os == "WINNT" else ""
    354     )
    355 
    356 
    357 set_config("BIN_SUFFIX", bin_suffix(target))
    358 set_config("HOST_BIN_SUFFIX", bin_suffix(host))
    359 
    360 
    361 @template
    362 def plain_llvm_or_prefixed(name, llvm_name=None):
    363     # look for a tool, using the following alternatives, in that order:
    364     # 1. llvm-${llvm_name}, or llvm-${name} if ${llvm_name} is not provided
    365     # 2. ${toolchain_prefix}${name}
    366     # 3. ${name}
    367 
    368     @depends(llvm_tool(f"llvm-{llvm_name or name}"), toolchain_prefix)
    369     def plain_llvm_or_prefixed(llvm_tool, toolchain_prefix):
    370         commands = [llvm_tool[0], name]
    371         for prefix in toolchain_prefix or ():
    372             commands.insert(1, f"{prefix}{name}")
    373         return tuple(commands)
    374 
    375     return plain_llvm_or_prefixed
    376 
    377 
    378 def validate_readelf(path):
    379     # llvm-readelf from llvm < 8 doesn't support the GNU binutils-compatible `-d`
    380     # flag. We could try running `$path -d $some_binary` but we might be cross
    381     # compiling and not have a binary at hand to run that against. `$path -d` alone
    382     # would fail whether the flag is supported or not. So we resort to look for the
    383     # option in the `--help` output, which fortunately, s compatible between
    384     # llvm-readelf and readelf.
    385     retcode, stdout, stderr = get_cmd_output(path, "--help")
    386     return retcode == 0 and any(l.startswith("  -d ") for l in stdout.splitlines())
    387 
    388 
    389 @depends("--enable-compile-environment", target, host)
    390 def readelf_when(compile_env, target, host):
    391     return compile_env and any(
    392         x.kernel not in ("Darwin", "WINNT") for x in (target, host)
    393     )
    394 
    395 
    396 readelf = check_prog(
    397     "READELF",
    398     plain_llvm_or_prefixed("readelf"),
    399     when=readelf_when,
    400     paths=clang_search_path,
    401     validate=validate_readelf,
    402 )
    403 
    404 
    405 def validate_objcopy(path):
    406     if "llvm-objcopy" not in path:
    407         return True
    408     # llvm-objcopy doesn't support --only-keep-debug before llvm 9.0.
    409     retcode, stdout, stderr = get_cmd_output(path, "--help")
    410     return retcode == 0 and any(
    411         l.startswith("  --only-keep-debug ") for l in stdout.splitlines()
    412     )
    413 
    414 
    415 check_prog(
    416     "OBJCOPY",
    417     plain_llvm_or_prefixed("objcopy"),
    418     when=readelf_when,
    419     paths=clang_search_path,
    420     validate=validate_objcopy,
    421 )
    422 
    423 
    424 # Make `profiling` available to this file even when js/moz.configure
    425 # doesn't end up included.
    426 profiling = dependable(False)
    427 # Same for js_standalone
    428 js_standalone = dependable(False)
    429 # Same for fold_libs
    430 fold_libs = dependable(False)
    431 # And dmd
    432 dmd = dependable(False)
    433 
    434 # Only available when toolkit/moz.configure is included
    435 pack_relative_relocs_flags = dependable(False)
    436 real_branding_directory = dependable(None)
    437 
    438 include(include_project_configure)
    439 
    440 
    441 @template
    442 def load_keyvalue_file(location, filename):
    443 
    444     @depends(build_environment, location, "--help", when=location)
    445     @checking(f"if configuration file {filename} exists")
    446     # This gives access to the sandbox. Don't copy this blindly.
    447     @imports("__sandbox__")
    448     @imports(_from="mozbuild.configure", _import="confvars")
    449     @imports("os.path")
    450     def load_keyvalue_file_impl(build_env, location, help):
    451         file_path = os.path.join(build_env.topsrcdir, location, filename)
    452         if os.path.exists(file_path):
    453             helper = __sandbox__._helper
    454             # parse confvars
    455             try:
    456                 keyvals = confvars.parse(file_path)
    457             except confvars.ConfVarsSyntaxError as e:
    458                 die(str(e))
    459             for key, value in keyvals.items():
    460                 # FIXME: remove test once we no longer load confvars from old-configure.
    461                 if key in __sandbox__._options:
    462                     # ~= imply_option, but with an accurate origin
    463                     helper.add(f"{key}={value}", origin="confvars", args=helper._args)
    464             return file_path
    465 
    466     return load_keyvalue_file_impl
    467 
    468 
    469 load_confvars = load_keyvalue_file(build_project, "confvars.sh")
    470 load_brandvars = load_keyvalue_file(real_branding_directory, "configure.sh")
    471 
    472 
    473 # Final flags validation and gathering
    474 # -------------------------------------------------
    475 
    476 include(
    477     "build/moz.configure/finalize-flags.configure", when="--enable-compile-environment"
    478 )
    479 
    480 # -------------------------------------------------
    481 
    482 
    483 @depends("--help")
    484 @imports(_from="mozbuild.backend", _import="backends")
    485 def build_backends_choices(_):
    486     return tuple(backends)
    487 
    488 
    489 @deprecated_option("--enable-build-backend", nargs="+", choices=build_backends_choices)
    490 def build_backend(backends):
    491     if backends:
    492         return tuple("+%s" % b for b in backends)
    493 
    494 
    495 imply_option("--build-backends", build_backend)
    496 
    497 
    498 @depends(
    499     host,
    500     target,
    501     "--enable-artifact-builds",
    502     "--disable-compile-environment",
    503     "--enable-project",
    504     "--enable-application",
    505     "--help",
    506 )
    507 @imports("sys")
    508 def build_backend_defaults(
    509     host,
    510     target,
    511     artifact_builds,
    512     compile_environment,
    513     project,
    514     application,
    515     _,
    516 ):
    517     if application:
    518         project = application[0]
    519     elif project:
    520         project = project[0]
    521 
    522     if artifact_builds:
    523         all_backends = ["FasterMake+RecursiveMake"]
    524     else:
    525         all_backends = ["RecursiveMake", "FasterMake"]
    526     if (
    527         host.os == "WINNT"
    528         and target.os == "WINNT"
    529         and compile_environment
    530         and project not in ("mobile/android", "memory", "tools/update-programs")
    531     ):
    532         all_backends.append("VisualStudio")
    533     if compile_environment and project not in ("memory", "tools/update-programs"):
    534         all_backends.append("Clangd")
    535     return tuple(all_backends) or None
    536 
    537 
    538 option(
    539     "--build-backends",
    540     nargs="+",
    541     default=build_backend_defaults,
    542     choices=build_backends_choices,
    543     help="Build backends to generate",
    544 )
    545 
    546 
    547 @depends("--build-backends")
    548 def build_backends(backends):
    549     return backends
    550 
    551 
    552 set_config("BUILD_BACKENDS", build_backends)
    553 
    554 
    555 # Determine whether to build the gtest xul. This happens in automation
    556 # on Android and Desktop platforms with the exception of:
    557 #  - Windows PGO, where linking xul-gtest.dll takes too long;
    558 #  - Android other than x86_64, where gtest is not required.
    559 @depends(
    560     build_project,
    561     target,
    562     moz_automation,
    563     enable_tests,
    564     when="--enable-compile-environment",
    565 )
    566 def build_gtest(build_project, target, automation, enable_tests):
    567     return bool(
    568         enable_tests
    569         and automation
    570         and build_project in ("browser", "comm/mail", "mobile/android")
    571         and not (target.os == "Android" and target.cpu != "x86_64")
    572     )
    573 
    574 
    575 option(
    576     "--enable-gtest-in-build",
    577     default=build_gtest,
    578     help="{Enable|Force disable} building the gtest libxul during the build",
    579     when="--enable-compile-environment",
    580 )
    581 
    582 set_config("LINK_GTEST_DURING_COMPILE", True, when="--enable-gtest-in-build")
    583 
    584 # Localization
    585 # ==============================================================
    586 option(
    587     "--enable-ui-locale",
    588     env="MOZ_UI_LOCALE",
    589     default="en-US",
    590     help="Select the user interface locale (default: en-US)",
    591 )
    592 
    593 
    594 @depends("--enable-ui-locale")
    595 def moz_ui_locale(value):
    596     return value[0]
    597 
    598 
    599 set_config("MOZ_UI_LOCALE", moz_ui_locale)
    600 
    601 
    602 # clang-plugin location
    603 # ==============================================================
    604 include(
    605     "build/moz.configure/clang_plugin.configure", when="--enable-compile-environment"
    606 )
    607 
    608 
    609 # GNU make detection
    610 # ==============================================================
    611 option(env="MAKE", nargs=1, help="Path to GNU make")
    612 
    613 
    614 @depends("MAKE", host)
    615 def possible_makes(make, host):
    616     candidates = []
    617     if make:
    618         candidates.append(make[0])
    619     if host.kernel == "WINNT":
    620         candidates.extend(("mozmake", "mingw32-make", "make", "gmake"))
    621     else:
    622         candidates.extend(("gmake", "make"))
    623     return candidates
    624 
    625 
    626 gmake = check_prog("GMAKE", possible_makes, bootstrap="mozmake")
    627 
    628 
    629 @depends(gmake)
    630 @checking("for gmake version")
    631 def gmake_version(prog):
    632     out = check_cmd_output(prog, "--version")
    633     version_line = out.splitlines()[0]
    634     if not version_line.startswith("GNU Make"):
    635         die("GNU make is required")
    636     return Version(version_line[8:].strip())
    637 
    638 
    639 @depends(gmake_version)
    640 def check_gmake_version(version):
    641     make_min_ver = Version("3.81")
    642     if version < make_min_ver:
    643         die(f"GNU Make {make_min_ver} or higher is required")
    644 
    645 
    646 # watchman detection
    647 # ==============================================================
    648 
    649 option(env="WATCHMAN", nargs=1, help="Path to the watchman program")
    650 
    651 
    652 @depends(host, "WATCHMAN")
    653 @checking("for watchman", callback=lambda w: w.path if w else "not found")
    654 def watchman(host, prog):
    655     # On Windows, `watchman` is only supported on 64-bit hosts.
    656     if host.os == "WINNT" and host.cpu != "x86_64":
    657         return
    658 
    659     if not prog:
    660         prog = find_program("watchman")
    661 
    662     if not prog:
    663         return
    664 
    665     # `watchman version` will talk to the Watchman daemon service.
    666     # This can hang due to permissions problems. e.g.
    667     # https://github.com/facebook/watchman/issues/376. So use
    668     # `watchman --version` to prevent a class of failures.
    669     out = check_cmd_output(prog, "--version", onerror=lambda: None)
    670     if out is None:
    671         return
    672 
    673     return namespace(path=prog, version=Version(out.strip()))
    674 
    675 
    676 @depends_if(watchman)
    677 @checking("for watchman version")
    678 def watchman_version(w):
    679     return w.version
    680 
    681 
    682 set_config("WATCHMAN", watchman.path)
    683 
    684 
    685 @depends_all(hg_version, hg_config, watchman)
    686 @checking("for watchman Mercurial integration")
    687 @imports("os")
    688 def watchman_hg(hg_version, hg_config, watchman):
    689     if hg_version < Version("3.8"):
    690         return "no (Mercurial 3.8+ required)"
    691 
    692     ext_enabled = False
    693     mode_disabled = False
    694 
    695     for k in ("extensions.fsmonitor", "extensions.hgext.fsmonitor"):
    696         if k in hg_config and hg_config[k] != "!":
    697             ext_enabled = True
    698 
    699     mode_disabled = hg_config.get("fsmonitor.mode") == "off"
    700 
    701     if not ext_enabled:
    702         return "no (fsmonitor extension not enabled)"
    703     if mode_disabled:
    704         return "no (fsmonitor.mode=off disables fsmonitor)"
    705 
    706     return True
    707 
    708 
    709 # Miscellaneous programs
    710 # ==============================================================
    711 check_prog("XARGS", ("xargs",))
    712 
    713 
    714 @depends(target)
    715 def extra_programs(target):
    716     if target.kernel == "Darwin":
    717         return namespace(
    718             MKFSHFS=("newfs_hfs", "mkfs.hfsplus"),
    719             HFS_TOOL=("hfsplus",),
    720         )
    721 
    722 
    723 check_prog("MKFSHFS", extra_programs.MKFSHFS, allow_missing=True)
    724 check_prog("HFS_TOOL", extra_programs.HFS_TOOL, allow_missing=True)
    725 
    726 
    727 nsis = check_prog(
    728     "MAKENSISU",
    729     ("makensis",),
    730     bootstrap="nsis/bin",
    731     allow_missing=True,
    732     when=target_is_windows,
    733 )
    734 
    735 # Make sure the version of makensis is up to date.
    736 
    737 
    738 @depends_if(nsis)
    739 @checking("for NSIS version")
    740 @imports("re")
    741 def nsis_version(nsis):
    742     nsis_min_version = "3.0b1"
    743 
    744     def onerror():
    745         return die("Failed to get nsis version.")
    746 
    747     out = check_cmd_output(nsis, "-version", onerror=onerror)
    748 
    749     m = re.search(r"(?<=v)[0-9]+\.[0-9]+((a|b|rc)[0-9]+)?", out)
    750 
    751     if not m:
    752         raise FatalCheckError("Unknown version of makensis")
    753     ver = Version(m.group(0))
    754 
    755     # Versions comparisons don't quite work well with beta versions, so ensure
    756     # it works for the non-beta version.
    757     if ver < nsis_min_version and (ver >= "3.0a" or ver < "3"):
    758         raise FatalCheckError(
    759             "To build the installer you must have NSIS"
    760             " version %s or greater in your path" % nsis_min_version
    761         )
    762 
    763     return ver
    764 
    765 
    766 # And that makensis is 32-bit (but only on Windows).
    767 @depends_if(nsis, when=depends(host)(lambda h: h.kernel == "WINNT"))
    768 @checking("for 32-bit NSIS")
    769 def nsis_binary_type(nsis):
    770     bin_type = windows_binary_type(nsis)
    771     if bin_type != "win32":
    772         raise FatalCheckError("%s is not a 32-bit Windows application" % nsis)
    773 
    774     return "yes"
    775 
    776 
    777 # And any flags we have to give to makensis
    778 @depends(host)
    779 def nsis_flags(host):
    780     if host.kernel != "WINNT":
    781         return "-nocd"
    782     return ""
    783 
    784 
    785 set_config("MAKENSISU_FLAGS", nsis_flags)
    786 
    787 check_prog("7Z", ("7z", "7za"), allow_missing=True, when=target_is_windows)
    788 check_prog("UPX", ("upx",), allow_missing=True, when=target_is_windows)
    789 
    790 
    791 check_prog(
    792     "DSYMUTIL",
    793     llvm_tool("dsymutil"),
    794     when=compile_environment & target_is_darwin,
    795     paths=clang_search_path,
    796 )
    797 
    798 
    799 check_prog(
    800     "OTOOL",
    801     plain_llvm_or_prefixed("otool"),
    802     when=compile_environment & target_is_darwin,
    803     paths=clang_search_path,
    804 )
    805 
    806 check_prog(
    807     "INSTALL_NAME_TOOL",
    808     plain_llvm_or_prefixed("install_name_tool", llvm_name="install-name-tool"),
    809     when=compile_environment & target_is_darwin & js_standalone,
    810     paths=clang_search_path,
    811 )
    812 
    813 option(
    814     "--enable-strip",
    815     when=compile_environment,
    816     help="Enable stripping of libs & executables",
    817 )
    818 
    819 # This should be handled as a `when` once bug 1617793 is fixed.
    820 
    821 
    822 @depends("--enable-strip", c_compiler, when=compile_environment)
    823 def enable_strip(strip, c_compiler):
    824     if strip and c_compiler.type != "clang-cl":
    825         return True
    826 
    827 
    828 set_config("ENABLE_STRIP", enable_strip)
    829 
    830 option(
    831     "--disable-install-strip",
    832     when=compile_environment,
    833     help="Enable stripping of libs & executables when packaging",
    834 )
    835 
    836 # This should be handled as a `when` once bug 1617793 is fixed.
    837 
    838 
    839 @depends("--enable-install-strip", c_compiler, when=compile_environment)
    840 def enable_install_strip(strip, c_compiler):
    841     if strip and c_compiler.type != "clang-cl":
    842         return True
    843 
    844 
    845 set_config("PKG_STRIP", enable_install_strip)
    846 
    847 
    848 @depends("--enable-strip", "--enable-install-strip", when=compile_environment)
    849 def strip(strip, install_strip):
    850     return strip or install_strip
    851 
    852 
    853 option(env="STRIP_FLAGS", nargs=1, when=strip, help="Flags for the strip command")
    854 
    855 
    856 @depends("STRIP_FLAGS", profiling, target, when=strip)
    857 def strip_flags(flags, profiling, target):
    858     if flags:
    859         return flags[0].split()
    860     if profiling:
    861         # Only strip debug info and symbols when profiling is enabled, keeping
    862         # local symbols.
    863         if target.kernel == "Darwin":
    864             return ["-S"]
    865         elif target.os == "Android":
    866             # The tooling we use with Android supports detached symbols, and the
    867             # size increase caused by local symbols are too much for mobile. So,
    868             # don't restrict the amount of stripping with a flag.
    869             return
    870         else:
    871             return ["--strip-debug"]
    872     # Otherwise strip everything we can, which happens without flags on non-Darwin.
    873     # On Darwin, it tries to strip things it can't, so we need to limit its scope.
    874     elif target.kernel == "Darwin":
    875         return ["-x", "-S"]
    876 
    877 
    878 set_config("STRIP_FLAGS", strip_flags)
    879 
    880 
    881 def validate_strip(path):
    882     if "llvm-strip" not in path:
    883         return True
    884     # llvm-strip doesn't support -S before llvm 8.0.
    885     retcode, stdout, stderr = get_cmd_output(path, "--help")
    886     return retcode == 0 and any(l.startswith("  -S ") for l in stdout.splitlines())
    887 
    888 
    889 @depends("--enable-compile-environment", target, host)
    890 def strip_when(compile_env, target, host):
    891     return compile_env and any(x.kernel != "WINNT" for x in (target, host))
    892 
    893 
    894 check_prog(
    895     "STRIP",
    896     plain_llvm_or_prefixed("strip"),
    897     when=strip_when,
    898     paths=clang_search_path,
    899     validate=validate_strip,
    900 )
    901 
    902 
    903 @depends(js_standalone, target)
    904 def system_zlib_default(js_standalone, target):
    905     return (
    906         js_standalone
    907         and target.kernel not in ("WINNT", "Darwin")
    908         and target.os != "Android"
    909     )
    910 
    911 
    912 option(
    913     "--with-system-zlib",
    914     nargs="?",
    915     default=system_zlib_default,
    916     help="{Use|Do not use} system libz",
    917     when=use_pkg_config,
    918 )
    919 
    920 
    921 @depends("--with-system-zlib", when=use_pkg_config)
    922 def with_system_zlib_option(with_system_zlib):
    923     return with_system_zlib
    924 
    925 
    926 @depends(with_system_zlib_option)
    927 def deprecated_system_zlib_path(value):
    928     if value and len(value) == 1:
    929         die(
    930             "--with-system-zlib=PATH is not supported anymore. Please use "
    931             "--with-system-zlib and set any necessary pkg-config environment variable."
    932         )
    933 
    934 
    935 pkg_check_modules("MOZ_ZLIB", "zlib >= 1.2.3", when="--with-system-zlib")
    936 
    937 set_config("MOZ_SYSTEM_ZLIB", True, when="--with-system-zlib")
    938 
    939 option(
    940     env="USE_LIBZ_RS",
    941     default=milestone.is_early_beta_or_earlier,
    942     help="Use libz-rs-sys instead of zlib",
    943     when=toolkit & ~with_system_zlib_option,
    944 )
    945 
    946 set_config("USE_LIBZ_RS", True, when="USE_LIBZ_RS")
    947 
    948 with only_when(cross_compiling):
    949     option(
    950         env="JS_BINARY",
    951         nargs=1,
    952         help="Host JavaScript runtime, if any, to use during cross compiles",
    953     )
    954     set_config("JS_BINARY", depends_if("JS_BINARY")(lambda value: value[0]))
    955 
    956 option(
    957     "--with-relative-data-dir",
    958     nargs=1,
    959     help="Sets the data directories to be relative to the application directory",
    960 )
    961 
    962 
    963 @depends("--with-relative-data-dir", target)
    964 @imports("json")
    965 def relative_data_dir(value, target):
    966     if value and target.os == "Android":
    967         die("--with-relative-data-dir is not supported on Android")
    968     if value:
    969         return json.dumps(value[0])
    970 
    971 
    972 set_define("RELATIVE_DATA_DIR", relative_data_dir)
    973 
    974 
    975 option(
    976     "--with-base-browser-version",
    977     nargs=1,
    978     help="Set the Base Browser version, e.g., 7.0a1",
    979 )
    980 
    981 
    982 @depends("--with-base-browser-version")
    983 def base_browser_version(value):
    984     if not value:
    985         die(
    986             "--with-base-browser-version is required for Base Browser and derived browsers."
    987         )
    988     return value[0]
    989 
    990 
    991 @depends("--with-base-browser-version")
    992 def base_browser_version_quoted(value):
    993     if not value:
    994         die(
    995             "--with-base-browser-version is required for Base Browser and derived browsers."
    996         )
    997     if '"' in value or "\\" in value:
    998         die('--with-base-browser-version cannot contain " or \\.')
    999     return f'"{value[0]}"'
   1000 
   1001 
   1002 set_define("BASE_BROWSER_VERSION", base_browser_version)
   1003 set_define("BASE_BROWSER_VERSION_QUOTED", base_browser_version_quoted)
   1004 
   1005 
   1006 # Tor Browser additions.
   1007 
   1008 # We always want Tor Browser to be defined. Since we do not need any
   1009 # value for it, just always set it to True.
   1010 set_define("TOR_BROWSER", True)
   1011 
   1012 
   1013 # Please do not add configure checks from here on.
   1014 
   1015 
   1016 # Assuming no other option is declared after this function, handle the
   1017 # env options that were injected by mozconfig_options by creating dummy
   1018 # Option instances and having the sandbox's CommandLineHelper handle
   1019 # them. We only do so for options that haven't been declared so far,
   1020 # which should be a proxy for the options that old-configure handles
   1021 # and that we don't know anything about.
   1022 @depends("--help")
   1023 @imports("__sandbox__")
   1024 @imports(_from="mozbuild.configure.options", _import="Option")
   1025 def remaining_mozconfig_options(_):
   1026     helper = __sandbox__._helper
   1027     for arg in list(helper):
   1028         if helper._origins[arg] != "mozconfig":
   1029             continue
   1030         name = arg.split("=", 1)[0]
   1031         if name.isupper() and name not in __sandbox__._options:
   1032             option = Option(env=name, nargs="*", help=name)
   1033             helper.handle(option)
   1034 
   1035 
   1036 @depends(build_environment, configure_cache)
   1037 @imports(_import="json")
   1038 @imports(_from="pathlib", _import="Path")
   1039 def save_cache(build_environment, configure_cache):
   1040     cache_file = Path(build_environment.topobjdir) / "configure.cache"
   1041 
   1042     with cache_file.open(mode="w") as fd:
   1043         json.dump(configure_cache, fd, indent=4)
   1044 
   1045 
   1046 @depends(build_environment, build_project)
   1047 @imports("__sandbox__")
   1048 @imports(_from="os.path", _import="exists")
   1049 def config_status_deps(build_env, build_project):
   1050     topsrcdir = build_env.topsrcdir
   1051     topobjdir = build_env.topobjdir
   1052 
   1053     if not topobjdir.endswith("js/src"):
   1054         extra_deps = [os.path.join(topobjdir, ".mozconfig.json")]
   1055     else:
   1056         # mozconfig changes may impact js configure.
   1057         extra_deps = [os.path.join(topobjdir[:-7], ".mozconfig.json")]
   1058 
   1059     confvars = os.path.join(topsrcdir, build_project, "confvars.sh")
   1060     if exists(confvars):
   1061         extra_deps.append(confvars)
   1062 
   1063     return (
   1064         list(__sandbox__._all_paths)
   1065         + extra_deps
   1066         + [
   1067             os.path.join(topsrcdir, "CLOBBER"),
   1068             os.path.join(topsrcdir, "configure"),
   1069             os.path.join(topsrcdir, "js", "src", "configure"),
   1070             os.path.join(topsrcdir, "nsprpub", "configure"),
   1071             os.path.join(topsrcdir, "config", "milestone.txt"),
   1072             os.path.join(topsrcdir, "browser", "config", "version.txt"),
   1073             os.path.join(topsrcdir, "browser", "config", "version_display.txt"),
   1074             os.path.join(topsrcdir, "python", "sites", "build.txt"),
   1075             os.path.join(topsrcdir, "python", "sites", "common.txt"),
   1076             os.path.join(topsrcdir, "python", "sites", "mach.txt"),
   1077             os.path.join(topsrcdir, "python", "mach", "mach", "site.py"),
   1078         ]
   1079     )
   1080 
   1081 
   1082 set_config("CONFIG_STATUS_DEPS", config_status_deps)
   1083 # Please do not add anything after setting config_dep_paths.