summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/rust.configure
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /build/moz.configure/rust.configure
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'build/moz.configure/rust.configure')
-rw-r--r--build/moz.configure/rust.configure786
1 files changed, 786 insertions, 0 deletions
diff --git a/build/moz.configure/rust.configure b/build/moz.configure/rust.configure
new file mode 100644
index 0000000000..7a2fd1ae70
--- /dev/null
+++ b/build/moz.configure/rust.configure
@@ -0,0 +1,786 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+# Rust is required by `rust_compiler` below. We allow_missing here
+# to propagate failures to the better error message there.
+option(env="RUSTC", nargs=1, help="Path to the rust compiler")
+option(env="CARGO", nargs=1, help="Path to the Cargo package manager")
+
+rustc = check_prog(
+ "_RUSTC",
+ ["rustc"],
+ what="rustc",
+ paths=rust_search_path,
+ input="RUSTC",
+ allow_missing=True,
+)
+cargo = check_prog(
+ "_CARGO",
+ ["cargo"],
+ what="cargo",
+ paths=rust_search_path,
+ input="CARGO",
+ allow_missing=True,
+)
+
+
+@template
+def unwrap_rustup(prog, name):
+ # rustc and cargo can either be rustup wrappers, or they can be the actual,
+ # plain executables. For cargo, on OSX, rustup sets DYLD_LIBRARY_PATH (at
+ # least until https://github.com/rust-lang/rustup.rs/pull/1752 is merged
+ # and shipped) and that can wreak havoc (see bug 1536486). Similarly, for
+ # rustc, rustup silently honors toolchain overrides set by vendored crates
+ # (see bug 1547196).
+ #
+ # In either case, we need to find the plain executables.
+ #
+ # To achieve that, try to run `PROG +stable`. When the rustup wrapper is in
+ # use, it either prints PROG's help and exits with status 0, or prints
+ # an error message (error: toolchain 'stable' is not installed) and exits
+ # with status 1. In the cargo case, when plain cargo is in use, it exits
+ # with a different error message (e.g. "error: no such subcommand:
+ # `+stable`"), and exits with status 101.
+ #
+ # Unfortunately, in the rustc case, when plain rustc is in use,
+ # `rustc +stable` will exit with status 1, complaining about a missing
+ # "+stable" file. We'll examine the error output to try and distinguish
+ # between failing rustup and failing rustc.
+ @depends(prog, dependable(name))
+ @imports(_from="__builtin__", _import="open")
+ @imports("os")
+ def unwrap(prog, name):
+ if not prog:
+ return
+
+ def from_rustup_which():
+ out = check_cmd_output("rustup", "which", name, executable=prog).rstrip()
+ # If for some reason the above failed to return something, keep the
+ # PROG we found originally.
+ if out:
+ log.info("Actually using '%s'", out)
+ return out
+
+ log.info("No `rustup which` output, using '%s'", prog)
+ return prog
+
+ (retcode, stdout, stderr) = get_cmd_output(prog, "+stable")
+
+ if name == "cargo" and retcode != 101:
+ prog = from_rustup_which()
+ elif name == "rustc":
+ if retcode == 0:
+ prog = from_rustup_which()
+ elif "+stable" in stderr:
+ # PROG looks like plain `rustc`.
+ pass
+ else:
+ # Assume PROG looks like `rustup`. This case is a little weird,
+ # insofar as the user doesn't have the "stable" toolchain
+ # installed, but go ahead and unwrap anyway: the user might
+ # have only certain versions, beta, or nightly installed, and
+ # we'll catch invalid versions later.
+ prog = from_rustup_which()
+
+ return normalize_path(prog)
+
+ return unwrap
+
+
+rustc = unwrap_rustup(rustc, "rustc")
+cargo = unwrap_rustup(cargo, "cargo")
+
+
+set_config("CARGO", cargo)
+set_config("RUSTC", rustc)
+
+
+@depends_if(rustc)
+@checking("rustc version", lambda info: info.version)
+def rustc_info(rustc):
+ if not rustc:
+ return
+ out = check_cmd_output(rustc, "--version", "--verbose").splitlines()
+ info = dict((s.strip() for s in line.split(":", 1)) for line in out[1:])
+ return namespace(
+ version=Version(info.get("release", "0")),
+ commit=info.get("commit-hash", "unknown"),
+ host=info["host"],
+ llvm_version=Version(info.get("LLVM version", "0")),
+ )
+
+
+set_config(
+ "RUSTC_VERSION",
+ depends(rustc_info)(lambda info: str(info.version) if info else None),
+)
+
+
+set_config(
+ "RUSTC_LLVM_VERSION",
+ depends(rustc_info)(lambda info: str(info.llvm_version) if info else None),
+)
+
+set_config(
+ "MOZ_CLANG_NEWER_THAN_RUSTC_LLVM",
+ depends(c_compiler, rustc_info)(
+ lambda c_compiler, rustc_info: rustc_info
+ and c_compiler.type == "clang"
+ and c_compiler.version.major > rustc_info.llvm_version.major
+ ),
+)
+
+
+@depends_if(cargo)
+@checking("cargo version", lambda info: info.version)
+@imports("re")
+def cargo_info(cargo):
+ if not cargo:
+ return
+ out = check_cmd_output(cargo, "--version", "--verbose").splitlines()
+ info = dict((s.strip() for s in line.split(":", 1)) for line in out[1:])
+ version = info.get("release")
+ # Older versions of cargo didn't support --verbose, in which case, they
+ # only output a not-really-pleasant-to-parse output. Fortunately, they
+ # don't error out, so we can just try some regexp matching on the output
+ # we already got.
+ if version is None:
+ VERSION_FORMAT = r"^cargo (\d\.\d+\.\d+).*"
+
+ m = re.search(VERSION_FORMAT, out[0])
+ # Fail fast if cargo changes its output on us.
+ if not m:
+ die("Could not determine cargo version from output: %s", out)
+ version = m.group(1)
+
+ return namespace(
+ version=Version(version),
+ )
+
+
+@depends(rustc_info, cargo_info, target)
+@imports(_from="mozboot.util", _import="MINIMUM_RUST_VERSION")
+@imports(_from="textwrap", _import="dedent")
+def rust_compiler(rustc_info, cargo_info, target):
+ if not rustc_info:
+ die(
+ dedent(
+ """\
+ Rust compiler not found.
+ To compile rust language sources, you must have 'rustc' in your path.
+ See https://www.rust-lang.org/ for more information.
+
+ You can install rust by running './mach bootstrap'
+ or by directly running the installer from https://rustup.rs/
+ """
+ )
+ )
+ rustc_min_version = Version(MINIMUM_RUST_VERSION)
+ cargo_min_version = rustc_min_version
+
+ version = rustc_info.version
+ is_nightly = "nightly" in version.version
+ is_version_number_match = (
+ version.major == rustc_min_version.major
+ and version.minor == rustc_min_version.minor
+ and version.patch == rustc_min_version.patch
+ )
+
+ if version < rustc_min_version or (is_version_number_match and is_nightly):
+ die(
+ dedent(
+ """\
+ Rust compiler {} is too old.
+
+ To compile Rust language sources please install at least
+ version {} of the 'rustc' toolchain (or, if using nightly,
+ at least one version newer than {}) and make sure it is
+ first in your path.
+
+ You can verify this by typing 'rustc --version'.
+
+ If you have the 'rustup' tool installed you can upgrade
+ to the latest release by typing 'rustup update'. The
+ installer is available from https://rustup.rs/
+ """.format(
+ version, rustc_min_version, rustc_min_version
+ )
+ )
+ )
+
+ if target.kernel == "WINNT" and (version.major, version.minor) == (1, 56):
+ die(
+ dedent(
+ """\
+ Rust compiler 1.56.* is not supported for Windows builds.
+
+ Use a newer or an older version.
+
+ See https://github.com/rust-lang/rust/issues/88576.
+ """
+ )
+ )
+
+ if not cargo_info:
+ die(
+ dedent(
+ """\
+ Cargo package manager not found.
+ To compile Rust language sources, you must have 'cargo' in your path.
+ See https://www.rust-lang.org/ for more information.
+
+ You can install cargo by running './mach bootstrap'
+ or by directly running the installer from https://rustup.rs/
+ """
+ )
+ )
+
+ version = cargo_info.version
+ if version < cargo_min_version:
+ die(
+ dedent(
+ """\
+ Cargo package manager {} is too old.
+
+ To compile Rust language sources please install at least
+ version {} of 'cargo' and make sure it is first in your path.
+
+ You can verify this by typing 'cargo --version'.
+ """
+ ).format(version, cargo_min_version)
+ )
+
+ return True
+
+
+@depends(rustc, when=rust_compiler)
+@imports(_from="__builtin__", _import="ValueError")
+def rust_supported_targets(rustc):
+ out = check_cmd_output(rustc, "--print", "target-list").splitlines()
+ data = {}
+ for t in out:
+ try:
+ info = split_triplet(t, allow_wasi=True)
+ except ValueError:
+ if t.startswith("thumb"):
+ cpu, rest = t.split("-", 1)
+ retry = "-".join(("arm", rest))
+ else:
+ continue
+ try:
+ info = split_triplet(retry, allow_wasi=True)
+ except ValueError:
+ continue
+ key = (info.cpu, info.endianness, info.os)
+ data.setdefault(key, []).append(namespace(rust_target=t, target=info))
+ return data
+
+
+def detect_rustc_target(
+ host_or_target, compiler_info, arm_target, rust_supported_targets
+):
+ # Rust's --target options are similar to, but not exactly the same
+ # as, the autoconf-derived targets we use. An example would be that
+ # Rust uses distinct target triples for targetting the GNU C++ ABI
+ # and the MSVC C++ ABI on Win32, whereas autoconf has a single
+ # triple and relies on the user to ensure that everything is
+ # compiled for the appropriate ABI. We need to perform appropriate
+ # munging to get the correct option to rustc.
+ # We correlate the autoconf-derived targets with the list of targets
+ # rustc gives us with --print target-list.
+ candidates = rust_supported_targets.get(
+ (host_or_target.cpu, host_or_target.endianness, host_or_target.os), []
+ )
+
+ def find_candidate(candidates):
+ if len(candidates) == 1:
+ return candidates[0].rust_target
+ elif not candidates:
+ return None
+
+ # We have multiple candidates. There are two cases where we can try to
+ # narrow further down using extra information from the build system.
+ # - For windows targets, correlate with the C compiler type
+ if host_or_target.kernel == "WINNT":
+ if host_or_target.abi:
+ if host_or_target.abi == "msvc":
+ suffix = "windows-msvc"
+ elif host_or_target.abi == "mingw":
+ suffix = "windows-gnu"
+ elif compiler_info.type in ("gcc", "clang"):
+ suffix = "windows-gnu"
+ else:
+ suffix = "windows-msvc"
+ narrowed = [
+ c for c in candidates if c.rust_target.endswith("-{}".format(suffix))
+ ]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+ elif narrowed:
+ candidates = narrowed
+
+ vendor_aliases = {"pc": ("w64", "windows")}
+ narrowed = [
+ c
+ for c in candidates
+ if host_or_target.vendor in vendor_aliases.get(c.target.vendor, ())
+ ]
+
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+
+ # - For arm targets, correlate with arm_target
+ # we could be more thorough with the supported rust targets, but they
+ # don't support OSes that are supported to build Gecko anyways.
+ # Also, sadly, the only interface to check the rust target cpu features
+ # is --print target-spec-json, and it's unstable, so we have to rely on
+ # our own knowledge of what each arm target means.
+ if host_or_target.cpu == "arm" and host_or_target.endianness == "little":
+ prefixes = []
+ if arm_target.arm_arch >= 7:
+ if arm_target.thumb2 and arm_target.fpu == "neon":
+ prefixes.append("thumbv7neon")
+ if arm_target.thumb2:
+ prefixes.append("thumbv7a")
+ prefixes.append("armv7")
+ if arm_target.arm_arch >= 6:
+ prefixes.append("armv6")
+ if host_or_target.os != "Android":
+ # arm-* rust targets are armv6... except arm-linux-androideabi
+ prefixes.append("arm")
+ if arm_target.arm_arch >= 5:
+ prefixes.append("armv5te")
+ if host_or_target.os == "Android":
+ # arm-* rust targets are armv6... except arm-linux-androideabi
+ prefixes.append("arm")
+ if arm_target.arm_arch >= 4:
+ prefixes.append("armv4t")
+ # rust freebsd targets are the only ones that don't have a 'hf' suffix
+ # for hard-float. Technically, that means if the float abi ever is not
+ # hard-float, this will pick a wrong target, but since rust only
+ # supports hard-float, let's assume that means freebsd only support
+ # hard-float.
+ if arm_target.float_abi == "hard" and host_or_target.os != "FreeBSD":
+ suffix = "hf"
+ else:
+ suffix = ""
+ for p in prefixes:
+ for c in candidates:
+ if c.rust_target.startswith(
+ "{}-".format(p)
+ ) and c.rust_target.endswith(suffix):
+ return c.rust_target
+
+ # See if we can narrow down on the exact alias.
+ # We use the sub_configure_alias to keep support mingw32 triplets as input.
+ narrowed = [
+ c
+ for c in candidates
+ if c.target.sub_configure_alias == host_or_target.sub_configure_alias
+ ]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+ elif narrowed:
+ candidates = narrowed
+
+ # See if we can narrow down with the raw OS
+ narrowed = [c for c in candidates if c.target.raw_os == host_or_target.raw_os]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+ elif narrowed:
+ candidates = narrowed
+
+ # See if we can narrow down with the raw OS and raw CPU
+ narrowed = [
+ c
+ for c in candidates
+ if c.target.raw_os == host_or_target.raw_os
+ and c.target.raw_cpu == host_or_target.raw_cpu
+ ]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+
+ # Finally, see if the vendor can be used to disambiguate.
+ narrowed = [c for c in candidates if c.target.vendor == host_or_target.vendor]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+
+ return None
+
+ rustc_target = find_candidate(candidates)
+
+ if rustc_target is None:
+ die("Don't know how to translate {} for rustc".format(host_or_target.alias))
+
+ return rustc_target
+
+
+@imports("os")
+@imports(_from="tempfile", _import="mkstemp")
+@imports(_from="textwrap", _import="dedent")
+@imports(_from="mozbuild.configure.util", _import="LineIO")
+def assert_rust_compile(host_or_target, rustc_target, rustc):
+ # Check to see whether our rustc has a reasonably functional stdlib
+ # for our chosen target.
+ target_arg = "--target=" + rustc_target
+ in_fd, in_path = mkstemp(prefix="conftest", suffix=".rs", text=True)
+ out_fd, out_path = mkstemp(prefix="conftest", suffix=".rlib")
+ os.close(out_fd)
+ try:
+ source = b'pub extern fn hello() { println!("Hello world"); }'
+ log.debug("Creating `%s` with content:", in_path)
+ with LineIO(lambda l: log.debug("| %s", l)) as out:
+ out.write(source)
+
+ os.write(in_fd, source)
+ os.close(in_fd)
+
+ cmd = [
+ rustc,
+ "--crate-type",
+ "staticlib",
+ target_arg,
+ "-o",
+ out_path,
+ in_path,
+ ]
+
+ def failed():
+ die(
+ dedent(
+ """\
+ Cannot compile for {} with {}
+ The target may be unsupported, or you may not have
+ a rust std library for that target installed. Try:
+
+ rustup target add {}
+ """.format(
+ host_or_target.alias, rustc, rustc_target
+ )
+ )
+ )
+
+ check_cmd_output(*cmd, onerror=failed)
+ if not os.path.exists(out_path) or os.path.getsize(out_path) == 0:
+ failed()
+ finally:
+ os.remove(in_path)
+ os.remove(out_path)
+
+
+@depends(
+ rustc,
+ host,
+ host_c_compiler,
+ rustc_info.host,
+ rust_supported_targets,
+ arm_target,
+ when=rust_compiler,
+)
+@checking("for rust host triplet")
+@imports(_from="textwrap", _import="dedent")
+def rust_host_triple(
+ rustc, host, compiler_info, rustc_host, rust_supported_targets, arm_target
+):
+ rustc_target = detect_rustc_target(
+ host, compiler_info, arm_target, rust_supported_targets
+ )
+ if rustc_target != rustc_host:
+ if host.alias == rustc_target:
+ configure_host = host.alias
+ else:
+ configure_host = "{}/{}".format(host.alias, rustc_target)
+ die(
+ dedent(
+ """\
+ The rust compiler host ({rustc}) is not suitable for the configure host ({configure}).
+
+ You can solve this by:
+ * Set your configure host to match the rust compiler host by editing your
+ mozconfig and adding "ac_add_options --host={rustc}".
+ * Or, install the rust toolchain for {configure}, if supported, by running
+ "rustup default stable-{rustc_target}"
+ """.format(
+ rustc=rustc_host,
+ configure=configure_host,
+ rustc_target=rustc_target,
+ )
+ )
+ )
+ assert_rust_compile(host, rustc_target, rustc)
+ return rustc_target
+
+
+@depends(
+ rustc, target, c_compiler, rust_supported_targets, arm_target, when=rust_compiler
+)
+@checking("for rust target triplet")
+def rust_target_triple(
+ rustc, target, compiler_info, rust_supported_targets, arm_target
+):
+ rustc_target = detect_rustc_target(
+ target, compiler_info, arm_target, rust_supported_targets
+ )
+ assert_rust_compile(target, rustc_target, rustc)
+ return rustc_target
+
+
+set_config("RUST_TARGET", rust_target_triple)
+set_config("RUST_HOST_TARGET", rust_host_triple)
+
+
+# This is used for putting source info into symbol files.
+set_config("RUSTC_COMMIT", depends(rustc_info)(lambda i: i.commit))
+
+# Rustdoc is required by Rust tests below.
+option(env="RUSTDOC", nargs=1, help="Path to the rustdoc program")
+
+rustdoc = check_prog(
+ "RUSTDOC",
+ ["rustdoc"],
+ paths=rust_search_path,
+ input="RUSTDOC",
+ allow_missing=True,
+)
+
+# This option is separate from --enable-tests because Rust tests are particularly
+# expensive in terms of compile time (especially for code in libxul).
+option(
+ "--enable-rust-tests",
+ help="Enable building and running of Rust tests during `make check`",
+)
+
+
+@depends("--enable-rust-tests", rustdoc)
+def rust_tests(enable_rust_tests, rustdoc):
+ if enable_rust_tests and not rustdoc:
+ die("--enable-rust-tests requires rustdoc")
+ return bool(enable_rust_tests)
+
+
+set_config("MOZ_RUST_TESTS", rust_tests)
+
+
+@depends(target, c_compiler, rustc)
+@imports("os")
+def rustc_natvis_ldflags(target, compiler_info, rustc):
+ if target.kernel == "WINNT" and compiler_info.type == "clang-cl":
+ sysroot = check_cmd_output(rustc, "--print", "sysroot").strip()
+ etc = os.path.join(sysroot, "lib/rustlib/etc")
+ ldflags = []
+ if os.path.isdir(etc):
+ for f in os.listdir(etc):
+ if f.endswith(".natvis"):
+ ldflags.append("-NATVIS:" + normsep(os.path.join(etc, f)))
+ return ldflags
+
+
+set_config("RUSTC_NATVIS_LDFLAGS", rustc_natvis_ldflags)
+
+
+option(
+ "--enable-rust-debug",
+ default=depends(when="--enable-debug")(lambda: True),
+ help="{Build|Do not build} Rust code with debug assertions turned " "on.",
+)
+
+
+@depends(when="--enable-rust-debug")
+def debug_rust():
+ return True
+
+
+set_config("MOZ_DEBUG_RUST", debug_rust)
+set_define("MOZ_DEBUG_RUST", debug_rust)
+
+# ==============================================================
+
+option(env="RUSTFLAGS", nargs=1, help="Rust compiler flags")
+set_config("RUSTFLAGS", depends("RUSTFLAGS")(lambda flags: flags))
+
+
+# Rust compiler flags
+# ==============================================================
+
+
+@depends(moz_optimize)
+def rustc_opt_level_default(moz_optimize):
+ return "2" if moz_optimize.optimize else "0"
+
+
+option(
+ env="RUSTC_OPT_LEVEL",
+ default=rustc_opt_level_default,
+ nargs=1,
+ help="Rust compiler optimization level (-C opt-level=%s)",
+)
+
+
+@depends("RUSTC_OPT_LEVEL")
+def rustc_opt_level(opt_level_option):
+ return opt_level_option[0]
+
+
+set_config("CARGO_PROFILE_RELEASE_OPT_LEVEL", rustc_opt_level)
+set_config("CARGO_PROFILE_DEV_OPT_LEVEL", rustc_opt_level)
+
+
+@depends(
+ rustc_opt_level,
+ debug_rust,
+ target,
+ "--enable-debug-symbols",
+ "--enable-frame-pointers",
+ path_remapping,
+ path_remappings,
+)
+def rust_compile_flags(
+ opt_level,
+ debug_rust,
+ target,
+ debug_symbols,
+ frame_pointers,
+ path_remapping,
+ path_remappings,
+):
+ # Cargo currently supports only two interesting profiles for building:
+ # development and release. Those map (roughly) to --enable-debug and
+ # --disable-debug in Gecko, respectively.
+ #
+ # But we'd also like to support an additional axis of control for
+ # optimization level. Since Cargo only supports 2 profiles, we're in
+ # a bit of a bind.
+ #
+ # Code here derives various compiler options given other configure options.
+ # The options defined here effectively override defaults specified in
+ # Cargo.toml files.
+
+ debug_assertions = None
+ debug_info = None
+
+ # opt-level=0 implies -C debug-assertions, which may not be desired
+ # unless Rust debugging is enabled.
+ if opt_level == "0" and not debug_rust:
+ debug_assertions = False
+
+ if debug_symbols:
+ debug_info = "2"
+
+ opts = []
+
+ if debug_assertions is not None:
+ opts.append("debug-assertions=%s" % ("yes" if debug_assertions else "no"))
+ if debug_info is not None:
+ opts.append("debuginfo=%s" % debug_info)
+ if frame_pointers:
+ opts.append("force-frame-pointers=yes")
+ # CFG for arm64 is crashy, see `def security_hardening_cflags`.
+ if target.kernel == "WINNT" and target.cpu != "aarch64":
+ opts.append("control-flow-guard=yes")
+
+ flags = []
+ for opt in opts:
+ flags.extend(["-C", opt])
+
+ if "rust" in path_remapping:
+ # rustc has supported --remap-path-prefix since version 1.26, well
+ # before our required minimum Rust version, so there's no need to
+ # feature-detect or gate on versions.
+ for old, new in path_remappings:
+ flags.append(f"--remap-path-prefix={old}={new}")
+
+ return flags
+
+
+# Rust incremental compilation
+# ==============================================================
+
+
+option("--disable-cargo-incremental", help="Disable incremental rust compilation.")
+
+
+@depends(
+ developer_options,
+ debug_rust,
+ "MOZ_AUTOMATION",
+ code_coverage,
+ "--disable-cargo-incremental",
+ using_sccache,
+ "RUSTC_WRAPPER",
+)
+@imports("os")
+def cargo_incremental(
+ developer_options,
+ debug_rust,
+ automation,
+ code_coverage,
+ enabled,
+ using_sccache,
+ rustc_wrapper,
+):
+ """Return a value for the CARGO_INCREMENTAL environment variable."""
+
+ if not enabled:
+ return "0"
+ elif enabled.origin != "default":
+ return "1"
+
+ # We never want to use incremental compilation in automation. sccache
+ # handles our automation use case much better than incremental compilation
+ # would.
+ if automation:
+ return "0"
+
+ # Coverage instrumentation doesn't play well with incremental compilation
+ # https://github.com/rust-lang/rust/issues/50203.
+ if code_coverage:
+ return "0"
+
+ # Incremental compilation doesn't work as well as it should, and if we're
+ # using sccache, it's better to use sccache than incremental compilation.
+ if not using_sccache and rustc_wrapper:
+ rustc_wrapper = os.path.basename(rustc_wrapper[0])
+ if os.path.splitext(rustc_wrapper)[0].lower() == "sccache":
+ using_sccache = True
+ if using_sccache:
+ return "0"
+
+ # Incremental compilation is automatically turned on for debug builds, so
+ # we don't need to do anything special here.
+ if debug_rust:
+ return
+
+ # Don't enable on --enable-release builds, because of the runtime
+ # performance cost.
+ if not developer_options:
+ return
+
+ # We're clear to use incremental compilation!
+ return "1"
+
+
+set_config("CARGO_INCREMENTAL", cargo_incremental)
+
+
+@depends(rust_compile_flags, "--enable-warnings-as-errors", rustc_info)
+def rust_flags(compile_flags, warnings_as_errors, rustc_info):
+ warning_flags = []
+
+ # Note that cargo passes --cap-lints warn to rustc for third-party code, so
+ # we don't need a very complicated setup.
+ if warnings_as_errors:
+ warning_flags.append("-Dwarnings")
+ # Work around https://github.com/rust-lang/rust/issues/84428
+ if rustc_info.version >= "1.52":
+ warning_flags.append("-Aproc-macro-back-compat")
+ else:
+ warning_flags.extend(("--cap-lints", "warn"))
+
+ return compile_flags + warning_flags
+
+
+set_config("MOZ_RUST_DEFAULT_FLAGS", rust_flags)