summaryrefslogtreecommitdiffstats
path: root/config/makefiles/rust.mk
diff options
context:
space:
mode:
Diffstat (limited to 'config/makefiles/rust.mk')
-rw-r--r--config/makefiles/rust.mk417
1 files changed, 417 insertions, 0 deletions
diff --git a/config/makefiles/rust.mk b/config/makefiles/rust.mk
new file mode 100644
index 0000000000..79f5624937
--- /dev/null
+++ b/config/makefiles/rust.mk
@@ -0,0 +1,417 @@
+# 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/.
+
+# /!\ In this file, we export multiple variables globally via make rather than
+# in recipes via the `env` command to avoid round-trips to msys on Windows, which
+# tend to break environment variable values in interesting ways.
+
+# /!\ Avoid the use of double-quotes in this file, so that the cargo
+# commands can be executed directly by make, without doing a round-trip
+# through a shell.
+
+cargo_host_flag := --target=$(RUST_HOST_TARGET)
+cargo_target_flag := --target=$(RUST_TARGET)
+
+# Permit users to pass flags to cargo from their mozconfigs (e.g. --color=always).
+cargo_build_flags = $(CARGOFLAGS)
+ifndef MOZ_DEBUG_RUST
+cargo_build_flags += --release
+endif
+
+# The Spidermonkey library can be built from a package tarball outside the
+# tree, so we want to let Cargo create lock files in this case. When built
+# within a tree, the Rust dependencies have been vendored in so Cargo won't
+# touch the lock file.
+ifndef JS_STANDALONE
+cargo_build_flags += --frozen
+endif
+
+cargo_build_flags += --manifest-path $(CARGO_FILE)
+ifdef BUILD_VERBOSE_LOG
+cargo_build_flags += -vv
+endif
+
+# Enable color output if original stdout was a TTY and color settings
+# aren't already present. This essentially restores the default behavior
+# of cargo when running via `mach`.
+ifdef MACH_STDOUT_ISATTY
+ifeq (,$(findstring --color,$(cargo_build_flags)))
+ifeq (WINNT,$(HOST_OS_ARCH))
+# Bug 1417003: color codes are non-trivial on Windows. For now,
+# prefer black and white to broken color codes.
+cargo_build_flags += --color=never
+else
+cargo_build_flags += --color=always
+endif
+endif
+endif
+
+# Without -j > 1, make will not pass jobserver info down to cargo. Force
+# one job when requested as a special case.
+ifeq (1,$(MOZ_PARALLEL_BUILD))
+cargo_build_flags += -j1
+endif
+
+# We also need to rebuild the rust stdlib so that it's instrumented. Because
+# build-std is still pretty experimental, we need to explicitly request
+# the panic_abort crate for `panic = "abort"` support.
+ifdef MOZ_TSAN
+cargo_build_flags += -Zbuild-std=std,panic_abort
+RUSTFLAGS += -Zsanitizer=thread
+endif
+
+# These flags are passed via `cargo rustc` and only apply to the final rustc
+# invocation (i.e., only the top-level crate, not its dependencies).
+cargo_rustc_flags = $(CARGO_RUSTCFLAGS)
+ifndef DEVELOPER_OPTIONS
+ifndef MOZ_DEBUG_RUST
+# Enable link-time optimization for release builds, but not when linking
+# gkrust_gtest. And not when doing cross-language LTO.
+ifndef MOZ_LTO_RUST_CROSS
+ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE)))
+cargo_rustc_flags += -Clto
+endif
+# We need -Cembed-bitcode=yes for all crates when using -Clto.
+RUSTFLAGS += -Cembed-bitcode=yes
+endif
+endif
+endif
+
+ifdef CARGO_INCREMENTAL
+export CARGO_INCREMENTAL
+endif
+
+rustflags_neon =
+ifeq (neon,$(MOZ_FPU))
+# Enable neon and disable restriction to 16 FPU registers
+# (CPUs with neon have 32 FPU registers available)
+rustflags_neon += -C target_feature=+neon,-d16
+endif
+
+rustflags_sancov =
+ifdef LIBFUZZER
+ifndef MOZ_TSAN
+# These options should match what is implicitly enabled for `clang -fsanitize=fuzzer`
+# here: https://github.com/llvm/llvm-project/blob/release/8.x/clang/lib/Driver/SanitizerArgs.cpp#L354
+#
+# -sanitizer-coverage-inline-8bit-counters Increments 8-bit counter for every edge.
+# -sanitizer-coverage-level=4 Enable coverage for all blocks, critical edges, and indirect calls.
+# -sanitizer-coverage-trace-compares Tracing of CMP and similar instructions.
+# -sanitizer-coverage-pc-table Create a static PC table.
+#
+# In TSan builds, we must not pass any of these, because sanitizer coverage is incompatible with TSan.
+rustflags_sancov += -Cpasses=sancov -Cllvm-args=-sanitizer-coverage-inline-8bit-counters -Cllvm-args=-sanitizer-coverage-level=4 -Cllvm-args=-sanitizer-coverage-trace-compares -Cllvm-args=-sanitizer-coverage-pc-table
+endif
+endif
+
+rustflags_override = $(MOZ_RUST_DEFAULT_FLAGS) $(rustflags_neon)
+
+ifdef DEVELOPER_OPTIONS
+# By default the Rust compiler will perform a limited kind of ThinLTO on each
+# crate. For local builds this additional optimization is not worth the
+# increase in compile time so we opt out of it.
+rustflags_override += -Clto=off
+endif
+
+ifdef MOZ_USING_SCCACHE
+export RUSTC_WRAPPER=$(CCACHE)
+endif
+
+ifneq (,$(MOZ_ASAN)$(MOZ_TSAN)$(MOZ_UBSAN))
+ifndef CROSS_COMPILE
+NATIVE_SANITIZERS=1
+endif # CROSS_COMPILE
+endif
+
+# We start with host variables because the rust host and the rust target might be the same,
+# in which case we want the latter to take priority.
+
+# We're passing these for consumption by the `cc` crate, which doesn't use the same
+# convention as cargo itself:
+# https://github.com/alexcrichton/cc-rs/blob/baa71c0e298d9ad7ac30f0ad78f20b4b3b3a8fb2/src/lib.rs#L1715
+rust_host_cc_env_name := $(subst -,_,$(RUST_HOST_TARGET))
+
+# HOST_CC/HOST_CXX/CC/CXX usually contain base flags for e.g. the build target.
+# We want to pass those through CFLAGS_*/CXXFLAGS_* instead, so that they end up
+# after whatever cc-rs adds to the compiler command line, so that they win.
+# Ideally, we'd use CRATE_CC_NO_DEFAULTS=1, but that causes other problems at the
+# moment.
+export CC_$(rust_host_cc_env_name)=$(filter-out $(HOST_CC_BASE_FLAGS),$(HOST_CC))
+export CXX_$(rust_host_cc_env_name)=$(filter-out $(HOST_CXX_BASE_FLAGS),$(HOST_CXX))
+# We don't have a HOST_AR. If rust needs one, assume it's going to pick an appropriate one.
+
+rust_cc_env_name := $(subst -,_,$(RUST_TARGET))
+
+export CC_$(rust_cc_env_name)=$(filter-out $(CC_BASE_FLAGS),$(CC))
+export CXX_$(rust_cc_env_name)=$(filter-out $(CXX_BASE_FLAGS),$(CXX))
+export AR_$(rust_cc_env_name)=$(AR)
+
+ifeq (WINNT,$(HOST_OS_ARCH))
+HOST_CC_BASE_FLAGS += -DUNICODE
+HOST_CXX_BASE_FLAGS += -DUNICODE
+CC_BASE_FLAGS += -DUNICODE
+CXX_BASE_FLAGS += -DUNICODE
+endif
+
+ifeq (,$(NATIVE_SANITIZERS)$(MOZ_CODE_COVERAGE))
+# -DMOZILLA_CONFIG_H is added to prevent mozilla-config.h from injecting anything
+# in C/C++ compiles from rust. That's not needed in the other branch because the
+# base flags don't force-include mozilla-config.h.
+export CFLAGS_$(rust_host_cc_env_name)=$(HOST_CC_BASE_FLAGS) $(COMPUTED_HOST_CFLAGS) -DMOZILLA_CONFIG_H
+export CXXFLAGS_$(rust_host_cc_env_name)=$(HOST_CXX_BASE_FLAGS) $(COMPUTED_HOST_CXXFLAGS) -DMOZILLA_CONFIG_H
+export CFLAGS_$(rust_cc_env_name)=$(CC_BASE_FLAGS) $(COMPUTED_CFLAGS) -DMOZILLA_CONFIG_H
+export CXXFLAGS_$(rust_cc_env_name)=$(CXX_BASE_FLAGS) $(COMPUTED_CXXFLAGS) -DMOZILLA_CONFIG_H
+else
+# Because cargo doesn't allow to distinguish builds happening for build
+# scripts/procedural macros vs. those happening for the rust target,
+# we can't blindly pass all our flags down for cc-rs to use them, because of the
+# side effects they can have on what otherwise should be host builds.
+# So for sanitizer and coverage builds, we only pass the base compiler flags.
+# This means C code built by rust is not going to be covered by sanitizer
+# and coverage. But at least we control what compiler is being used,
+# rather than relying on cc-rs guesses, which, sometimes fail us.
+export CFLAGS_$(rust_host_cc_env_name)=$(HOST_CC_BASE_FLAGS)
+export CXXFLAGS_$(rust_host_cc_env_name)=$(HOST_CXX_BASE_FLAGS)
+export CFLAGS_$(rust_cc_env_name)=$(CC_BASE_FLAGS)
+export CXXFLAGS_$(rust_cc_env_name)=$(CXX_BASE_FLAGS)
+endif
+
+# Force the target down to all bindgen callers, even those that may not
+# read BINDGEN_SYSTEM_FLAGS some way or another.
+export BINDGEN_EXTRA_CLANG_ARGS:=$(filter --target=%,$(BINDGEN_SYSTEM_FLAGS))
+export CARGO_TARGET_DIR
+export RUSTFLAGS
+export RUSTC
+export RUSTDOC
+export RUSTFMT
+export MOZ_SRC=$(topsrcdir)
+export MOZ_DIST=$(ABS_DIST)
+export LIBCLANG_PATH=$(MOZ_LIBCLANG_PATH)
+export CLANG_PATH=$(MOZ_CLANG_PATH)
+export PKG_CONFIG
+export PKG_CONFIG_ALLOW_CROSS=1
+export RUST_BACKTRACE=full
+export MOZ_TOPOBJDIR=$(topobjdir)
+export PYTHON3
+
+# Set COREAUDIO_SDK_PATH for third_party/rust/coreaudio-sys/build.rs
+ifeq ($(OS_ARCH), Darwin)
+ifdef MACOS_SDK_DIR
+export COREAUDIO_SDK_PATH=$(MACOS_SDK_DIR)
+endif
+endif
+
+target_rust_ltoable := force-cargo-library-build
+target_rust_nonltoable := force-cargo-test-run force-cargo-library-check $(foreach b,build check,force-cargo-program-$(b))
+
+ifdef MOZ_PGO_RUST
+ifdef MOZ_PROFILE_GENERATE
+rust_pgo_flags := -C profile-generate=$(topobjdir)
+# The C compiler may be passed extra llvm flags for PGO that we also want to pass to rust as well.
+# In PROFILE_GEN_CFLAGS, they look like "-mllvm foo", and we want "-C llvm-args=foo", so first turn
+# "-mllvm foo" into "-mllvm:foo" so that it becomes a unique argument, that we can then filter for,
+# excluding other flags, and then turn into the right string.
+rust_pgo_flags += $(patsubst -mllvm:%,-C llvm-args=%,$(filter -mllvm:%,$(subst -mllvm ,-mllvm:,$(PROFILE_GEN_CFLAGS))))
+else # MOZ_PROFILE_USE
+rust_pgo_flags := -C profile-use=$(PGO_PROFILE_PATH)
+endif
+endif
+
+$(target_rust_ltoable): RUSTFLAGS:=$(rustflags_override) $(rustflags_sancov) $(RUSTFLAGS) $(if $(MOZ_LTO_RUST_CROSS),-Clinker-plugin-lto) $(rust_pgo_flags)
+$(target_rust_nonltoable): RUSTFLAGS:=$(rustflags_override) $(rustflags_sancov) $(RUSTFLAGS)
+
+TARGET_RECIPES := $(target_rust_ltoable) $(target_rust_nonltoable)
+
+HOST_RECIPES := \
+ $(foreach a,library program,$(foreach b,build check,force-cargo-host-$(a)-$(b)))
+
+$(HOST_RECIPES): RUSTFLAGS:=$(rustflags_override)
+
+# If this is a release build we want rustc to generate one codegen unit per
+# crate. This results in better optimization and less code duplication at the
+# cost of longer compile times.
+ifndef DEVELOPER_OPTIONS
+$(TARGET_RECIPES) $(HOST_RECIPES): RUSTFLAGS += -C codegen-units=1
+endif
+
+# We use the + prefix to pass down the jobserver fds to cargo, but we
+# don't use the prefix when make -n is used, so that cargo doesn't run
+# in that case)
+define RUN_CARGO
+$(if $(findstring n,$(filter-out --%, $(MAKEFLAGS))),,+)$(CARGO) $(1) $(cargo_build_flags)
+endef
+
+# This function is intended to be called by:
+#
+# $(call CARGO_BUILD,EXTRA_ENV_VAR1=X EXTRA_ENV_VAR2=Y ...)
+#
+# but, given the idiosyncracies of make, can also be called without arguments:
+#
+# $(call CARGO_BUILD)
+define CARGO_BUILD
+$(call RUN_CARGO,rustc)
+endef
+
+define CARGO_CHECK
+$(call RUN_CARGO,check)
+endef
+
+cargo_host_linker_env_var := CARGO_TARGET_$(call varize,$(RUST_HOST_TARGET))_LINKER
+cargo_linker_env_var := CARGO_TARGET_$(call varize,$(RUST_TARGET))_LINKER
+
+# Cargo needs the same linker flags as the C/C++ compiler,
+# but not the final libraries. Filter those out because they
+# cause problems on macOS 10.7; see bug 1365993 for details.
+# Also, we don't want to pass PGO flags until cargo supports them.
+export MOZ_CARGO_WRAP_LDFLAGS
+export MOZ_CARGO_WRAP_LD
+export MOZ_CARGO_WRAP_HOST_LDFLAGS
+export MOZ_CARGO_WRAP_HOST_LD
+# Exporting from make always exports a value. Setting a value per-recipe
+# would export an empty value for the host recipes. When not doing a
+# cross-compile, the --target for those is the same, and cargo will use
+# CARGO_TARGET_*_LINKER for its linker, so we always pass the
+# cargo-linker wrapper, and fill MOZ_CARGO_WRAP_{HOST_,}LD* more or less
+# appropriately for all recipes.
+ifeq (WINNT,$(HOST_OS_ARCH))
+# Use .bat wrapping on Windows hosts, and shell wrapping on other hosts.
+# Like for CC/C*FLAGS, we want the target values to trump the host values when
+# both variables are the same.
+export $(cargo_host_linker_env_var):=$(topsrcdir)/build/cargo-host-linker.bat
+export $(cargo_linker_env_var):=$(topsrcdir)/build/cargo-linker.bat
+WRAP_HOST_LINKER_LIBPATHS:=$(HOST_LINKER_LIBPATHS_BAT)
+else
+export $(cargo_host_linker_env_var):=$(topsrcdir)/build/cargo-host-linker
+export $(cargo_linker_env_var):=$(topsrcdir)/build/cargo-linker
+WRAP_HOST_LINKER_LIBPATHS:=$(HOST_LINKER_LIBPATHS)
+endif
+
+# Defining all of this for ASan/TSan builds results in crashes while running
+# some crates's build scripts (!), so disable it for now.
+# See https://github.com/rust-lang/cargo/issues/5754
+ifndef NATIVE_SANITIZERS
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LDFLAGS:=$(filter-out -fsanitize=cfi% -framework Cocoa -lobjc AudioToolbox ExceptionHandling -fprofile-%,$(LDFLAGS))
+endif # NATIVE_SANITIZERS
+
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LDFLAGS:=$(HOST_LDFLAGS) $(WRAP_HOST_LINKER_LIBPATHS)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LDFLAGS:=$(HOST_LDFLAGS) $(WRAP_HOST_LINKER_LIBPATHS)
+
+ifeq (,$(filter clang-cl,$(CC_TYPE)))
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LD:=$(CC)
+else
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LD:=$(LINKER)
+endif
+
+ifeq (,$(filter clang-cl,$(HOST_CC_TYPE)))
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD:=$(HOST_CC)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD:=$(HOST_CC)
+else
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD:=$(HOST_LINKER)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD:=$(HOST_LINKER)
+endif
+
+ifdef RUST_LIBRARY_FILE
+
+ifdef RUST_LIBRARY_FEATURES
+rust_features_flag := --features '$(RUST_LIBRARY_FEATURES)'
+endif
+
+# Assume any system libraries rustc links against are already in the target's LIBS.
+#
+# We need to run cargo unconditionally, because cargo is the only thing that
+# has full visibility into how changes in Rust sources might affect the final
+# build.
+force-cargo-library-build:
+ $(REPORT_BUILD)
+ $(call CARGO_BUILD) --lib $(cargo_target_flag) $(rust_features_flag) -- $(cargo_rustc_flags)
+
+$(RUST_LIBRARY_FILE): force-cargo-library-build
+# When we are building in --enable-release mode; we add an additional check to confirm
+# that we are not importing any networking-related functions in rust code. This reduces
+# the chance of proxy bypasses originating from rust code.
+# The check only works when rust code is built with -Clto but without MOZ_LTO_RUST_CROSS.
+# Sanitizers and sancov also fail because compiler-rt hooks network functions.
+ifndef MOZ_PROFILE_GENERATE
+ifeq ($(OS_ARCH), Linux)
+ifeq (,$(rustflags_sancov)$(MOZ_ASAN)$(MOZ_TSAN)$(MOZ_UBSAN))
+ifndef MOZ_LTO_RUST_CROSS
+ifneq (,$(filter -Clto,$(cargo_rustc_flags)))
+ $(call py_action,check_binary,--target --networking $@)
+endif
+endif
+endif
+endif
+endif
+
+force-cargo-library-check:
+ $(call CARGO_CHECK) --lib $(cargo_target_flag) $(rust_features_flag)
+else
+force-cargo-library-check:
+ @true
+endif # RUST_LIBRARY_FILE
+
+ifdef RUST_TESTS
+
+rust_test_options := $(foreach test,$(RUST_TESTS),-p $(test))
+
+ifdef RUST_TEST_FEATURES
+rust_test_features_flag := --features '$(RUST_TEST_FEATURES)'
+endif
+
+# Don't stop at the first failure. We want to list all failures together.
+rust_test_flag := --no-fail-fast
+
+force-cargo-test-run:
+ $(call RUN_CARGO,test $(cargo_target_flag) $(rust_test_flag) $(rust_test_options) $(rust_test_features_flag))
+
+endif
+
+ifdef HOST_RUST_LIBRARY_FILE
+
+ifdef HOST_RUST_LIBRARY_FEATURES
+host_rust_features_flag := --features '$(HOST_RUST_LIBRARY_FEATURES)'
+endif
+
+force-cargo-host-library-build:
+ $(REPORT_BUILD)
+ $(call CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
+
+$(HOST_RUST_LIBRARY_FILE): force-cargo-host-library-build ;
+
+force-cargo-host-library-check:
+ $(call CARGO_CHECK) --lib $(cargo_host_flag) $(host_rust_features_flag)
+else
+force-cargo-host-library-check:
+ @true
+endif # HOST_RUST_LIBRARY_FILE
+
+ifdef RUST_PROGRAMS
+
+force-cargo-program-build: $(call resfile,module)
+ $(REPORT_BUILD)
+ $(call CARGO_BUILD) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag) -- $(addprefix -C link-arg=$(CURDIR)/,$(call resfile,module))
+
+$(RUST_PROGRAMS): force-cargo-program-build ;
+
+force-cargo-program-check:
+ $(call CARGO_CHECK) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
+else
+force-cargo-program-check:
+ @true
+endif # RUST_PROGRAMS
+ifdef HOST_RUST_PROGRAMS
+
+force-cargo-host-program-build:
+ $(REPORT_BUILD)
+ $(call CARGO_BUILD) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
+
+$(HOST_RUST_PROGRAMS): force-cargo-host-program-build ;
+
+force-cargo-host-program-check:
+ $(REPORT_BUILD)
+ $(call CARGO_CHECK) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
+else
+force-cargo-host-program-check:
+ @true
+endif # HOST_RUST_PROGRAMS