Cross-compilation with proc-macros: how do you handle .cargo/config.toml without breaking the build?

Hi colleagues,

Do you also run into hacks when cross-compiling? For example, if a project has a dependency on proc-macros, do you end up with at least two separate .cargo/config.toml files - one for development and one for release?

The issue is that you can't build a static binary for any target from an x86_64 host when your config includes something like this:

[target.x86_64-unknown-linux-gnu]
linker = "compilers/cc-x86_64-linux-gnu"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

Because proc-macros must be compiled for the host target, and this setup forces everything - including proc-macros - to be built with the overridden linker, which breaks the build.

For example, so far I’ve found this workaround:

If the build machine is linux-gnu, then use config.linux-musl.toml.
If the build machine is linux-musl, then use config.linux-gnu.toml.

config.linux-gnu.toml

[target.aarch64-unknown-linux-gnu]
linker = "compilers/cc-aarch64-linux-gnu"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

[target.riscv64gc-unknown-linux-gnu]
linker = "compilers/cc-riscv64-linux-gnu"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

[target.x86_64-unknown-linux-gnu]
linker = "compilers/cc-x86_64-linux-gnu"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

config.linux-musl.toml

[target.aarch64-unknown-linux-musl]
linker = "compilers/cc-aarch64-linux-musl"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

[target.riscv64gc-unknown-linux-musl]
linker = "compilers/cc-riscv64-linux-musl"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]

[target.x86_64-unknown-linux-musl]
linker = "compilers/cc-x86_64-linux-musl"
rustflags = ["-C", "link-self-contained=no", "-C", "target-feature=+crt-static"]
1 Like

And for local development and testing, I use config.toml without overriding [target.X] - and then everything works.
It’s both funny and a bit sad at the same time.