[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231027003504.146703-2-yakoyoku@gmail.com>
Date: Thu, 26 Oct 2023 21:34:50 -0300
From: Martin Rodriguez Reboredo <yakoyoku@...il.com>
To: Masahiro Yamada <masahiroy@...nel.org>,
Nathan Chancellor <nathan@...nel.org>,
Nick Desaulniers <ndesaulniers@...gle.com>,
Nicolas Schier <nicolas@...sle.eu>,
Miguel Ojeda <ojeda@...nel.org>,
Alex Gaynor <alex.gaynor@...il.com>,
Wedson Almeida Filho <wedsonaf@...il.com>,
Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
Björn Roy Baron <bjorn3_gh@...tonmail.com>,
Benno Lossin <benno.lossin@...ton.me>,
Andreas Hindborg <a.hindborg@...sung.com>,
Alice Ryhl <aliceryhl@...gle.com>, Andrew Davis <afd@...com>,
Rob Herring <robh@...nel.org>,
Shuah Khan <skhan@...uxfoundation.org>,
Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
Chuck Lever <chuck.lever@...cle.com>
Cc: linux-kbuild@...r.kernel.org, linux-kernel@...r.kernel.org,
rust-for-linux@...r.kernel.org
Subject: [RFC PATCH v2 1/2] kbuild: Build Rust crates as libraries
Enables compiling Rust crates as dependencies of kernel modules. These
are also meant to be used as libraries for other parts of the kernel.
For these crates `bindings` is also exposed to them and they get their
symbols exported for them to be used by other code.
When a composite object depends on an `.rlib` file, which by the way is
a current ar archive, Kbuild will compile it from its base Rust source
and archive it.
This makes possible to have Rust bindings for a subsystem that is
compiled either built-in or as a module. They can also be made into
modules by themselves too.
Signed-off-by: Martin Rodriguez Reboredo <yakoyoku@...il.com>
---
v1 -> v2:
- Fixed kernel compilation.
- Added support for building crates as modules.
.gitignore | 2 ++
Makefile | 4 ++--
scripts/Makefile.build | 49 +++++++++++++++++++++++++++++++++++----
scripts/Makefile.lib | 18 +++++++++++---
scripts/Makefile.modfinal | 7 +++++-
5 files changed, 70 insertions(+), 10 deletions(-)
diff --git a/.gitignore b/.gitignore
index 0bbae167bf93..8353b01e2915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@
*.o
*.o.*
*.patch
+*.rlib
*.rmeta
*.rpm
*.rsi
@@ -53,6 +54,7 @@
*.zst
Module.symvers
modules.order
+exports_*_generated.c
#
# Top-level generic files
diff --git a/Makefile b/Makefile
index 8a40530868ff..4113a5b93ddc 100644
--- a/Makefile
+++ b/Makefile
@@ -283,7 +283,7 @@ no-compiler-targets := $(no-dot-config-targets) install dtbs_install \
headers_install modules_install modules_sign kernelrelease image_name
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
image_name
-single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/
+single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rlib %.rsi %.s %.symtypes %/
config-build :=
mixed-build :=
@@ -1919,7 +1919,7 @@ $(clean-dirs):
clean: $(clean-dirs)
$(call cmd,rmfiles)
@find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
- \( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
+ \( -name '*.[aios]' -o -name '*.rlib' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '*.ko.*' \
-o -name '*.dtb' -o -name '*.dtbo' \
-o -name '*.dtb.S' -o -name '*.dtbo.S' \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index da37bfa97211..11045ddba1a9 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -20,6 +20,7 @@ always-m :=
targets :=
subdir-y :=
subdir-m :=
+rust-libs :=
EXTRA_AFLAGS :=
EXTRA_CFLAGS :=
EXTRA_CPPFLAGS :=
@@ -243,9 +244,13 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call if_changed_rule,cc_o_c)
$(call cmd,force_checksrc)
+mod_objs = $(call real-search, $*.o, .o, -objs -y -m)
+exports_objs = $(foreach m, $(sort $(basename \
+ $(filter $(notdir $(rlib-m)), $(mod_objs)))), exports_$m_generated.o)
+
# To make this rule robust against "Argument list too long" error,
# ensure to add $(obj)/ prefix by a shell command.
-cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \
+cmd_mod = printf '%s\n' $(mod_objs) $(exports_objs) | \
$(AWK) '!x[$$0]++ { print("$(obj)/"$$0) }' > $@
$(obj)/%.mod: FORCE
@@ -274,7 +279,7 @@ rust_common_cmd = \
-Zcrate-attr='feature($(rust_allowed_features))' \
--extern alloc --extern kernel \
--crate-type rlib -L $(objtree)/rust/ \
- --crate-name $(basename $(notdir $@)) \
+ --crate-name $(basename $(notdir $<)) \
--out-dir $(dir $@) --emit=dep-info=$(depfile)
# `--emit=obj`, `--emit=asm` and `--emit=llvm-ir` imply a single codegen unit
@@ -285,11 +290,42 @@ rust_common_cmd = \
# i.e. the outputs we would get for the different single targets (e.g. `.ll`)
# would not match each other.
+rlib_obj = $(dir $@)$*.$*.o
+rlib_meta = $(dir $@)$(patsubst %.rlib,%.rmeta,$(notdir $@))
+
quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $<
+quiet_cmd_ln_rlib_o = SYMLINK $@
+ cmd_ln_rlib_o = ln -s -f $*.$*.o $@
+
$(obj)/%.o: $(src)/%.rs FORCE
- $(call if_changed_dep,rustc_o_rs)
+ $(if $(findstring $@, $(rlib-y) $(rlib-m)), \
+ $(call if_changed,ln_rlib_o), $(call if_changed_dep,rustc_o_rs))
+
+quiet_cmd_rustc_rlib_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+ cmd_rustc_rlib_rs = $(rust_common_cmd) --extern bindings \
+ --emit=obj=$(rlib_obj) --emit=metadata=$(rlib_meta) $<; \
+ rm -f $@; $(AR) cDPrST $@ $(rlib_obj) $(rlib_meta)
+
+quiet_cmd_rlib_exports = EXPORTS $@
+ cmd_rlib_exports = \
+ echo "\#include <linux/module.h>" > $@; \
+ $(NM) -p --defined-only $(rlib_obj) \
+ | grep -P ' (T|R|D) (?!(init|cleanup)_module)' | cut -d ' ' -f 3 \
+ | xargs -Isymbol \
+ echo 'extern int symbol; EXPORT_SYMBOL_GPL(symbol);' >> $@
+
+$(rlib-m): $(obj)/%.o: $(obj)/exports_%_generated.o $(obj)/lib%.rlib $(src)/%.rs FORCE
+
+$(obj)/lib%.rlib: $(src)/%.rs FORCE
+ $(call if_changed_dep,rustc_rlib_rs)
+
+$(obj)/exports_%_generated.c: $(obj)/lib%.rlib FORCE
+ $(call if_changed,rlib_exports)
+
+$(obj)/exports_%_generated.o: $(obj)/exports_%_generated.c FORCE
+ $(call if_changed,cc_o_c)
quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_rsi_rs = \
@@ -394,9 +430,14 @@ $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
# To make this rule robust against "Argument list too long" error,
# remove $(obj)/ prefix, and restore it by a shell command.
+# If we have a .rlib for the archive change it for its object member
+crate-obj = $(foreach m, $1, $(if $(findstring .rlib, $m), \
+ $(basename $(m:lib%=%)).$(m:lib%.rlib=%.o),$m))
+
quiet_cmd_ar_builtin = AR $@
cmd_ar_builtin = rm -f $@; \
- $(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \
+ $(if $(real-prereqs), printf "$(obj)/%s " \
+ $(call crate-obj, $(patsubst $(obj)/%,%,$(real-prereqs))) | xargs) \
$(AR) cDPrST $@
$(obj)/built-in.a: $(real-obj-y) FORCE
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 68d0134bdbf9..3454b05dbbdc 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -45,12 +45,17 @@ else
obj-y := $(filter-out %/, $(obj-y))
endif
+rlib-y := $(foreach m, $(filter lib%.rlib, $(obj-y)), $(m:lib%.rlib=%.o))
+rlib-m := $(foreach m, $(filter lib%.rlib, $(obj-m)), $(m:lib%.rlib=%.o))
+
# Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
# List composite targets that are constructed by combining other targets
multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m)))
# List primitive targets that are compiled from source files
real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m))
+# List exported symbols from .rlib targets
+rlib-exports = $(foreach m, $1, $(if $(findstring .rlib, $m),$(m:lib%.rlib=exports_%_generated.o)) $m)
# If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object
multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y)
@@ -59,7 +64,7 @@ multi-obj-ym := $(multi-obj-y) $(multi-obj-m)
# Replace multi-part objects by their individual parts,
# including built-in.a from subdirectories
-real-obj-y := $(call real-search, $(obj-y), .o, -objs -y)
+real-obj-y := $(call rlib-exports, $(call real-search, $(obj-y), .o, -objs -y))
real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m)
always-y += $(always-m)
@@ -95,6 +100,8 @@ extra-y := $(addprefix $(obj)/,$(extra-y))
always-y := $(addprefix $(obj)/,$(always-y))
targets := $(addprefix $(obj)/,$(targets))
obj-m := $(addprefix $(obj)/,$(obj-m))
+rlib-y := $(addprefix $(obj)/,$(rlib-y))
+rlib-m := $(addprefix $(obj)/,$(rlib-m))
lib-y := $(addprefix $(obj)/,$(lib-y))
real-obj-y := $(addprefix $(obj)/,$(real-obj-y))
real-obj-m := $(addprefix $(obj)/,$(real-obj-m))
@@ -210,7 +217,11 @@ _cpp_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj)
endif
endif
-part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y)
+_rust_libs = $(foreach l, $(rust-libs), -L $(obj)/$(dir $l) --extern $(notdir $(basename $l)))
+
+part-of-module = \
+ $(if $(or $(filter $(basename $@).o, $(real-obj-m)), \
+ $(filter $(basename $@).rlib, $(real-obj-m))),y)
quiet_modtag = $(if $(part-of-module),[M], )
modkern_cflags = \
@@ -232,7 +243,8 @@ c_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(_c_flags) $(modkern_cflags) \
$(basename_flags) $(modname_flags)
-rust_flags = $(_rust_flags) $(modkern_rustflags) @$(objtree)/include/generated/rustc_cfg
+rust_flags = $(_rust_flags) $(modkern_rustflags) $(_rust_libs) \
+ @$(objtree)/include/generated/rustc_cfg
a_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(_a_flags) $(modkern_aflags)
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index b3a6aa8fbe8c..e05749a5ca0a 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -30,11 +30,16 @@ quiet_cmd_cc_o_c = CC [M] $@
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
+# Symlinks of foo.o that point to foo.foo.o are members of a .rlib archives,
+# so their exports should be added to the module
+ko_objs = $(foreach o, $(filter %.o, $^),$(if \
+ $(filter-out %$o,$(realpath $o)),$(dir $o)exports_$(notdir $*)_generated.o) $o)
+
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o += \
$(LD) -r $(KBUILD_LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
- -T scripts/module.lds -o $@ $(filter %.o, $^); \
+ -T scripts/module.lds -o $@ $(ko_objs); \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
quiet_cmd_btf_ko = BTF [M] $@
--
2.42.0
Powered by blists - more mailing lists