1################################################################################
2# Cargo package infrastructure
3#
4# This file implements an infrastructure that eases development of package
5# .mk files for Cargo packages. It should be used for all packages that use
6# Cargo as their build system.
7#
8# See the Buildroot documentation for details on the usage of this
9# infrastructure
10#
11# In terms of implementation, this Cargo infrastructure requires the .mk file
12# to only specify metadata information about the package: name, version,
13# download URL, etc.
14#
15# We still allow the package .mk file to override what the different steps
16# are doing, if needed. For example, if <PKG>_BUILD_CMDS is already defined,
17# it is used as the list of commands to perform to build the package,
18# instead of the default Cargo behaviour. The package can also define some
19# post operation hooks.
20#
21################################################################################
22
23BR_CARGO_HOME = $(DL_DIR)/br-cargo-home
24
25PKG_COMMON_CARGO_ENV = \
26	CARGO_HOME=$(BR_CARGO_HOME)
27
28# __CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS is needed to allow
29# passing the -Z target-applies-to-host, which is needed together with
30# CARGO_TARGET_APPLIES_TO_HOST to fix build problems when target
31# architecture == host architecture.
32
33# __CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS="nightly" is to allow
34# using nighly features on stable releases, i.e features that are not
35# yet considered stable.
36#
37# CARGO_UNSTABLE_HOST_CONFIG="true" enables the host specific
38# configuration feature
39#
40# CARGO_UNSTABLE_TARGET_APPLIES_TO_HOST="true" enables the nightly
41# configuration option target-applies-to-host value to be set
42#
43# CARGO_TARGET_APPLIES_TO_HOST="false" is actually setting the value
44# for this feature, which we disable, to make sure builds where target
45# arch == host arch work correctly
46PKG_CARGO_ENV = \
47	$(PKG_COMMON_CARGO_ENV) \
48	__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS="nightly" \
49	CARGO_UNSTABLE_HOST_CONFIG="true" \
50	CARGO_UNSTABLE_TARGET_APPLIES_TO_HOST="true" \
51	CARGO_TARGET_APPLIES_TO_HOST="false" \
52	CARGO_BUILD_TARGET="$(RUSTC_TARGET_NAME)" \
53	CARGO_HOST_RUSTFLAGS="$(addprefix -C link-args=,$(HOST_LDFLAGS))" \
54	CARGO_TARGET_$(call UPPERCASE,$(RUSTC_TARGET_NAME))_LINKER=$(notdir $(TARGET_CROSS))gcc
55
56# We always set both CARGO_PROFILE_DEV and CARGO_PROFILE_RELEASE
57# as we are unable to select a build profile using the environment.
58#
59# Other cargo profiles generally derive from these two profiles.
60
61# Disable incremental compilation to match release default.
62#
63# Set codegen-units to release default.
64#
65# Set split-debuginfo to default off for ELF platforms.
66PKG_CARGO_ENV += \
67	CARGO_PROFILE_DEV_INCREMENTAL="false" \
68	CARGO_PROFILE_RELEASE_INCREMENTAL="false" \
69	CARGO_PROFILE_DEV_CODEGEN_UNITS="16" \
70	CARGO_PROFILE_RELEASE_CODEGEN_UNITS="16" \
71	CARGO_PROFILE_DEV_SPLIT_DEBUGINFO="off" \
72	CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO="off"
73
74# Set the optimization level with the release default as fallback.
75ifeq ($(BR2_OPTIMIZE_0),y)
76PKG_CARGO_ENV += \
77	CARGO_PROFILE_DEV_OPT_LEVEL="0" \
78	CARGO_PROFILE_RELEASE_OPT_LEVEL="0"
79else ifeq ($(BR2_OPTIMIZE_1),y)
80PKG_CARGO_ENV += \
81	CARGO_PROFILE_DEV_OPT_LEVEL="1" \
82	CARGO_PROFILE_RELEASE_OPT_LEVEL="1"
83else ifeq ($(BR2_OPTIMIZE_2),y)
84PKG_CARGO_ENV += \
85	CARGO_PROFILE_DEV_OPT_LEVEL="2" \
86	CARGO_PROFILE_RELEASE_OPT_LEVEL="2"
87else ifeq ($(BR2_OPTIMIZE_3),y)
88PKG_CARGO_ENV += \
89	CARGO_PROFILE_DEV_OPT_LEVEL="3" \
90	CARGO_PROFILE_RELEASE_OPT_LEVEL="3"
91else ifeq ($(BR2_OPTIMIZE_G),y)
92PKG_CARGO_ENV += \
93	CARGO_PROFILE_DEV_OPT_LEVEL="0" \
94	CARGO_PROFILE_RELEASE_OPT_LEVEL="0"
95else ifeq ($(BR2_OPTIMIZE_S),y)
96PKG_CARGO_ENV += \
97	CARGO_PROFILE_DEV_OPT_LEVEL="s" \
98	CARGO_PROFILE_RELEASE_OPT_LEVEL="s"
99else ifeq ($(BR2_OPTIMIZE_FAST),y)
100PKG_CARGO_ENV += \
101	CARGO_PROFILE_DEV_OPT_LEVEL="3" \
102	CARGO_PROFILE_RELEASE_OPT_LEVEL="3"
103else
104PKG_CARGO_ENV += \
105	CARGO_PROFILE_DEV_OPT_LEVEL="3" \
106	CARGO_PROFILE_RELEASE_OPT_LEVEL="3"
107endif
108
109ifeq ($(BR2_ENABLE_LTO),y)
110PKG_CARGO_ENV += \
111	CARGO_PROFILE_DEV_LTO="true" \
112	CARGO_PROFILE_RELEASE_LTO="true"
113else
114PKG_CARGO_ENV += \
115	CARGO_PROFILE_DEV_LTO="false" \
116	CARGO_PROFILE_RELEASE_LTO="false"
117endif
118
119
120ifeq ($(BR2_ENABLE_DEBUG),y)
121ifeq ($(BR2_DEBUG_3),y)
122# full debug info
123PKG_CARGO_ENV += \
124	CARGO_PROFILE_DEV_DEBUG="2" \
125	CARGO_PROFILE_RELEASE_DEBUG="2"
126else
127# line tables only
128PKG_CARGO_ENV += \
129	CARGO_PROFILE_DEV_DEBUG="1" \
130	CARGO_PROFILE_RELEASE_DEBUG="1"
131endif
132else
133# no debug info
134PKG_CARGO_ENV += \
135	CARGO_PROFILE_DEV_DEBUG="0" \
136	CARGO_PROFILE_RELEASE_DEBUG="0"
137endif
138
139# Enabling debug-assertions enables the runtime debug_assert! macro.
140#
141# Enabling overflow-checks enables runtime panic on integer overflow.
142ifeq ($(BR2_ENABLE_RUNTIME_DEBUG),y)
143PKG_CARGO_ENV += \
144	CARGO_PROFILE_DEV_DEBUG_ASSERTIONS="true" \
145	CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="true" \
146	CARGO_PROFILE_DEV_OVERFLOW_CHECKS="true" \
147	CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="true"
148else
149PKG_CARGO_ENV += \
150	CARGO_PROFILE_DEV_DEBUG_ASSERTIONS="false" \
151	CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" \
152	CARGO_PROFILE_DEV_OVERFLOW_CHECKS="false" \
153	CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false"
154endif
155
156#
157# This is a workaround for https://github.com/rust-lang/compiler-builtins/issues/420
158# and should be removed when fixed upstream
159#
160ifeq ($(NORMALIZED_ARCH),arm)
161	PKG_CARGO_ENV += \
162		CARGO_TARGET_$(call UPPERCASE,$(RUSTC_TARGET_NAME))_RUSTFLAGS="-Clink-arg=-Wl,--allow-multiple-definition"
163endif
164
165HOST_PKG_CARGO_ENV = \
166	$(PKG_COMMON_CARGO_ENV) \
167	RUSTFLAGS="$(addprefix -C link-args=,$(HOST_LDFLAGS))"
168
169################################################################################
170# inner-cargo-package -- defines how the configuration, compilation and
171# installation of a cargo package should be done, implements a few hooks
172# to tune the build process for cargo specifities and calls the generic
173# package infrastructure to generate the necessary make targets
174#
175#  argument 1 is the lowercase package name
176#  argument 2 is the uppercase package name, including a HOST_ prefix
177#             for host packages
178#  argument 3 is the uppercase package name, without the HOST_ prefix
179#             for host packages
180#  argument 4 is the type (target or host)
181################################################################################
182
183define inner-cargo-package
184
185# We need host-rustc to run cargo at download time (for vendoring),
186# and at build and install time.
187$(2)_DOWNLOAD_DEPENDENCIES += host-rustc
188$(2)_DEPENDENCIES += host-rustc
189
190$(2)_DOWNLOAD_POST_PROCESS = cargo
191$(2)_DL_ENV += CARGO_HOME=$$(BR_CARGO_HOME)
192
193# If building in a sub directory, use that to find the Cargo.toml
194ifneq ($$($(2)_SUBDIR),)
195$(2)_DL_ENV += BR_CARGO_MANIFEST_PATH=$$($(2)_SUBDIR)/Cargo.toml
196endif
197
198# Because we append vendored info, we can't rely on the values being empty
199# once we eventually get into the generic-package infra. So, we duplicate
200# the heuristics here
201ifndef $(2)_LICENSE
202 ifdef $(3)_LICENSE
203  $(2)_LICENSE = $$($(3)_LICENSE)
204 endif
205endif
206
207# Due to vendoring, it is pretty likely that not all licenses are
208# listed in <pkg>_LICENSE. If the license is unset, it is "unknown"
209# so adding unknowns to some unknown is still some other unkown,
210# so don't append the blurb in that case.
211ifneq ($$($(2)_LICENSE),)
212$(2)_LICENSE += , vendored dependencies licenses probably not listed
213endif
214
215# Note: in all the steps below, we "cd" into the build directory to
216# execute the "cargo" tool instead of passing $(@D)/Cargo.toml as the
217# manifest-path. Indeed while the latter seems to work, it in fact
218# breaks in subtle ways as the way cargo searches for its
219# configuration file is based (among other rules) on the current
220# directory. This means that if cargo is started outside of a package
221# directory, its configuration file will not be taken into account.
222#
223# Also, we pass:
224#  * --offline to prevent cargo from downloading anything: all
225#    dependencies should have been built by the download post
226#    process logic
227#  * --locked to force cargo to use the Cargo.lock file, which ensures
228#    that a fixed set of dependency versions is used
229
230#
231# Build step. Only define it if not already defined by the package .mk
232# file.
233#
234ifndef $(2)_BUILD_CMDS
235ifeq ($(4),target)
236define $(2)_BUILD_CMDS
237	cd $$($$(PKG)_SRCDIR) && \
238	$$(TARGET_MAKE_ENV) \
239		$$(TARGET_CONFIGURE_OPTS) \
240		$$(PKG_CARGO_ENV) \
241		$$($(2)_CARGO_ENV) \
242		cargo build \
243			--offline \
244			$$(if $$(BR2_ENABLE_DEBUG),,--release) \
245			--manifest-path Cargo.toml \
246			--locked \
247			$$($(2)_CARGO_BUILD_OPTS)
248endef
249else # ifeq ($(4),target)
250define $(2)_BUILD_CMDS
251	cd $$($$(PKG)_SRCDIR) && \
252	$$(HOST_MAKE_ENV) \
253		$$(HOST_CONFIGURE_OPTS) \
254		$$(HOST_PKG_CARGO_ENV) \
255		$$($(2)_CARGO_ENV) \
256		cargo build \
257			--offline \
258			--release \
259			--manifest-path Cargo.toml \
260			--locked \
261			$$($(2)_CARGO_BUILD_OPTS)
262endef
263endif # ifeq ($(4),target)
264endif # ifndef $(2)_BUILD_CMDS
265
266#
267# Target installation step. Only define it if not already defined by
268# the package .mk file.
269#
270ifndef $(2)_INSTALL_TARGET_CMDS
271define $(2)_INSTALL_TARGET_CMDS
272	cd $$($$(PKG)_SRCDIR) && \
273	$$(TARGET_MAKE_ENV) \
274		$$(TARGET_CONFIGURE_OPTS) \
275		$$(PKG_CARGO_ENV) \
276		$$($(2)_CARGO_ENV) \
277		cargo install \
278			--offline \
279			--root $$(TARGET_DIR)/usr/ \
280			--bins \
281			--path ./ \
282			--force \
283			--locked \
284			-Z target-applies-to-host \
285			$$($(2)_CARGO_INSTALL_OPTS)
286endef
287endif
288
289ifndef $(2)_INSTALL_CMDS
290define $(2)_INSTALL_CMDS
291	cd $$($$(PKG)_SRCDIR) && \
292	$$(HOST_MAKE_ENV) \
293		$$(HOST_CONFIGURE_OPTS) \
294		$$(HOST_PKG_CARGO_ENV) \
295		$$($(2)_CARGO_ENV) \
296		cargo install \
297			--offline \
298			--root $$(HOST_DIR) \
299			--bins \
300			--path ./ \
301			--force \
302			--locked \
303			$$($(2)_CARGO_INSTALL_OPTS)
304endef
305endif
306
307# Call the generic package infrastructure to generate the necessary
308# make targets
309$(call inner-generic-package,$(1),$(2),$(3),$(4))
310
311endef
312
313################################################################################
314# cargo-package -- the target generator macro for Cargo packages
315################################################################################
316
317cargo-package = $(call inner-cargo-package,$(pkgname),$(call UPPERCASE,$(pkgname)),$(call UPPERCASE,$(pkgname)),target)
318host-cargo-package = $(call inner-cargo-package,host-$(pkgname),$(call UPPERCASE,host-$(pkgname)),$(call UPPERCASE,$(pkgname)),host)
319