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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.