When building Rust code with LLVM=1 with -j1, rustc was encountering
an error:
"multiple candidates for `rmeta` dependency `core` found", with two
candidates:
1. The host's standard library from the rustup toolchain
2. The kernel's custom libcore.rmeta in the rust/ directory
This occurred because the build system was using `-L$(objtree)/rust`
for host library builds (proc_macro2, quote, syn), which caused rustc
to search the rust/ directory. During this search, rustc would find
both the kernel's custom libcore.rmeta and gain access to the host's
standard library, creating a conflict.
The solution is to separate host libraries into a dedicated rust/host/
subdirectory and use `-L$(objtree)/rust/host` for host builds instead
of `-L$(objtree)/rust`. This ensures that:
1. Host library builds (proc_macro2, quote, syn) only search rust/host/
and never encounter the kernel's libcore.rmeta
2. Proc macro builds use `-L$(objtree)/rust/host` to find their
dependencies
3. Test builds use `-L$(objtree)/rust/test` for their dependencies
4. Target builds continue to use `-L$(objtree)/rust` as before
Special handling is added for rustdoc-pin_init, which is a host build
(to access the alloc crate) but depends on proc macros from the main
rust/ directory. It uses explicit `--extern` paths with absolute paths
to reference the proc macros without adding `-L$(objtree)/rust`, which
would reintroduce the conflict.
The rust/host/ directory is added to clean-files to ensure it's removed
during `make clean`.
Changes:
- Add clean-files := host/ to clean the generated directory
- Change host library targets from lib*.rlib to host/lib*.rlib
- Update cmd_rustc_procmacrolibrary to create host/ directory
- Update cmd_rustc_procmacro to use -L$(objtree)/rust/host
- Update cmd_rustdoc to use -L$(objtree)/rust/host for host builds
- Update cmd_rustc_test_library to use -L$(objtree)/rust/test
- Update rustdoc-pin_init to use explicit --extern paths for proc macros
Link: https://github.com/Rust-for-Linux/linux/issues/105
Link: https://github.com/linuxppc/issues/issues/451
Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com>
---
rust/Makefile | 63 ++++++++++++++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 23 deletions(-)
diff --git a/rust/Makefile b/rust/Makefile
index 9801af2e1e02..762bddc868e4 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -3,6 +3,9 @@
# Where to place rustdoc generated documentation
rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
+# Clean generated host directory
+clean-files := host/
+
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
@@ -27,7 +30,7 @@ endif
obj-$(CONFIG_RUST) += exports.o
-always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib
+always-$(CONFIG_RUST) += host/libproc_macro2.rlib host/libquote.rlib host/libsyn.rlib
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs
always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c
@@ -150,7 +153,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \
$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
- $(rustc_target_flags) -L$(objtree)/$(obj) \
+ $(rustc_target_flags) -L$(objtree)/$(obj)$(if $(rustdoc_host),/host) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
--crate-name $(subst rustdoc-,,$@) \
@@ -193,13 +196,16 @@ rustdoc-proc_macro2: $(src)/proc-macro2/lib.rs rustdoc-clean FORCE
+$(call if_changed,rustdoc)
rustdoc-quote: private rustdoc_host = yes
-rustdoc-quote: private rustc_target_flags = $(quote-flags)
+rustdoc-quote: private rustc_target_flags = $(quote-flags) \
+ --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib)
rustdoc-quote: private skip_flags = $(quote-skip_flags)
rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE
+$(call if_changed,rustdoc)
rustdoc-syn: private rustdoc_host = yes
-rustdoc-syn: private rustc_target_flags = $(syn-flags)
+rustdoc-syn: private rustc_target_flags = $(syn-flags) \
+ --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \
+ --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib)
rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE
+$(call if_changed,rustdoc)
@@ -236,7 +242,10 @@ rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs \
+$(call if_changed,rustdoc)
rustdoc-pin_init: private rustdoc_host = yes
-rustdoc-pin_init: private rustc_target_flags = $(pin_init-flags) \
+rustdoc-pin_init: private rustc_target_flags = \
+ --extern pin_init_internal=$(abspath $(objtree)/$(obj)/$(libpin_init_internal_name)) \
+ --extern macros=$(abspath $(objtree)/$(obj)/$(libmacros_name)) \
+ $(call cfgs-to-flags,$(pin_init-cfgs)) \
--extern alloc --cfg feature=\"alloc\"
rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \
rustdoc-macros FORCE
@@ -369,7 +378,9 @@ rusttest: rusttest-macros
rusttest-macros: private rustc_target_flags = --extern proc_macro \
--extern macros --extern kernel --extern pin_init \
- --extern proc_macro2 --extern quote --extern syn
+ --extern proc_macro2=$(abspath $(objtree)/$(obj)/test/libproc_macro2.rlib) \
+ --extern quote=$(abspath $(objtree)/$(obj)/test/libquote.rlib) \
+ --extern syn=$(abspath $(objtree)/$(obj)/test/libsyn.rlib)
rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
rusttest-macros: $(src)/macros/lib.rs \
rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE
@@ -525,48 +536,54 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE
quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@
cmd_rustc_procmacrolibrary = \
+ mkdir -p $(dir $@); \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \
--emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \
- --out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \
--crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $<
-$(obj)/libproc_macro2.rlib: private skip_clippy = 1
-$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
-$(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
+$(obj)/host/libproc_macro2.rlib: private skip_clippy = 1
+$(obj)/host/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags)
+$(obj)/host/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
-$(obj)/libquote.rlib: private skip_clippy = 1
-$(obj)/libquote.rlib: private skip_flags = $(quote-skip_flags)
-$(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags)
-$(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE
+$(obj)/host/libquote.rlib: private skip_clippy = 1
+$(obj)/host/libquote.rlib: private skip_flags = $(quote-skip_flags)
+$(obj)/host/libquote.rlib: private rustc_target_flags = $(quote-flags) \
+ --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib)
+$(obj)/host/libquote.rlib: $(src)/quote/lib.rs $(obj)/host/libproc_macro2.rlib FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
-$(obj)/libsyn.rlib: private skip_clippy = 1
-$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags)
-$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE
+$(obj)/host/libsyn.rlib: private skip_clippy = 1
+$(obj)/host/libsyn.rlib: private rustc_target_flags = $(syn-flags) \
+ --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \
+ --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib)
+$(obj)/host/libsyn.rlib: $(src)/syn/lib.rs $(obj)/host/libquote.rlib FORCE
+$(call if_changed_dep,rustc_procmacrolibrary)
quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
cmd_rustc_procmacro = \
- $(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
+ $(RUSTC_OR_CLIPPY) $(rust_common_flags) \
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
- --crate-type proc-macro -L$(objtree)/$(obj) \
+ --crate-type proc-macro \
+ -L$(objtree)/$(obj)/host \
--crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \
- @$(objtree)/include/generated/rustc_cfg $<
+ @$(objtree)/include/generated/rustc_cfg \
+ $(rustc_target_flags) \
+ $<
# Procedural macros can only be used with the `rustc` that compiled it.
$(obj)/$(libmacros_name): private rustc_target_flags = \
--extern proc_macro2 --extern quote --extern syn
-$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \
- $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
+$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/host/libproc_macro2.rlib \
+ $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
$(obj)/$(libpin_init_internal_name): private rustc_target_flags = $(pin_init_internal-flags)
$(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs \
- $(obj)/libproc_macro2.rlib $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE
+ $(obj)/host/libproc_macro2.rlib $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE
+$(call if_changed_dep,rustc_procmacro)
# `rustc` requires `-Zunstable-options` to use custom target specifications
--
2.53.0
On Fri Apr 3, 2026 at 3:53 PM BST, Mukesh Kumar Chaurasiya (IBM) wrote: > When building Rust code with LLVM=1 with -j1, rustc was encountering > an error: > "multiple candidates for `rmeta` dependency `core` found", with two > candidates: > 1. The host's standard library from the rustup toolchain > 2. The kernel's custom libcore.rmeta in the rust/ directory > > This occurred because the build system was using `-L$(objtree)/rust` > for host library builds (proc_macro2, quote, syn), which caused rustc > to search the rust/ directory. During this search, rustc would find > both the kernel's custom libcore.rmeta and gain access to the host's > standard library, creating a conflict. > > The solution is to separate host libraries into a dedicated rust/host/ > subdirectory and use `-L$(objtree)/rust/host` for host builds instead > of `-L$(objtree)/rust`. This ensures that: > > 1. Host library builds (proc_macro2, quote, syn) only search rust/host/ > and never encounter the kernel's libcore.rmeta > 2. Proc macro builds use `-L$(objtree)/rust/host` to find their > dependencies > 3. Test builds use `-L$(objtree)/rust/test` for their dependencies > 4. Target builds continue to use `-L$(objtree)/rust` as before > > Special handling is added for rustdoc-pin_init, which is a host build > (to access the alloc crate) but depends on proc macros from the main > rust/ directory. It uses explicit `--extern` paths with absolute paths > to reference the proc macros without adding `-L$(objtree)/rust`, which > would reintroduce the conflict. > > The rust/host/ directory is added to clean-files to ensure it's removed > during `make clean`. > > Changes: > - Add clean-files := host/ to clean the generated directory > - Change host library targets from lib*.rlib to host/lib*.rlib > - Update cmd_rustc_procmacrolibrary to create host/ directory > - Update cmd_rustc_procmacro to use -L$(objtree)/rust/host > - Update cmd_rustdoc to use -L$(objtree)/rust/host for host builds > - Update cmd_rustc_test_library to use -L$(objtree)/rust/test > - Update rustdoc-pin_init to use explicit --extern paths for proc macros This should go after the tags and ---, so it's not part of the commit message. > > Link: https://github.com/Rust-for-Linux/linux/issues/105 > Link: https://github.com/linuxppc/issues/issues/451 > Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com> > --- > rust/Makefile | 63 ++++++++++++++++++++++++++++++++------------------- > 1 file changed, 40 insertions(+), 23 deletions(-) > > diff --git a/rust/Makefile b/rust/Makefile > index 9801af2e1e02..762bddc868e4 100644 > --- a/rust/Makefile > +++ b/rust/Makefile > @@ -3,6 +3,9 @@ > # Where to place rustdoc generated documentation > rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc > > +# Clean generated host directory > +clean-files := host/ > + > obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o > always-$(CONFIG_RUST) += exports_core_generated.h > > @@ -27,7 +30,7 @@ endif > > obj-$(CONFIG_RUST) += exports.o > > -always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib > +always-$(CONFIG_RUST) += host/libproc_macro2.rlib host/libquote.rlib host/libsyn.rlib > > always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs > always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c > @@ -150,7 +153,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< > OBJTREE=$(abspath $(objtree)) \ > $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \ > $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \ > - $(rustc_target_flags) -L$(objtree)/$(obj) \ > + $(rustc_target_flags) -L$(objtree)/$(obj)$(if $(rustdoc_host),/host) \ > -Zunstable-options --generate-link-to-definition \ > --output $(rustdoc_output) \ > --crate-name $(subst rustdoc-,,$@) \ > @@ -193,13 +196,16 @@ rustdoc-proc_macro2: $(src)/proc-macro2/lib.rs rustdoc-clean FORCE > +$(call if_changed,rustdoc) > > rustdoc-quote: private rustdoc_host = yes > -rustdoc-quote: private rustc_target_flags = $(quote-flags) > +rustdoc-quote: private rustc_target_flags = $(quote-flags) \ > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) Why not just add `-L$(objtree)/$(obj)/host`? If we go with the host directory approach we shouldn't need to explicitly specify the path? Best, Gary > rustdoc-quote: private skip_flags = $(quote-skip_flags) > rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE > +$(call if_changed,rustdoc) > > rustdoc-syn: private rustdoc_host = yes > -rustdoc-syn: private rustc_target_flags = $(syn-flags) > +rustdoc-syn: private rustc_target_flags = $(syn-flags) \ > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \ > + --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib) > rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE > +$(call if_changed,rustdoc) > > @@ -236,7 +242,10 @@ rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs \ > +$(call if_changed,rustdoc) > > rustdoc-pin_init: private rustdoc_host = yes > -rustdoc-pin_init: private rustc_target_flags = $(pin_init-flags) \ > +rustdoc-pin_init: private rustc_target_flags = \ > + --extern pin_init_internal=$(abspath $(objtree)/$(obj)/$(libpin_init_internal_name)) \ > + --extern macros=$(abspath $(objtree)/$(obj)/$(libmacros_name)) \ > + $(call cfgs-to-flags,$(pin_init-cfgs)) \ > --extern alloc --cfg feature=\"alloc\" > rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \ > rustdoc-macros FORCE > @@ -369,7 +378,9 @@ rusttest: rusttest-macros > > rusttest-macros: private rustc_target_flags = --extern proc_macro \ > --extern macros --extern kernel --extern pin_init \ > - --extern proc_macro2 --extern quote --extern syn > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/test/libproc_macro2.rlib) \ > + --extern quote=$(abspath $(objtree)/$(obj)/test/libquote.rlib) \ > + --extern syn=$(abspath $(objtree)/$(obj)/test/libsyn.rlib) > rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro > rusttest-macros: $(src)/macros/lib.rs \ > rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE > @@ -525,48 +536,54 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE > > quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@ > cmd_rustc_procmacrolibrary = \ > + mkdir -p $(dir $@); \ > $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \ > $(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \ > --emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \ > - --out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \ > --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $< > > -$(obj)/libproc_macro2.rlib: private skip_clippy = 1 > -$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags) > -$(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE > +$(obj)/host/libproc_macro2.rlib: private skip_clippy = 1 > +$(obj)/host/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags) > +$(obj)/host/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE > +$(call if_changed_dep,rustc_procmacrolibrary) > > -$(obj)/libquote.rlib: private skip_clippy = 1 > -$(obj)/libquote.rlib: private skip_flags = $(quote-skip_flags) > -$(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags) > -$(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE > +$(obj)/host/libquote.rlib: private skip_clippy = 1 > +$(obj)/host/libquote.rlib: private skip_flags = $(quote-skip_flags) > +$(obj)/host/libquote.rlib: private rustc_target_flags = $(quote-flags) \ > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) > +$(obj)/host/libquote.rlib: $(src)/quote/lib.rs $(obj)/host/libproc_macro2.rlib FORCE > +$(call if_changed_dep,rustc_procmacrolibrary) > > -$(obj)/libsyn.rlib: private skip_clippy = 1 > -$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags) > -$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE > +$(obj)/host/libsyn.rlib: private skip_clippy = 1 > +$(obj)/host/libsyn.rlib: private rustc_target_flags = $(syn-flags) \ > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \ > + --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib) > +$(obj)/host/libsyn.rlib: $(src)/syn/lib.rs $(obj)/host/libquote.rlib FORCE > +$(call if_changed_dep,rustc_procmacrolibrary) > > quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@ > cmd_rustc_procmacro = \ > - $(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \ > + $(RUSTC_OR_CLIPPY) $(rust_common_flags) \ > -Clinker-flavor=gcc -Clinker=$(HOSTCC) \ > -Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \ > --emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \ > - --crate-type proc-macro -L$(objtree)/$(obj) \ > + --crate-type proc-macro \ > + -L$(objtree)/$(obj)/host \ > --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \ > - @$(objtree)/include/generated/rustc_cfg $< > + @$(objtree)/include/generated/rustc_cfg \ > + $(rustc_target_flags) \ > + $< > > # Procedural macros can only be used with the `rustc` that compiled it. > $(obj)/$(libmacros_name): private rustc_target_flags = \ > --extern proc_macro2 --extern quote --extern syn > -$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \ > - $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE > +$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/host/libproc_macro2.rlib \ > + $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE > +$(call if_changed_dep,rustc_procmacro) > > $(obj)/$(libpin_init_internal_name): private rustc_target_flags = $(pin_init_internal-flags) > $(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs \ > - $(obj)/libproc_macro2.rlib $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE > + $(obj)/host/libproc_macro2.rlib $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE > +$(call if_changed_dep,rustc_procmacro) > > # `rustc` requires `-Zunstable-options` to use custom target specifications
On Fri, Apr 03, 2026 at 04:09:04PM +0100, Gary Guo wrote: > On Fri Apr 3, 2026 at 3:53 PM BST, Mukesh Kumar Chaurasiya (IBM) wrote: > > When building Rust code with LLVM=1 with -j1, rustc was encountering > > an error: > > "multiple candidates for `rmeta` dependency `core` found", with two > > candidates: > > 1. The host's standard library from the rustup toolchain > > 2. The kernel's custom libcore.rmeta in the rust/ directory > > > > This occurred because the build system was using `-L$(objtree)/rust` > > for host library builds (proc_macro2, quote, syn), which caused rustc > > to search the rust/ directory. During this search, rustc would find > > both the kernel's custom libcore.rmeta and gain access to the host's > > standard library, creating a conflict. > > > > The solution is to separate host libraries into a dedicated rust/host/ > > subdirectory and use `-L$(objtree)/rust/host` for host builds instead > > of `-L$(objtree)/rust`. This ensures that: > > > > 1. Host library builds (proc_macro2, quote, syn) only search rust/host/ > > and never encounter the kernel's libcore.rmeta > > 2. Proc macro builds use `-L$(objtree)/rust/host` to find their > > dependencies > > 3. Test builds use `-L$(objtree)/rust/test` for their dependencies > > 4. Target builds continue to use `-L$(objtree)/rust` as before > > > > Special handling is added for rustdoc-pin_init, which is a host build > > (to access the alloc crate) but depends on proc macros from the main > > rust/ directory. It uses explicit `--extern` paths with absolute paths > > to reference the proc macros without adding `-L$(objtree)/rust`, which > > would reintroduce the conflict. > > > > The rust/host/ directory is added to clean-files to ensure it's removed > > during `make clean`. > > > > Changes: > > - Add clean-files := host/ to clean the generated directory > > - Change host library targets from lib*.rlib to host/lib*.rlib > > - Update cmd_rustc_procmacrolibrary to create host/ directory > > - Update cmd_rustc_procmacro to use -L$(objtree)/rust/host > > - Update cmd_rustdoc to use -L$(objtree)/rust/host for host builds > > - Update cmd_rustc_test_library to use -L$(objtree)/rust/test > > - Update rustdoc-pin_init to use explicit --extern paths for proc macros > > This should go after the tags and ---, so it's not part of the commit message. > Hey Gary, I was intending that to be a part of commit message. May be specifying that as changes is confusing. I'll put it there as a summary. > > > > Link: https://github.com/Rust-for-Linux/linux/issues/105 > > Link: https://github.com/linuxppc/issues/issues/451 > > Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com> > > --- > > rust/Makefile | 63 ++++++++++++++++++++++++++++++++------------------- > > 1 file changed, 40 insertions(+), 23 deletions(-) > > > > diff --git a/rust/Makefile b/rust/Makefile > > index 9801af2e1e02..762bddc868e4 100644 > > --- a/rust/Makefile > > +++ b/rust/Makefile > > @@ -3,6 +3,9 @@ > > # Where to place rustdoc generated documentation > > rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc > > > > +# Clean generated host directory > > +clean-files := host/ > > + > > obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o > > always-$(CONFIG_RUST) += exports_core_generated.h > > > > @@ -27,7 +30,7 @@ endif > > > > obj-$(CONFIG_RUST) += exports.o > > > > -always-$(CONFIG_RUST) += libproc_macro2.rlib libquote.rlib libsyn.rlib > > +always-$(CONFIG_RUST) += host/libproc_macro2.rlib host/libquote.rlib host/libsyn.rlib > > > > always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.rs > > always-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.c > > @@ -150,7 +153,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< > > OBJTREE=$(abspath $(objtree)) \ > > $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \ > > $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \ > > - $(rustc_target_flags) -L$(objtree)/$(obj) \ > > + $(rustc_target_flags) -L$(objtree)/$(obj)$(if $(rustdoc_host),/host) \ > > -Zunstable-options --generate-link-to-definition \ > > --output $(rustdoc_output) \ > > --crate-name $(subst rustdoc-,,$@) \ > > @@ -193,13 +196,16 @@ rustdoc-proc_macro2: $(src)/proc-macro2/lib.rs rustdoc-clean FORCE > > +$(call if_changed,rustdoc) > > > > rustdoc-quote: private rustdoc_host = yes > > -rustdoc-quote: private rustc_target_flags = $(quote-flags) > > +rustdoc-quote: private rustc_target_flags = $(quote-flags) \ > > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) > > Why not just add `-L$(objtree)/$(obj)/host`? If we go with the host directory > approach we shouldn't need to explicitly specify the path? > > Best, > Gary > Yeah makes sense. Will send out new revision. Regards, Mukesh > > rustdoc-quote: private skip_flags = $(quote-skip_flags) > > rustdoc-quote: $(src)/quote/lib.rs rustdoc-clean rustdoc-proc_macro2 FORCE > > +$(call if_changed,rustdoc) > > > > rustdoc-syn: private rustdoc_host = yes > > -rustdoc-syn: private rustc_target_flags = $(syn-flags) > > +rustdoc-syn: private rustc_target_flags = $(syn-flags) \ > > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \ > > + --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib) > > rustdoc-syn: $(src)/syn/lib.rs rustdoc-clean rustdoc-quote FORCE > > +$(call if_changed,rustdoc) > > > > @@ -236,7 +242,10 @@ rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs \ > > +$(call if_changed,rustdoc) > > > > rustdoc-pin_init: private rustdoc_host = yes > > -rustdoc-pin_init: private rustc_target_flags = $(pin_init-flags) \ > > +rustdoc-pin_init: private rustc_target_flags = \ > > + --extern pin_init_internal=$(abspath $(objtree)/$(obj)/$(libpin_init_internal_name)) \ > > + --extern macros=$(abspath $(objtree)/$(obj)/$(libmacros_name)) \ > > + $(call cfgs-to-flags,$(pin_init-cfgs)) \ > > --extern alloc --cfg feature=\"alloc\" > > rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \ > > rustdoc-macros FORCE > > @@ -369,7 +378,9 @@ rusttest: rusttest-macros > > > > rusttest-macros: private rustc_target_flags = --extern proc_macro \ > > --extern macros --extern kernel --extern pin_init \ > > - --extern proc_macro2 --extern quote --extern syn > > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/test/libproc_macro2.rlib) \ > > + --extern quote=$(abspath $(objtree)/$(obj)/test/libquote.rlib) \ > > + --extern syn=$(abspath $(objtree)/$(obj)/test/libsyn.rlib) > > rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro > > rusttest-macros: $(src)/macros/lib.rs \ > > rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE > > @@ -525,48 +536,54 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE > > > > quiet_cmd_rustc_procmacrolibrary = $(RUSTC_OR_CLIPPY_QUIET) PL $@ > > cmd_rustc_procmacrolibrary = \ > > + mkdir -p $(dir $@); \ > > $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \ > > $(filter-out $(skip_flags),$(rust_common_flags) $(rustc_target_flags)) \ > > --emit=dep-info=$(depfile) --emit=link=$@ --crate-type rlib -O \ > > - --out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \ > > --crate-name $(patsubst lib%.rlib,%,$(notdir $@)) $< > > > > -$(obj)/libproc_macro2.rlib: private skip_clippy = 1 > > -$(obj)/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags) > > -$(obj)/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE > > +$(obj)/host/libproc_macro2.rlib: private skip_clippy = 1 > > +$(obj)/host/libproc_macro2.rlib: private rustc_target_flags = $(proc_macro2-flags) > > +$(obj)/host/libproc_macro2.rlib: $(src)/proc-macro2/lib.rs FORCE > > +$(call if_changed_dep,rustc_procmacrolibrary) > > > > -$(obj)/libquote.rlib: private skip_clippy = 1 > > -$(obj)/libquote.rlib: private skip_flags = $(quote-skip_flags) > > -$(obj)/libquote.rlib: private rustc_target_flags = $(quote-flags) > > -$(obj)/libquote.rlib: $(src)/quote/lib.rs $(obj)/libproc_macro2.rlib FORCE > > +$(obj)/host/libquote.rlib: private skip_clippy = 1 > > +$(obj)/host/libquote.rlib: private skip_flags = $(quote-skip_flags) > > +$(obj)/host/libquote.rlib: private rustc_target_flags = $(quote-flags) \ > > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) > > +$(obj)/host/libquote.rlib: $(src)/quote/lib.rs $(obj)/host/libproc_macro2.rlib FORCE > > +$(call if_changed_dep,rustc_procmacrolibrary) > > > > -$(obj)/libsyn.rlib: private skip_clippy = 1 > > -$(obj)/libsyn.rlib: private rustc_target_flags = $(syn-flags) > > -$(obj)/libsyn.rlib: $(src)/syn/lib.rs $(obj)/libquote.rlib FORCE > > +$(obj)/host/libsyn.rlib: private skip_clippy = 1 > > +$(obj)/host/libsyn.rlib: private rustc_target_flags = $(syn-flags) \ > > + --extern proc_macro2=$(abspath $(objtree)/$(obj)/host/libproc_macro2.rlib) \ > > + --extern quote=$(abspath $(objtree)/$(obj)/host/libquote.rlib) > > +$(obj)/host/libsyn.rlib: $(src)/syn/lib.rs $(obj)/host/libquote.rlib FORCE > > +$(call if_changed_dep,rustc_procmacrolibrary) > > > > quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@ > > cmd_rustc_procmacro = \ > > - $(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \ > > + $(RUSTC_OR_CLIPPY) $(rust_common_flags) \ > > -Clinker-flavor=gcc -Clinker=$(HOSTCC) \ > > -Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \ > > --emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \ > > - --crate-type proc-macro -L$(objtree)/$(obj) \ > > + --crate-type proc-macro \ > > + -L$(objtree)/$(obj)/host \ > > --crate-name $(patsubst lib%.$(libmacros_extension),%,$(notdir $@)) \ > > - @$(objtree)/include/generated/rustc_cfg $< > > + @$(objtree)/include/generated/rustc_cfg \ > > + $(rustc_target_flags) \ > > + $< > > > > # Procedural macros can only be used with the `rustc` that compiled it. > > $(obj)/$(libmacros_name): private rustc_target_flags = \ > > --extern proc_macro2 --extern quote --extern syn > > -$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/libproc_macro2.rlib \ > > - $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE > > +$(obj)/$(libmacros_name): $(src)/macros/lib.rs $(obj)/host/libproc_macro2.rlib \ > > + $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE > > +$(call if_changed_dep,rustc_procmacro) > > > > $(obj)/$(libpin_init_internal_name): private rustc_target_flags = $(pin_init_internal-flags) > > $(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs \ > > - $(obj)/libproc_macro2.rlib $(obj)/libquote.rlib $(obj)/libsyn.rlib FORCE > > + $(obj)/host/libproc_macro2.rlib $(obj)/host/libquote.rlib $(obj)/host/libsyn.rlib FORCE > > +$(call if_changed_dep,rustc_procmacro) > > > > # `rustc` requires `-Zunstable-options` to use custom target specifications >
© 2016 - 2026 Red Hat, Inc.