summaryrefslogtreecommitdiffstats
path: root/config/makefiles
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--config/makefiles/autotargets.mk93
-rw-r--r--config/makefiles/debugmake.mk114
-rw-r--r--config/makefiles/functions.mk41
-rw-r--r--config/makefiles/makeutils.mk121
-rw-r--r--config/makefiles/nonrecursive.mk68
-rw-r--r--config/makefiles/rust.mk613
-rw-r--r--config/makefiles/target_binaries.mk43
-rw-r--r--config/makefiles/xpidl/Makefile.in94
8 files changed, 1187 insertions, 0 deletions
diff --git a/config/makefiles/autotargets.mk b/config/makefiles/autotargets.mk
new file mode 100644
index 0000000000..a3a073b359
--- /dev/null
+++ b/config/makefiles/autotargets.mk
@@ -0,0 +1,93 @@
+# -*- makefile -*-
+# vim:set ts=8 sw=8 sts=8 noet:
+#
+# 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/.
+#
+
+ifndef INCLUDED_AUTOTARGETS_MK #{
+
+# Conditional does not wrap the entire file so multiple
+# includes will be able to accumulate dependencies.
+
+###########################################################################
+# AUTO_DEPS - A list of deps/targets drived from other macros.
+###########################################################################
+
+MKDIR ?= mkdir -p
+TOUCH ?= touch
+
+# declare for local use, rules.mk may not have been loaded
+space = $(NULL) $(NULL)
+
+# Deps will be considered intermediate when used as a pre-requisite for
+# wildcard targets. Inhibit their removal, mkdir -p is a standalone op.
+.PRECIOUS: %/.mkdir.done
+
+#########################
+##---] FUNCTIONS [---##
+#########################
+
+# Squeeze can be overzealous, restore root for abspath
+getPathPrefix =$(if $(filter /%,$(1)),/)
+
+# Squeeze '//' from the path, easily created by string functions
+_slashSqueeze =$(foreach val,$(getargv),$(call getPathPrefix,$(val))$(subst $(space),/,$(strip $(subst /,$(space),$(val)))))
+
+# Squeeze extraneous directory slashes from the path
+# o protect embedded spaces within the path
+# o replace //+ sequences with /
+slash_strip = \
+ $(strip \
+ $(subst <--[**]-->,$(space),\
+ $(call _slashSqueeze,\
+ $(subst $(space),<--[**]-->,$(1))\
+ )))
+
+# Extract directory path from a dependency file.
+mkdir_stem =$(foreach val,$(getargv),$(subst /.mkdir.done,$(NULL),$(val)))
+
+## Generate timestamp file for threadsafe directory creation
+mkdir_deps =$(foreach dir,$(getargv),$(call slash_strip,$(dir)/.mkdir.done))
+
+#######################
+##---] TARGETS [---##
+#######################
+
+%/.mkdir.done: # mkdir -p -p => mkdir -p
+ $(subst $(space)-p,$(null),$(MKDIR)) -p '$(dir $@)'
+# Make the timestamp old enough for not being a problem with symbolic links
+# targets depending on it. Use Jan 3, 1980 to accomodate any timezone where
+# 198001010000 would translate to something older than FAT epoch.
+ @$(TOUCH) -t 198001030000 '$@'
+
+# A handful of makefiles are attempting "mkdir dot".
+# tbpl/valgrind builds are using this target
+# https://bugzilla.mozilla.org/show_bug.cgi?id=837754
+.mkdir.done:
+ @echo 'WARNING: $(MKDIR) -dot- requested by $(MAKE) -C $(CURDIR) $(MAKECMDGOALS)'
+ @$(TOUCH) -t 198001030000 '$@'
+
+INCLUDED_AUTOTARGETS_MK = 1
+endif #}
+
+
+## Accumulate deps and cleanup
+ifneq (,$(GENERATED_DIRS))
+ GENERATED_DIRS := $(strip $(sort $(GENERATED_DIRS)))
+ tmpauto :=$(call mkdir_deps,GENERATED_DIRS)
+ GENERATED_DIRS_DEPS +=$(tmpauto)
+endif
+
+#################################################################
+# One ring/dep to rule them all:
+# config/rules.mk::all target is available by default
+# Add $(AUTO_DEPS) as an explicit target dependency when needed.
+#################################################################
+
+AUTO_DEPS +=$(GENERATED_DIRS_DEPS)
+AUTO_DEPS := $(strip $(sort $(AUTO_DEPS)))
+
+# Complain loudly if deps have not loaded so getargv != $(NULL)
+$(call requiredfunction,getargv)
diff --git a/config/makefiles/debugmake.mk b/config/makefiles/debugmake.mk
new file mode 100644
index 0000000000..bf2db445a3
--- /dev/null
+++ b/config/makefiles/debugmake.mk
@@ -0,0 +1,114 @@
+# -*- makefile -*-
+# vim:set ts=8 sw=8 sts=8 noet:
+#
+# 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/.
+#
+
+###########################################################################
+## Intent: Helper targets for displaying variables and state information
+###########################################################################
+
+# Support usage outside of config/rules.mk
+ifndef INCLUDED_DEBUGMAKE_MK #{
+
+define CR
+
+
+endef
+
+define shell_quote
+'$(subst $(CR),\$(CR),$(subst ','\'',$(1)))'
+endef
+
+echo-variable-%:
+ @echo $(call shell_quote,$($*))
+
+echo-dirs:
+ @echo $(call shell_quote,$(DIRS))
+
+define print_var
+@printf '%20s = %s\n' $1 $(call shell_quote,$($1))
+
+endef
+
+define print_vars
+$(foreach var,$1,$(call print_var,$(var)))
+endef
+
+showtargs:
+ifneq (,$(filter $(PROGRAM) $(HOST_PROGRAM) $(SIMPLE_PROGRAMS) $(LIBRARY) $(SHARED_LIBRARY),$(TARGETS)))
+ @echo --------------------------------------------------------------------------------
+ $(call print_vars,\
+ PROGRAM \
+ SIMPLE_PROGRAMS \
+ LIBRARY \
+ SHARED_LIBRARY \
+ LIBS \
+ DEF_FILE \
+ IMPORT_LIBRARY \
+ STATIC_LIBS \
+ SHARED_LIBS \
+ EXTRA_DSO_LDOPTS \
+ DEPENDENT_LIBS \
+ )
+ @echo --------------------------------------------------------------------------------
+endif
+ $(LOOP_OVER_DIRS)
+
+showbuild showhost: _DEPEND_CFLAGS=
+showbuild showhost: COMPILE_PDB_FLAG=
+showbuild:
+ $(call print_vars,\
+ MOZ_WIDGET_TOOLKIT \
+ CC \
+ CXX \
+ CCC \
+ CPP \
+ LD \
+ AR \
+ MKSHLIB \
+ MKCSHLIB \
+ RC \
+ CFLAGS \
+ OS_CFLAGS \
+ COMPILE_CFLAGS \
+ CXXFLAGS \
+ OS_CXXFLAGS \
+ COMPILE_CXXFLAGS \
+ COMPILE_CMFLAGS \
+ COMPILE_CMMFLAGS \
+ LDFLAGS \
+ OS_LDFLAGS \
+ DSO_LDOPTS \
+ OS_INCLUDES \
+ OS_LIBS \
+ BIN_FLAGS \
+ INCLUDES \
+ DEFINES \
+ ACDEFINES \
+ BIN_SUFFIX \
+ LIB_SUFFIX \
+ DLL_SUFFIX \
+ IMPORT_LIB_SUFFIX \
+ INSTALL \
+ VPATH \
+ )
+
+showhost:
+ $(call print_vars,\
+ HOST_CC \
+ HOST_CXX \
+ HOST_CFLAGS \
+ HOST_LDFLAGS \
+ HOST_LIBS \
+ HOST_EXTRA_LIBS \
+ HOST_EXTRA_DEPS \
+ HOST_PROGRAM \
+ HOST_OBJS \
+ HOST_PROGOBJS \
+ )
+
+INCLUDED_DEBUGMAKE_MK = 1
+endif #}
diff --git a/config/makefiles/functions.mk b/config/makefiles/functions.mk
new file mode 100644
index 0000000000..65c9a6749f
--- /dev/null
+++ b/config/makefiles/functions.mk
@@ -0,0 +1,41 @@
+#
+# 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/.
+
+#
+# functions.mk
+#
+# Defines functions that are needed by various Makefiles throughout the build
+# system, which are needed before config.mk can be included.
+#
+
+# Define an include-at-most-once flag
+ifdef INCLUDED_FUNCTIONS_MK
+$(error Do not include functions.mk twice!)
+endif
+INCLUDED_FUNCTIONS_MK = 1
+
+core_abspath = $(error core_abspath is unsupported, use $$(abspath) instead)
+core_realpath = $(error core_realpath is unsupported)
+
+core_winabspath = $(error core_winabspath is unsupported)
+
+# Run a named Python build action. The first argument is the name of the build
+# action. The second argument are the arguments to pass to the action (space
+# delimited arguments). e.g.
+#
+# libs::
+# $(call py_action,purge_manifests,_build_manifests/purge/foo.manifest)
+#
+# The first argument can optionally contain the name of the file being created
+# or processed. e.g.
+# libs::
+# $(call py_action,purge_manifests foo.manifest,_build_manifests/purge/foo.manifest)
+# This optional name will be displayed in build profiles.
+define py_action
+$(call BUILDSTATUS,START_$(firstword $(1)) $(or $(word 2,$(1)),$(2)))
+$(if $(3),cd $(3) && )$(PYTHON3) -m mozbuild.action.$(firstword $(1)) $(2)
+$(call BUILDSTATUS,END_$(firstword $(1)) $(or $(word 2,$(1)),$(2)))
+
+endef
diff --git a/config/makefiles/makeutils.mk b/config/makefiles/makeutils.mk
new file mode 100644
index 0000000000..95c7791a4b
--- /dev/null
+++ b/config/makefiles/makeutils.mk
@@ -0,0 +1,121 @@
+# -*- makefile -*-
+# vim:set ts=8 sw=8 sts=8 noet:
+#
+# 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/.
+
+## Identify function argument types
+istype =$(if $(value ${1}),list,scalar)
+isval =$(if $(filter-out list,$(call istype,${1})),true)
+isvar =$(if $(filter-out scalar,$(call istype,${1})),true)
+
+# Access up to 9 arguments passed, option needed to emulate $*
+# Inline for function expansion, do not use $(call )
+argv =$(strip
+argv +=$(if $(1), $(1))$(if $(2), $(2))$(if $(3), $(3))$(if $(4), $(4))
+argv +=$(if $(5), $(5))$(if $(6), $(6))$(if $(7), $(7))$(if $(8), $(8))
+argv +=$(if $(9), $(9))
+argv +=$(if $(10), $(error makeutils.mk::argv can only handle 9 arguments))
+argv +=)
+
+###########################################################################
+## Access function args as a simple list, inline within user functions.
+## Usage: $(info ** $(call banner,$(getargv)))
+## $(call banner,scalar)
+## $(call banner,list0 list1 list2)
+## $(call banner,ref) ; ref=foo bar tans
+## getarglist() would be a more accurate name but is longer to type
+getargv = $(if $(call isvar,$(1)),$($(1)),$(argv))
+
+###########################################################################
+# Strip [n] leading options from an argument list. This will allow passing
+# extra args to user functions that will not propogate to sub-$(call )'s
+# Usage: $(call subargv,2)
+subargv =$(wordlist $(1),$(words $(getargv)),$(getargv))
+
+###########################################################################
+# Intent: Display a distinct banner heading in the output stream
+# Usage: $(call banner,BUILDING: foo bar tans)
+# Debug:
+# target-preqs = \
+# $(call banner,target-preqs-BEGIN) \
+# foo bar tans \
+# $(call banner,target-preqs-END) \
+# $(NULL)
+# target: $(target-preqs)
+
+banner = \
+$(info ) \
+$(info ***************************************************************************) \
+$(info ** $(getargv)) \
+$(info ***************************************************************************) \
+$(NULL)
+
+#####################################################################
+# Intent: Determine if a string or pattern is contained in a list
+# Usage: strcmp - $(call if_XinY,clean,$(MAKECMDGOALS))
+# : pattern - $(call if_XinY,clean%,$(MAKECMDGOALS))
+is_XinY =$(filter $(1),$(call subargv,3,$(getargv)))
+
+#####################################################################
+# Provide an alternate var to support testing
+ifdef MAKEUTILS_UNIT_TEST
+ mcg_goals=TEST_MAKECMDGOALS
+else
+ mcg_goals=MAKECMDGOALS
+endif
+
+# Intent: Conditionals for detecting common/tier target use
+isTargetStem = $(sort \
+ $(foreach var,$(getargv),\
+ $(foreach pat,$(var)% %$(var),\
+ $(call is_XinY,$(pat),${$(mcg_goals)})\
+ )))
+isTargetStemClean = $(call isTargetStem,clean)
+isTargetStemExport = $(call isTargetStem,export)
+isTargetStemLibs = $(call isTargetStem,libs)
+isTargetStemTools = $(call isTargetStem,tools)
+
+##################################################
+# Intent: Validation functions / unit test helpers
+
+errorifneq =$(if $(subst $(strip $(1)),$(NULL),$(strip $(2))),$(error expected [$(1)] but found [$(2)]))
+
+# Intent: verify function declaration exists
+requiredfunction =$(foreach func,$(1) $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9),$(if $(value $(func)),$(NULL),$(error required function [$(func)] is unavailable)))
+
+
+
+## http://www.gnu.org/software/make/manual/make.html#Call-Function
+## Usage: o = $(call map,origin,o map $(MAKE))
+map = $(foreach val,$(2),$(call $(1),$(val)))
+
+
+## Disable checking for clean targets
+ifeq (,$(filter %clean clean%,$(MAKECMDGOALS))) #{
+
+# Usage: $(call checkIfEmpty,[error|warning] foo NULL bar)
+checkIfEmpty =$(foreach var,$(wordlist 2,100,$(argv)),$(if $(strip $($(var))),$(NOP),$(call $(1),Variable $(var) does not contain a value)))
+
+# Usage: $(call errorIfEmpty,foo NULL bar)
+errorIfEmpty =$(call checkIfEmpty,error $(argv))
+warnIfEmpty =$(call checkIfEmpty,warning $(argv))
+
+endif #}
+
+###########################################################################
+## Common makefile library loader
+###########################################################################
+ifdef MOZILLA_DIR
+topORerr = $(MOZILLA_DIR)
+else
+topORerr = $(if $(topsrcdir),$(topsrcdir),$(error topsrcdir is not defined))
+endif
+
+ifdef USE_AUTOTARGETS_MK # mkdir_deps
+ include $(topORerr)/config/makefiles/autotargets.mk
+endif
+
+## copy(src, dst): recursive copy
+copy_dir = (cd $(1)/. && $(TAR) $(TAR_CREATE_FLAGS) - .) | (cd $(2)/. && tar -xf -)
diff --git a/config/makefiles/nonrecursive.mk b/config/makefiles/nonrecursive.mk
new file mode 100644
index 0000000000..498de568e7
--- /dev/null
+++ b/config/makefiles/nonrecursive.mk
@@ -0,0 +1,68 @@
+# -*- makefile -*-
+# vim:set ts=8 sw=8 sts=8 noet:
+#
+# 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/.
+
+# The purpose of this file is to pull in non-recursive targets when performing
+# a partial tree (not top-level) build. This will allow people to continue to
+# build individual directories while some of the targets may not be normally
+# defined in that make file.
+#
+# Non-recursive targets are attached to existing make targets. The
+# NONRECURSIVE_TARGETS variable lists the make targets that modified. For
+# each target in this list, the NONRECURSIVE_TARGET_<target> variable will
+# contain a list of partial variable names. We will then look in variables
+# named NONRECURSIVE_TARGETS_<target>_<fragment>_* for information describing
+# how to evaluate non-recursive make targets.
+#
+# Targets are defined by the following variables:
+#
+# FILE - The make file to evaluate. This is equivalent to
+# |make -f <FILE>|
+# DIRECTORY - The directory whose Makefile to evaluate. This is
+# equivalent to |make -C <DIRECTORY>|.
+# TARGETS - Targets to evaluate in that make file.
+#
+# Only 1 of FILE or DIRECTORY may be defined.
+#
+# For example:
+#
+# NONRECURSIVE_TARGETS = export libs
+# NONRECURSIVE_TARGETS_export = headers
+# NONRECURSIVE_TARGETS_export_headers_FILE = /path/to/exports.mk
+# NONRECURSIVE_TARGETS_export_headers_TARGETS = $(DIST)/include/foo.h $(DIST)/include/bar.h
+# NONRECURSIVE_TARGETS_libs = cppsrcs
+# NONRECURSIVE_TARGETS_libs_cppsrcs_DIRECTORY = $(DEPTH)/foo
+# NONRECURSIVE_TARGETS_libs_cppsrcs_TARGETS = /path/to/foo.o /path/to/bar.o
+#
+# Will get turned into the following:
+#
+# exports::
+# $(MAKE) -C $(DEPTH) -f /path/to/exports.mk $(DIST)/include/foo.h $(DIST)/include/bar.h
+#
+# libs::
+# $(MAKE) -C $(DEPTH)/foo /path/to/foo.o /path/to/bar.o
+
+ifndef INCLUDED_NONRECURSIVE_MK
+
+define define_nonrecursive_target
+$(1)::
+ $$(MAKE) -C $(or $(4),$$(DEPTH)) $(addprefix -f ,$(3)) $(2)
+endef
+
+$(foreach target,$(NONRECURSIVE_TARGETS), \
+ $(foreach entry,$(NONRECURSIVE_TARGETS_$(target)), \
+ $(eval $(call define_nonrecursive_target, \
+ $(target), \
+ $(NONRECURSIVE_TARGETS_$(target)_$(entry)_TARGETS), \
+ $(NONRECURSIVE_TARGETS_$(target)_$(entry)_FILE), \
+ $(NONRECURSIVE_TARGETS_$(target)_$(entry)_DIRECTORY), \
+ )) \
+ ) \
+)
+
+INCLUDED_NONRECURSIVE_MK := 1
+endif
+
diff --git a/config/makefiles/rust.mk b/config/makefiles/rust.mk
new file mode 100644
index 0000000000..9e3d5256b9
--- /dev/null
+++ b/config/makefiles/rust.mk
@@ -0,0 +1,613 @@
+# 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
+
+ifneq (,$(USE_CARGO_JSON_MESSAGE_FORMAT))
+cargo_build_flags += --message-format=json
+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)))
+ifdef NO_ANSI
+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.
+cargo_build_flags += $(filter -j1,$(MAKEFLAGS))
+
+# 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
+
+rustflags_sancov =
+ifdef LIBFUZZER
+ifndef MOZ_TSAN
+ifndef FUZZING_JS_FUZZILLI
+# These options should match what is implicitly enabled for `clang -fsanitize=fuzzer`
+# here: https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/Driver/SanitizerArgs.cpp#L422
+#
+# -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-module -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
+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
+# Never enable when sancov is enabled to work around https://github.com/rust-lang/rust/issues/90300.
+ifndef rustflags_sancov
+# Never enable when coverage is enabled to work around https://github.com/rust-lang/rust/issues/90045.
+ifndef MOZ_CODE_COVERAGE
+ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE)))
+cargo_rustc_flags += -Clto$(if $(filter full,$(MOZ_LTO_RUST_CROSS)),=fat)
+endif
+# We need -Cembed-bitcode=yes for all crates when using -Clto.
+RUSTFLAGS += -Cembed-bitcode=yes
+endif
+endif
+endif
+endif
+endif
+
+ifdef CARGO_INCREMENTAL
+export CARGO_INCREMENTAL
+endif
+
+rustflags_neon =
+ifeq (neon,$(MOZ_FPU))
+ifneq (,$(filter thumbv7neon-,$(RUST_TARGET)))
+# Enable neon and disable restriction to 16 FPU registers when neon is enabled
+# but we're not using a thumbv7neon target, where it's already the default.
+# (CPUs with neon have 32 FPU registers available)
+rustflags_neon += -C target_feature=+neon,-d16
+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
+
+ifndef CROSS_COMPILE
+ifdef MOZ_TSAN
+PASS_ONLY_BASE_CFLAGS_TO_RUST=1
+else
+ifneq (,$(MOZ_ASAN)$(MOZ_UBSAN))
+ifneq ($(OS_ARCH), Linux)
+PASS_ONLY_BASE_CFLAGS_TO_RUST=1
+endif # !Linux
+endif # MOZ_ASAN || MOZ_UBSAN
+endif # MOZ_TSAN
+endif # !CROSS_COMPILE
+
+ifeq (WINNT,$(HOST_OS_ARCH))
+ifdef MOZ_CODE_COVERAGE
+PASS_ONLY_BASE_CFLAGS_TO_RUST=1
+endif # MOZ_CODE_COVERAGE
+endif # WINNT
+
+ifeq (WINNT,$(HOST_OS_ARCH))
+normalize_sep = $(subst \,/,$(1))
+else
+normalize_sep = $(1)
+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))
+export AR_$(rust_host_cc_env_name)=$(HOST_AR)
+
+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
+endif
+ifeq (WINNT,$(OS_ARCH))
+CC_BASE_FLAGS += -DUNICODE
+CXX_BASE_FLAGS += -DUNICODE
+endif
+
+ifneq (1,$(PASS_ONLY_BASE_CFLAGS_TO_RUST))
+# -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 sanitizers
+# 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
+
+# When host == target, cargo will compile build scripts with sanitizers enabled
+# if sanitizers are enabled, which may randomly fail when they execute
+# because of https://github.com/google/sanitizers/issues/1322.
+# Work around by disabling __tls_get_addr interception (bug 1635327).
+ifeq ($(RUST_TARGET),$(RUST_HOST_TARGET))
+define sanitizer_options
+ifdef MOZ_$1
+export $1_OPTIONS:=$$($1_OPTIONS:%=%:)intercept_tls_get_addr=0
+endif
+endef
+$(foreach san,ASAN TSAN UBSAN,$(eval $(call sanitizer_options,$(san))))
+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 LIBCLANG_PATH=$(MOZ_LIBCLANG_PATH)
+export CLANG_PATH=$(MOZ_CLANG_PATH)
+export PKG_CONFIG
+export PKG_CONFIG_ALLOW_CROSS=1
+export PKG_CONFIG_PATH
+ifneq (,$(PKG_CONFIG_SYSROOT_DIR))
+export PKG_CONFIG_SYSROOT_DIR
+endif
+ifneq (,$(PKG_CONFIG_LIBDIR))
+export PKG_CONFIG_LIBDIR
+endif
+export RUST_BACKTRACE=full
+export MOZ_TOPOBJDIR=$(topobjdir)
+export MOZ_FOLD_LIBS
+export PYTHON3
+export CARGO_PROFILE_RELEASE_OPT_LEVEL
+export CARGO_PROFILE_DEV_OPT_LEVEL
+
+# 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
+
+ifndef RUSTC_BOOTSTRAP
+RUSTC_BOOTSTRAP := mozglue_static,qcms
+ifdef MOZ_RUST_SIMD
+RUSTC_BOOTSTRAP := $(RUSTC_BOOTSTRAP),encoding_rs,packed_simd
+endif
+export RUSTC_BOOTSTRAP
+endif
+
+target_rust_ltoable := force-cargo-library-build $(ADD_RUST_LTOABLE)
+target_rust_nonltoable := force-cargo-test-run force-cargo-program-build
+
+ifdef MOZ_PGO_RUST
+ifdef MOZ_PROFILE_GENERATE
+rust_pgo_flags := -C profile-generate=$(topobjdir)
+ifeq (1,$(words $(filter 5.% 6.% 7.% 8.% 9.% 10.% 11.%,$(CC_VERSION) $(RUSTC_LLVM_VERSION))))
+# Disable value profiling when:
+# (RUSTC_LLVM_VERSION < 12 and CC_VERSION >= 12) or (RUSTC_LLVM_VERSION >= 12 and CC_VERSION < 12)
+rust_pgo_flags += -C llvm-args=--disable-vp=true
+endif
+# 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
+
+# Work around https://github.com/rust-lang/rust/issues/112480
+ifdef MOZ_DEBUG_RUST
+ifneq (,$(filter i686-pc-windows-%,$(RUST_TARGET)))
+RUSTFLAGS += -Zmir-enable-passes=-CheckAlignment
+RUSTC_BOOTSTRAP := 1
+endif
+endif
+
+$(target_rust_ltoable): RUSTFLAGS:=$(rustflags_override) $(rustflags_sancov) $(RUSTFLAGS) $(rust_pgo_flags) \
+ $(if $(MOZ_LTO_RUST_CROSS),\
+ -Clinker-plugin-lto \
+ ,)
+$(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 udeps clippy,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_INNER
+$(if $(findstring n,$(filter-out --%, $(MAKEFLAGS))),,+)$(CARGO) $(1) $(cargo_build_flags) $(CARGO_EXTRA_FLAGS) $(cargo_extra_cli_flags)
+endef
+
+ifdef CARGO_CONTINUE_ON_ERROR
+define RUN_CARGO
+-$(RUN_CARGO_INNER)
+endef
+else
+define RUN_CARGO
+$(RUN_CARGO_INNER)
+endef
+endif
+
+# 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$(if $(BUILDSTATUS), --timings))
+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
+
+export MOZ_CLANG_NEWER_THAN_RUSTC_LLVM
+export MOZ_CARGO_WRAP_LDFLAGS
+export MOZ_CARGO_WRAP_LD
+export MOZ_CARGO_WRAP_LD_CXX
+export MOZ_CARGO_WRAP_HOST_LDFLAGS
+export MOZ_CARGO_WRAP_HOST_LD
+export MOZ_CARGO_WRAP_HOST_LD_CXX
+# 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
+
+# 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.
+# Finally, we also remove the -Wl,--build-id=uuid flag when it's in
+# the LDFLAGS. The flag was chosen over the default (build-id=sha1)
+# in developer builds, because for libxul, it's faster. But it's also
+# non-deterministic. So when the rust compiler produces procedural
+# macros as libraries, they're not reproducible. Those procedural
+# macros then end up as dependencies of other crates, and their
+# non-reproducibility leads to sccache transitively having cache
+# misses.
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LDFLAGS:=$(filter-out -fsanitize=cfi% -framework Cocoa -lobjc AudioToolbox ExceptionHandling -fprofile-% -Wl$(COMMA)--build-id=uuid,$(LDFLAGS))
+
+# When building with sanitizer, rustc links its own runtime, which conflicts
+# with the one that passing -fsanitize=* to the linker would add.
+# Ideally, we'd always do this filtering, but because the flags may also apply
+# to build scripts because cargo doesn't allow the distinction, we only filter
+# when building programs, except when using thread sanitizer where we filter
+# everywhere.
+ifneq (,$(filter -Zsanitizer=%,$(RUSTFLAGS)))
+$(if $(filter -Zsanitizer=thread,$(RUSTFLAGS)),$(TARGET_RECIPES),force-cargo-program-build): MOZ_CARGO_WRAP_LDFLAGS:=$(filter-out -fsanitize=%,$(MOZ_CARGO_WRAP_LDFLAGS))
+endif
+
+# Rustc assumes that *-windows-gnu targets build with mingw-gcc and manually
+# add runtime libraries that don't exist with mingw-clang. We created dummy
+# libraries in $(topobjdir)/build/win32, but that's not enough, because some
+# of the wanted symbols that come from these libraries are available in a
+# different library, that we add manually. We also need to avoid rustc
+# passing -nodefaultlibs to clang so that it adds clang_rt.
+ifeq (WINNT_clang,$(OS_ARCH)_$(CC_TYPE))
+force-cargo-program-build: MOZ_CARGO_WRAP_LDFLAGS+=-L$(topobjdir)/build/win32 -lunwind
+force-cargo-program-build: CARGO_RUSTCFLAGS += -C default-linker-libraries=yes
+endif
+
+# Rustc passes -nodefaultlibs to the linker (clang) on mac, which prevents
+# clang from adding the necessary sanitizer runtimes when building with
+# C/C++ sanitizer but without rust sanitizer.
+ifeq (Darwin,$(OS_ARCH))
+ifeq (,$(filter -Zsanitizer=%,$(RUSTFLAGS)))
+ifneq (,$(filter -fsanitize=%,$(LDFLAGS)))
+force-cargo-program-build: CARGO_RUSTCFLAGS += -C default-linker-libraries=yes
+endif
+endif
+endif
+
+$(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)
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LD_CXX:=$(CXX)
+else
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LD:=$(LINKER)
+$(TARGET_RECIPES): MOZ_CARGO_WRAP_LD_CXX:=$(LINKER)
+endif
+
+ifeq (,$(filter clang-cl,$(HOST_CC_TYPE)))
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD:=$(HOST_CC)
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD_CXX:=$(HOST_CXX)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD:=$(HOST_CC)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD_CXX:=$(HOST_CXX)
+else
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD:=$(HOST_LINKER)
+$(HOST_RECIPES): MOZ_CARGO_WRAP_LD_CXX:=$(HOST_LINKER)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD:=$(HOST_LINKER)
+$(TARGET_RECIPES) $(HOST_RECIPES): MOZ_CARGO_WRAP_HOST_LD_CXX:=$(HOST_LINKER)
+endif
+
+define make_default_rule
+$(1):
+
+endef
+
+# make_cargo_rule(target, real-target [, extra-deps])
+# Generates a rule suitable to rebuild $(target) only if its dependencies are
+# obsolete.
+# It relies on the fact that upon build, cargo generates a dependency file named
+# `$(target).d'. Unfortunately the lhs of the rule has an absolute path,
+# so we extract it under the name $(target)_deps below.
+#
+# If the dependencies are empty, the file was not created so we force a rebuild.
+# Otherwise we add it to the dependency list.
+#
+# The actual rule is a bit tricky. The `+' prefix allow for recursive parallel
+# make, and it's skipped (`:') if we already triggered a rebuild as part of the
+# dependency chain.
+#
+# Another tricky thing: some dependencies may contain escaped spaces, and they
+# need to be preserved, but $(foreach) splits on spaces, so we replace escaped
+# spaces with some unlikely string for the foreach, and replace them back in the
+# loop itself.
+define make_cargo_rule
+$(notdir $(1))_deps := $$(wordlist 2, 10000000, $$(if $$(wildcard $(basename $(1)).d),$$(shell cat $(basename $(1)).d)))
+$(1): $(CARGO_FILE) $(3) $(topsrcdir)/Cargo.lock $$(if $$($(notdir $(1))_deps),$$($(notdir $(1))_deps),$(2))
+ $$(REPORT_BUILD)
+ $$(if $$($(notdir $(1))_deps),+$(MAKE) $(2),:)
+
+$$(foreach dep, $$(call normalize_sep,$$(subst \ ,_^_^_^_,$$($(notdir $(1))_deps))),$$(eval $$(call make_default_rule,$$(subst _^_^_^_,\ ,$$(dep)))))
+endef
+
+ifdef RUST_LIBRARY_FILE
+
+rust_features_flag := --features '$(if $(RUST_LIBRARY_FEATURES),$(RUST_LIBRARY_FEATURES) )mozilla-central-workspace-hack'
+
+ifeq (WASI,$(OS_ARCH))
+# The rust wasi target defaults to statically link the wasi crt, but when we
+# build static libraries from rust and link them with C/C++ code, we also link
+# a wasi crt, which may conflict with rust's.
+force-cargo-library-build: CARGO_RUSTCFLAGS += -C target-feature=-crt-static
+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:
+ $(call BUILDSTATUS,START_Rust $(notdir $(RUST_LIBRARY_FILE)))
+ $(call CARGO_BUILD) --lib $(cargo_target_flag) $(rust_features_flag) -- $(cargo_rustc_flags)
+ $(call BUILDSTATUS,END_Rust $(notdir $(RUST_LIBRARY_FILE)))
+# 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 $(@F),--networking $(RUST_LIBRARY_FILE))
+endif
+endif
+endif
+endif
+endif
+
+$(eval $(call make_cargo_rule,$(RUST_LIBRARY_FILE),force-cargo-library-build))
+
+SUGGEST_INSTALL_ON_FAILURE = (ret=$$?; if [ $$ret = 101 ]; then echo If $1 is not installed, install it using: cargo install $1; fi; exit $$ret)
+
+ifndef CARGO_NO_AUTO_ARG
+force-cargo-library-%:
+ $(call RUN_CARGO,$*) --lib $(cargo_target_flag) $(rust_features_flag) || $(call SUGGEST_INSTALL_ON_FAILURE,cargo-$*)
+else
+force-cargo-library-%:
+ $(call RUN_CARGO,$*) || $(call SUGGEST_INSTALL_ON_FAILURE,cargo-$*)
+endif
+
+else
+force-cargo-library-%:
+ @true
+
+endif # RUST_LIBRARY_FILE
+
+ifdef RUST_TESTS
+
+rust_test_options := $(foreach test,$(RUST_TESTS),-p $(test))
+
+rust_test_features_flag := --features '$(if $(RUST_TEST_FEATURES),$(RUST_TEST_FEATURES) )mozilla-central-workspace-hack'
+
+# 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 # RUST_TESTS
+
+ifdef HOST_RUST_LIBRARY_FILE
+
+host_rust_features_flag := --features '$(if $(HOST_RUST_LIBRARY_FEATURES),$(HOST_RUST_LIBRARY_FEATURES) )mozilla-central-workspace-hack'
+
+force-cargo-host-library-build:
+ $(call BUILDSTATUS,START_Rust $(notdir $(HOST_RUST_LIBRARY_FILE)))
+ $(call CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
+ $(call BUILDSTATUS,END_Rust $(notdir $(HOST_RUST_LIBRARY_FILE)))
+
+$(eval $(call make_cargo_rule,$(HOST_RUST_LIBRARY_FILE),force-cargo-host-library-build))
+
+ifndef CARGO_NO_AUTO_ARG
+force-cargo-host-library-%:
+ $(call RUN_CARGO,$*) --lib $(cargo_host_flag) $(host_rust_features_flag)
+else
+force-cargo-host-library-%:
+ $(call RUN_CARGO,$*) --lib $(filter-out --release $(cargo_host_flag)) $(host_rust_features_flag)
+endif
+
+else
+force-cargo-host-library-%:
+ @true
+endif # HOST_RUST_LIBRARY_FILE
+
+ifdef RUST_PROGRAMS
+
+program_features_flag := --features mozilla-central-workspace-hack
+
+force-cargo-program-build: $(call resfile,module)
+ $(call BUILDSTATUS,START_Rust $(RUST_CARGO_PROGRAMS))
+ $(call CARGO_BUILD) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag) $(program_features_flag) -- $(addprefix -C link-arg=$(CURDIR)/,$(call resfile,module)) $(CARGO_RUSTCFLAGS)
+ $(call BUILDSTATUS,END_Rust $(RUST_CARGO_PROGRAMS))
+
+$(foreach RUST_PROGRAM,$(RUST_PROGRAMS), $(eval $(call make_cargo_rule,$(RUST_PROGRAM),force-cargo-program-build,$(call resfile,module))))
+
+ifndef CARGO_NO_AUTO_ARG
+force-cargo-program-%:
+ $(call RUN_CARGO,$*) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag) $(program_features_flag)
+else
+force-cargo-program-%:
+ $(call RUN_CARGO,$*)
+endif
+
+else
+force-cargo-program-%:
+ @true
+endif # RUST_PROGRAMS
+ifdef HOST_RUST_PROGRAMS
+
+host_program_features_flag := --features mozilla-central-workspace-hack
+
+force-cargo-host-program-build:
+ $(call BUILDSTATUS,START_Rust $(HOST_RUST_CARGO_PROGRAMS))
+ $(call CARGO_BUILD) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag) $(host_program_features_flag)
+ $(call BUILDSTATUS,END_Rust $(HOST_RUST_CARGO_PROGRAMS))
+
+$(foreach HOST_RUST_PROGRAM,$(HOST_RUST_PROGRAMS), $(eval $(call make_cargo_rule,$(HOST_RUST_PROGRAM),force-cargo-host-program-build)))
+
+ifndef CARGO_NO_AUTO_ARG
+force-cargo-host-program-%:
+ $(call BUILDSTATUS,START_Rust $(HOST_RUST_CARGO_PROGRAMS))
+ $(call RUN_CARGO,$*) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag) $(host_program_features_flag)
+ $(call BUILDSTATUS,END_Rust $(HOST_RUST_CARGO_PROGRAMS))
+else
+force-cargo-host-program-%:
+ $(call RUN_CARGO,$*) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(filter-out --release $(cargo_target_flag))
+endif
+
+else
+force-cargo-host-program-%:
+ @true
+
+endif # HOST_RUST_PROGRAMS
diff --git a/config/makefiles/target_binaries.mk b/config/makefiles/target_binaries.mk
new file mode 100644
index 0000000000..31b2c4367e
--- /dev/null
+++ b/config/makefiles/target_binaries.mk
@@ -0,0 +1,43 @@
+# -*- makefile -*-
+# vim:set ts=8 sw=8 sts=8 noet:
+#
+# 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/.
+
+ifndef NO_DIST_INSTALL
+
+ifneq (,$(strip $(SIMPLE_PROGRAMS)$(RUST_PROGRAMS)))
+PROGRAMS_EXECUTABLES = $(SIMPLE_PROGRAMS) $(RUST_PROGRAMS)
+PROGRAMS_DEST ?= $(FINAL_TARGET)
+PROGRAMS_TARGET := target
+INSTALL_TARGETS += PROGRAMS
+endif
+
+
+ifdef SHARED_LIBRARY
+SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
+SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)
+ifndef SHARED_LIBRARY_TARGET
+SHARED_LIBRARY_TARGET = target
+endif
+INSTALL_TARGETS += SHARED_LIBRARY
+endif # SHARED_LIBRARY
+
+ifdef WASM_LIBRARY
+WASM_LIBRARY_FILES = $(WASM_LIBRARY)
+WASM_LIBRARY_DEST ?= $(FINAL_TARGET)
+WASM_LIBRARY_TARGET = target
+INSTALL_TARGETS += WASM_LIBRARY
+endif
+
+ifneq (,$(strip $(HOST_SIMPLE_PROGRAMS)))
+HOST_PROGRAMS_EXECUTABLES = $(HOST_SIMPLE_PROGRAMS) $(HOST_RUST_PROGRAMS)
+HOST_PROGRAMS_DEST ?= $(DIST)/host/bin
+HOST_PROGRAMS_TARGET = host
+INSTALL_TARGETS += HOST_PROGRAMS
+endif
+
+endif # !NO_DIST_INSTALL
+
+# EOF
diff --git a/config/makefiles/xpidl/Makefile.in b/config/makefiles/xpidl/Makefile.in
new file mode 100644
index 0000000000..96601d6cb9
--- /dev/null
+++ b/config/makefiles/xpidl/Makefile.in
@@ -0,0 +1,94 @@
+# 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/.
+
+STANDALONE_MAKEFILE := 1
+
+include $(topsrcdir)/config/rules.mk
+
+# Building XPIDLs effectively consists of two steps:
+#
+# 1) Staging all .idl files to a common directory.
+# 2) Doing everything with the .idl files.
+#
+# Each .idl file is processed into a .h file and typelib information.
+# The .h file shares the same stem as the input file and is installed
+# in the common headers include directory.
+#
+# XPIDL files are logically grouped together by modules. The typelib
+# information for all XPIDLs in the same module is linked together into
+# an .xpt file having the name of the module.
+#
+# As an optimization to reduce overall CPU usage, we process all .idl
+# belonging to a module with a single command invocation. This prevents
+# redundant parsing of .idl files and significantly reduces CPU cycles.
+
+# For dependency files.
+idl_deps_dir := .deps
+
+dist_idl_dir := $(DIST)/idl
+dist_include_dir := $(DIST)/include
+dist_xpcrs_dir := $(DIST)/xpcrs
+stub_file := xptdata.stub
+process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py
+target_file := $(topobjdir)/xpcom/reflect/xptinfo/xptdata.cpp
+xptdata_h := $(dist_include_dir)/xptdata.h
+generated_files := $(target_file) $(xptdata_h)
+code_gen_py := $(topsrcdir)/xpcom/reflect/xptinfo/xptcodegen.py
+code_gen_deps := $(topsrcdir)/xpcom/ds/tools/perfecthash.py
+
+# TODO we should use py_action, but that would require extra directories to be
+# in the virtualenv.
+%.xpt:
+ $(REPORT_BUILD)
+ $(call BUILDSTATUS,START_xpt $@)
+ $(PYTHON3) $(process_py) --depsdir $(idl_deps_dir) \
+ --bindings-conf $(topsrcdir)/dom/bindings/Bindings.conf \
+ $(foreach dir,$(all_idl_dirs),-I $(dir)) \
+ $(dist_include_dir) $(dist_xpcrs_dir) $(@D) \
+ $(basename $(notdir $@)) $($(basename $(notdir $@))_deps)
+# When some IDL is added or removed, if the actual IDL file was already, or
+# still is, in the tree, simple dependencies can't detect that the XPT needs
+# to be rebuilt.
+# Add the current value of $($(xpidl_module)_deps) in the depend file, such that
+# we can later check if the value has changed since last build, which will
+# indicate whether IDLs were added or removed.
+# Note that removing previously built files is not covered.
+ @echo $(basename $(notdir $@))_deps_built = $($(basename $(notdir $@))_deps) >> $(idl_deps_dir)/$(basename $(notdir $@)).pp
+ $(call BUILDSTATUS,END_xpt $@)
+
+xpidl_modules := @xpidl_modules@
+xpt_files := $(addsuffix .xpt,$(xpidl_modules))
+
+@xpidl_rules@
+
+depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
+
+ifdef COMPILE_ENVIRONMENT
+xpidl:: $(generated_files)
+endif
+
+# See bug 1420119 for why we need the semicolon.
+$(target_file) $(xptdata_h) : $(stub_file) ;
+
+$(xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir) $(dist_xpcrs_dir))
+
+$(stub_file) : $(xpt_files) $(code_gen_py) $(code_gen_deps)
+ $(REPORT_BUILD)
+ $(call BUILDSTATUS,START_xpt $(notdir $(generated_files)))
+ $(PYTHON3) $(code_gen_py) $(generated_files) $(xpt_files)
+ @touch $@
+ $(call BUILDSTATUS,END_xpt $(notdir $(generated_files)))
+
+-include $(depends_files)
+
+define xpt_deps
+$(1): $(call mkdir_deps,$(dir $(1)))
+ifneq ($($(basename $(notdir $(1)))_deps),$($(basename $(notdir $(1)))_deps_built))
+$(1): FORCE
+endif
+endef
+
+$(foreach xpt,$(xpt_files),$(eval $(call xpt_deps,$(xpt))))
+
+.PHONY: xpidl