Linux kbuild/kconfig development
 help / color / mirror / Atom feed
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

      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