Excuse me for the double mail, I was not yet subscribing to the mailing list, so my mail was hidden.
Hi everyone,
I've been investigating the issue when enabling ccache for kernel builds that involve Rust.
First of all, as documented in the ccache issue tracker [1], ccache is not directly compatible with Rust.
Therefore the current goal is to keep ccache enabled for the C portions of the kernel while bypassing it for Rust.
While an alternative like sccache [2], compatible with both C and Rust exists, you will see below that the underlying issue is the same, so just replacing ccache by sccache will change nothing here.
The issue (commit 235e6d49e5888ad04416219e10b6df91a738661a + this patch):
When ccache is enabled, ${CC} to ${CCACHE}{CC}, ex: gcc to ccache gcc
Then, when compiling the kernel, scripts/Makefile.host will give it to rustc with -Clinker=$(HOSTCC) [3], but the shell expands $(HOSTCC) to two words, therefore rustc takes gcc as another parameters, and it errors out.
I attempted to resolve it by modifying the incriminated Makefile in the following ways:
Trial 1: Quoting HOSTCC in Kernel Makefile
Modify scripts/Makefile.host to wrap HOSTCC in quotes to ensure it is passed as a single string parameter:
Replace -Clinker=$(HOSTCC) to -Clinker='$(HOSTCC)'
Result: Failure, rustc looks for a binary path literally named ccache gcc, which does not exist, indeed, -Clinker argument value is treated by rustc as a real path, and not a command [4].
Trial 2: Splitting HOSTCC into Linker and Pre-link Args
Modified scripts/Makefile.host to force the linker to the first word of HOSTCC and pass subsequent words to -Zpre-link-args:
Replace -Clinker=$(HOSTCC) by -Clinker=$(firstword $(HOSTCC)) -Zpre-link-args='$(wordlist 2,$(words $(HOSTCC)),$(HOSTCC))'
Result: Failure, rustc executes the command as: "ccache" "-m64" "gcc" ....
This is invalid because in rustc, the target-specific pre-link arguments (from compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs) are added before our custom args, placing -m64 before the gcc executable [5] .
Proposed Solutions
1. Kernel + Rust Patch (A): Patch the kernel Makefile (like the Trial 1) and patch rustc to accept a command string (with arguments) for -Clinker instead of a strict Path.
2. Kernel + Rust Patch (B): Patch the kernel Makefile (like the Trial 2) and patch rustc to use post_link_args instead of pre_link_args for target-specific values, ensuring the executable stays at the end of the command.
3. Shell Wrappers: Implement shell wrappers for CC, CXX, etc. This would allow rustc to call a single wrapper script, hiding ccache from it.
4. Kernel only: Patch the kernel Makefile to filter out ccache from CC (works in practice but not generic for a possible other wrapper in the future).
5. Leave as-is: disable ccache when rust is enabled .
Risks and Considerations - Upstreamability: Patching rust and the kernel at the same time could take time. - Maintainability: While the shell wrapper approach is more flexible and solves the issue for other tools with similar limitations, it might make debugging in Yocto more difficult and requires significant changes.
I'm leaning towards the 1st or the 3rd approach, but I'd appreciate the maintainers' thoughts on which path fits the OE architecture best.
[1] https://github.com/ccache/ccache/issues/364
[2] https://github.com/mozilla/sccache
[3] https://git.yoctoproject.org/linux-yocto/tree/scripts/Makefile.host?h=v6.18.1#n94
Best regards,
Alban Moizan