From: Nicolas Schier <nsc@kernel.org>
To: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
Cc: "Mohamad Alsadhan" <mo@sdhn.cc>,
"Nathan Chancellor" <nathan@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Yoann Congal" <yoann.congal@smile.fr>,
linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v8] kbuild: host: use single executable for rustc -C linker
Date: Wed, 17 Jun 2026 21:40:20 +0200 [thread overview]
Message-ID: <ajL4JBIUVHdYISsX@levanger> (raw)
In-Reply-To: <CANiq72=p+NG_JRuDBJPPtN2QkmFGJ0BuFNMWnQ=Vg+v8x9+0yg@mail.gmail.com>
On Wed, Jun 10, 2026 at 03:18:54PM +0200, Miguel Ojeda wrote:
> On Sat, May 9, 2026 at 12:20 PM Mohamad Alsadhan <mo@sdhn.cc> wrote:
> >
> > rustc's -C linker= option expects a single executable path. When
> > HOSTCC contains a wrapper (e.g. "ccache gcc"), passing
> > `-Clinker=$(HOSTCC)` results in the shell splitting the value into
> > multiple words, and rustc interprets the additional word as an
> > input filename:
>
> I have been taking a look at this, and considered applying it since
> Kbuild is OK with it (thanks a lot for all the work during the
> different versions), but I am not sure if the following bits are all
> intended:
>
> - Shouldn't `HOSTRUSTC_LD` be documented in `Documentation/kbuild/kbuild.rst`?
Good catch, thanks. Yes.
> - Why do we do both `clean-files` and `CLEAN_FILES`?
>
> + In fact, should we do it on `clean` or `mrproper`? Nicolas
> originally suggested `MRPROPER_FILES`, but this is on `CLEAN_FILES`.
> But more on that below, since I guess it depends on how we treat
> out-of-tree modules...
>
> - Was this tested with an out-of-tree module? I am asking because:
>
> + It does create an unused wrapper in a `scripts/` folder in the
> out-of-tree module directory (i.e. the one used is the in-tree one) --
> is that intended?
>
> + If we remove the wrapper during `clean` as the patch currently
> does, then it means we cannot build Rust host programs in an
> out-of-tree module (because it uses the in-tree one). Should it be in
> `mrproper` instead, or should we generate a per-out-of-tree-module
> one?
>
> While I think the kernel generally expects that the same
> toolchain is used for both the main build and out-of-tree modules (it
> may happen to work otherwise, but as a policy it is not supposed to be
> supported, or at least that is what I recall I was told), I am not
> sure if it applies to host programs. I guess someone may want to use a
> different host toolchain vs. the one used to build the main kernel,
> and I guess things would generally work.
>
> - The `filechk` could fail if we use Rust host programs in more
> folders later on, i.e. if two submakes run it at the same time, and
> one at the end deletes the (shared) temporary, then the other will
> fail if it was in the middle of updating it.
Uh, thanks for all those good questions. I didn't even think about rust
host progs being built in out-of-tree module trees. And the concurrent
filechk calls are really no good.
Iff HOSTRUSTC_LD shall be kept stable for external kernel modules, a
semi-simple solution might be to move rustc-wrapper rules to
scripts/basic/ and use cmd_* instead of filechk. Regarding the
queations above, this would mean:
* ${KBUILD_OUTPUT}/scripts/basic/rustc-wrapper will be purged during
'mrproper'
* It will be generated only once, no matter who many in-tree folder
use it.
Only roughly tested:
diff --git a/Makefile b/Makefile
index 8235b6a9b3cc..e3a82c344e69 100644
--- a/Makefile
+++ b/Makefile
@@ -661,6 +661,7 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \
PHONY += scripts_basic
scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS)
scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS)
+scripts_basic: HOSTRUSTC_LD := $(HOSTRUSTC_LD)
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
diff --git a/rust/Makefile b/rust/Makefile
index 2fbdebb93bf2..d02002c50432 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -593,7 +593,7 @@ quiet_cmd_rustc_procmacro = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET))
cmd_rustc_procmacro = \
$(rustc_target_envs) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) $(rust_common_flags) $(rustc_target_flags) \
- -Clinker-flavor=gcc -Clinker=$(HOSTCC) \
+ -Clinker-flavor=gcc -Clinker=$(objtree)/scripts/basic/rustc-wrapper \
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
--crate-type proc-macro -L$(objtree)/$(obj) \
@@ -610,12 +610,14 @@ $(obj)/$(libzerocopy_derive_name): $(src)/zerocopy-derive/lib.rs $(obj)/libproc_
$(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)/libquote.rlib $(obj)/libsyn.rlib \
+ scripts/basic/rustc-wrapper 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)/libproc_macro2.rlib $(obj)/libquote.rlib $(obj)/libsyn.rlib \
+ scripts/basic/rustc-wrapper FORCE
+$(call if_changed_dep,rustc_procmacro)
# `rustc` requires `-Zunstable-options` to use custom target specifications
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index c1dedf646a39..0be405efa38a 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -91,7 +91,8 @@ hostcxx_flags = -Wp,-MMD,$(depfile) \
# current working directory, which may be not accessible in the out-of-tree
# modules case.
hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \
- -Clinker-flavor=gcc -Clinker=$(HOSTCC) \
+ -Clinker-flavor=gcc \
+ -Clinker=$(objtree)/scripts/basic/rustc-wrapper \
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
$(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \
$(HOSTRUSTFLAGS_$(target-stem))
@@ -153,7 +154,7 @@ $(host-cxxobjs): $(obj)/%.o: $(obj)/%.cc FORCE
quiet_cmd_host-rust = HOSTRUSTC $@
cmd_host-rust = \
$(HOSTRUSTC) $(hostrust_flags) --emit=link=$@ $<
-$(host-rust): $(obj)/%: $(src)/%.rs FORCE
+$(host-rust): $(obj)/%: $(src)/%.rs scripts/basic/rustc-wrapper FORCE
+$(call if_changed_dep,host-rust)
targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
index 07c195f605a1..d314c04fe131 100644
--- a/scripts/basic/.gitignore
+++ b/scripts/basic/.gitignore
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
/fixdep
/randstruct.seed
+/rustc-wrapper
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index fb8e2c38fbc7..0aec1adc199b 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -19,3 +19,25 @@ always-$(CONFIG_RANDSTRUCT) += randstruct.seed
$(obj)/../../include/generated/integer-wrap.h: $(srctree)/scripts/integer-wrap-ignore.scl FORCE
$(call if_changed,touch)
always-$(CONFIG_UBSAN_INTEGER_WRAP) += ../../include/generated/integer-wrap.h
+
+# rustc-wrapper: rustc's `-Clinker=` expects a single executable path, not a
+# command line. `HOSTCC` may be a multi-word command when wrapped (e.g.
+# "ccache gcc"), which would otherwise be split by the shell and mis-parsed by
+# rustc. To work around this, we generate a script that invokes `HOSTRUSTC_LD`
+# with the linker arguments appended so such commands can be used safely.
+#
+# Set `HOSTRUSTC_LD` for a different rustc linker command than `HOSTCC`
+HOSTRUSTC_LD ?= $(HOSTCC)
+
+quiet_cmd_rustc-wrapper = GEN $@
+ cmd_rustc-wrapper = \
+ printf '%s\n' '\#!/bin/sh' '$(addsuffix $(space),$(HOSTRUSTC_LD))"$$@"' >$@; \
+ chmod a+x $@
+
+$(obj)/rustc-wrapper: FORCE
+ $(call if_changed,rustc-wrapper)
+
+always-$(CONFIG_RUST) += rustc-wrapper
+ifneq ($(CONFIG_RUST),)
+targets += rustc-wrapper
+endif
--
Nicolas
prev parent reply other threads:[~2026-06-17 19:41 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-09 10:19 [PATCH v8] kbuild: host: use single executable for rustc -C linker Mohamad Alsadhan
2026-05-11 6:59 ` Nathan Chancellor
2026-05-11 11:18 ` Nicolas Schier
2026-05-12 17:32 ` Yoann Congal
2026-06-10 13:18 ` Miguel Ojeda
2026-06-17 19:40 ` Nicolas Schier [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ajL4JBIUVHdYISsX@levanger \
--to=nsc@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=miguel.ojeda.sandonis@gmail.com \
--cc=mo@sdhn.cc \
--cc=nathan@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=yoann.congal@smile.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox