From 732c369b7ed6c9d274589d72db21008527c41796 Mon Sep 17 00:00:00 2001 From: chrysn Date: Fri, 2 Apr 2021 19:01:19 +0200 Subject: [PATCH] makefiles: Add mechanism to build modules through Cargo ... and to dissect the static libraries into invidial .o files to link them the same way we link C. --- Makefile.include | 4 +++ makefiles/cargo-settings.inc.mk | 43 +++++++++++++++++++++++++++++++++ makefiles/cargo-targets.inc.mk | 34 ++++++++++++++++++++++++++ makefiles/vars.inc.mk | 1 + 4 files changed, 82 insertions(+) create mode 100644 makefiles/cargo-settings.inc.mk create mode 100644 makefiles/cargo-targets.inc.mk diff --git a/Makefile.include b/Makefile.include index 68be673d70..a91c125ecc 100644 --- a/Makefile.include +++ b/Makefile.include @@ -216,6 +216,8 @@ ifeq (,$(TOOLCHAIN)) override TOOLCHAIN := gnu endif +include $(RIOTMAKE)/cargo-settings.inc.mk + GLOBAL_GOALS += buildtest \ buildtest-indocker \ info-boards-features-blacklisted \ @@ -1033,6 +1035,8 @@ endif endif +include $(RIOTMAKE)/cargo-targets.inc.mk + # include RIOT_MAKEFILES_GLOBAL_POST configuration files # allows setting user specific system wide configuration parsed after the body # of $(RIOTBASE)/Makefile.include diff --git a/makefiles/cargo-settings.inc.mk b/makefiles/cargo-settings.inc.mk new file mode 100644 index 0000000000..d5e3f7ec3d --- /dev/null +++ b/makefiles/cargo-settings.inc.mk @@ -0,0 +1,43 @@ +# Rust's own version of the target triple / quadruple. +# +# This does not have a sane default, and needs to be set in the architecture +# files. +# RUST_TARGET = ... + +# Flags that need to be added to the RIOT_CFLAGS passed to cargo in order to +# make bindgen happy +CARGO_EXTRACFLAGS ?= + +# Setting anything other than "debug" or "release" will necessitate additional +# -Z unstable-options as of 2021-03 nightlies. +CARGO_PROFILE ?= release + +# The Rust version to use. +# +# As long as C2Rust and riot-wrappers require nightly, the only alternative +# here is to pick a particular nightly when something breaks. +# +# (Default is empty, because the riotbuild container picks a particular nightly +# and sets it as a default; users without a nightly default need to either +# override this here or in rustup) +CARGO_CHANNEL ?= + +# Note that if we did not set this explicitly, CARGO_LIB would have to +# understand which value cargo uses in absence of CARGO_TARGET_DIR, which would +# be $(APPDIR)/target. +# +# For many cases, it would be beneficial to base this on BINDIRBASE rather than +# BINDIR, for that would allow different boards using the same CPU to share +# compiled code (unless they they build conditionally on environment variables, +# like riot-sys does). This is not done for two reasons: +# +# * Overriding BINDIR (like is done in Murdock) would not take effect, +# requiring additional overrides to enable out-of-tree building. +# +# * Switching back and forth between two boards of the same CPU requires +# riot-sys rebuilds. (On its own, this would be outweighed by the shared +# compilation of other modules). +CARGO_TARGET_DIR = $(BINDIR)/target + +# The single Rust library to be built. +CARGO_LIB = $(CARGO_TARGET_DIR)/$(RUST_TARGET)/${CARGO_PROFILE}/lib$(APPLICATION_RUST_MODULE).a diff --git a/makefiles/cargo-targets.inc.mk b/makefiles/cargo-targets.inc.mk new file mode 100644 index 0000000000..f9343e1ddf --- /dev/null +++ b/makefiles/cargo-targets.inc.mk @@ -0,0 +1,34 @@ +CARGO_COMPILE_COMMANDS = $(BINDIR)/cargo-compile-commands.json +CARGO_COMPILE_COMMANDS_FLAGS = --clang + +# This is duplicating the compile-commands rule because unlike in the use case +# when a $(RIOTBASE)/compile_commands.json is built, we *want* this to be +# per-board and per-application. (The large mechanisms are shared anyway). +# +# Changes relative to the compile-commands rule: This uses lazysponge to keep +# Rust from rebuilding, and uses a custom output file and +# CARGO_COMPILE_COMMAND_FLAGS. +$(CARGO_COMPILE_COMMANDS): $(BUILDDEPS) + $(Q)DIRS="$(DIRS)" APPLICATION_BLOBS="$(BLOBS)" \ + "$(MAKE)" -C $(APPDIR) -f $(RIOTMAKE)/application.inc.mk compile-commands + $(Q)$(RIOTTOOLS)/compile_commands/compile_commands.py $(CARGO_COMPILE_COMMANDS_FLAGS) $(BINDIR) \ + | $(LAZYSPONGE) $@ + + +$(CARGO_LIB): $(RIOTBUILD_CONFIG_HEADER_C) $(BUILDDEPS) $(CARGO_COMPILE_COMMANDS) FORCE + $(Q)[ x"${RUST_TARGET}" != x"" ] || (echo "Error: No RUST_TARGET was set for this platform. (Set FEATURES_REQUIRED+=rust_target to catch this earlier)."; exit 1) + $(Q)CC= CFLAGS= CPPFLAGS= CXXFLAGS= RIOT_COMPILE_COMMANDS_JSON="$(CARGO_COMPILE_COMMANDS)" RIOT_USEMODULE="$(USEMODULE)" cargo $(patsubst +,,+${CARGO_CHANNEL}) build --target $(RUST_TARGET) `if [ x$(CARGO_PROFILE) = xrelease ]; then echo --release; else if [ x$(CARGO_PROFILE) '!=' xdebug ]; then echo "--profile $(CARGO_PROFILE)"; fi; fi` $(CARGO_OPTIONS) + +$(APPLICATION_RUST_MODULE).module: $(CARGO_LIB) FORCE + $(Q)# Ensure no old object files persist. These would lead to duplicate + $(Q)# symbols, or worse, lingering behaivor of XFA entries. + $(Q)rm -rf $(BINDIR)/$(APPLICATION_RUST_MODULE)/ + $(Q)mkdir -p $(BINDIR)/$(APPLICATION_RUST_MODULE)/ + + $(Q)# On cortex-m0 boards like airfy-beacon, the archive contains a + $(Q)# bin/thumbv6m-none-eabi.o file; the directory must be present for + $(Q)# ar to unpack it... + $(Q)mkdir -p $(BINDIR)/$(APPLICATION_RUST_MODULE)/bin/ + $(Q)cd $(BINDIR)/$(APPLICATION_RUST_MODULE)/ && $(AR) x $< + $(Q)# ... and move them back if any exist, careful to err if anything is duplicate + $(Q)rmdir $(BINDIR)/$(APPLICATION_RUST_MODULE)/bin/ || (mv -n $(BINDIR)/$(APPLICATION_RUST_MODULE)/bin/* $(BINDIR)/$(APPLICATION_RUST_MODULE)/ && rmdir $(BINDIR)/$(APPLICATION_RUST_MODULE)/bin/) diff --git a/makefiles/vars.inc.mk b/makefiles/vars.inc.mk index 720e473d9d..c8607d295b 100644 --- a/makefiles/vars.inc.mk +++ b/makefiles/vars.inc.mk @@ -42,6 +42,7 @@ export RIOTMAKE # Location of all supplemental Makefiles (such as t export RIOTKCONFIG # Location of all supplemental Kconfig files export BINDIRBASE # This is the folder where the application should be built in. For each BOARD a different subfolder is used. export BINDIR # This is the folder where the application should be built in. +export CARGO_TARGET_DIR # This is the folder where Rust parts of the application should be built in. export BUILD_DIR # This is the base folder to store common build files and artifacts, e.g. test results. export APPDIR # The base folder containing the application export PKGDIRBASE # The base folder for building packages