There are four mutually exclusive sources of extra flags. They are checked in order, with the first one being used:
- CARGO_ENCODED_RUSTFLAGS environment variable.
- RUSTFLAGS environment variable.
- All matching target..rustflags and target..rustflags config entries joined together.
- build.rustflags config value
This mutual exclusivity is quite annoying, and could be even problematic.
Suppose you have something like this in your global configuration:
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]
rustflags = ["-Z", "gcc-ld=lld"]
Now suppose you need to enable a cfg, let's say
tokio_unstable in one or more of your crates.
RUSTFLAGS does enable the cfg, but your global linker settings are ignored!
- Using crate-local/workspace-local
build.rustflags, as often suggested, doesn't work at all.
- You need to add all your global per-target rustflags in your crate-local/workspace-local config with cfg appended.
Now, suppose you want to set
-Z threads=n globally... well, it's not really global anymore, unless you use a higher-priority rustflags-setting method which will override your other settings!
Am I missing anything?
Alternatively, useful rustflags should be adopted "natively" by Cargo, as either cargo/config or Cargo.toml options.
For example, there's already
linker setting, so you don't need rustflags for it:
linker = "lld"
Sure. But that's not a generic solution.
Right now, it's not rare to find suggestions of e.g. enabling a cfg via adding the flags in the build section of
.cargo/config. Some even seem to think that checking that file in is enough, and things should just work for others, being totally oblivious to the mutual exclusivity problem.
I just find it weird that there is no way to reliably locally append
rustflags without having to check global config (and the environment) first, and that global config is not a base that can be appended to. Unless using
build.rs is considered "the right solution" here!
linker = "lld" will make rustc directly invoke lld doesn't it? That only works on msvc windows, wasm32-unknown-unknown, wasm32-wasi and baremetal systems. On unix you have to use a linker driver like gcc or clang. You can then tell this linker driver to use lld as actual linker using
Cargo on Unix could be smarter about this and use a linker driver if necessary, instead of exposing inconsistent platform-specific behavior.
For example, you can set
debug = true in Cargo.toml, and not care if that's
/Zi, or whether it needs dSYM paths or pdb formats or whatnot. You specify what you want, and in that case Rust/Cargo is smart enough to abstract the underlying details from you. You don't even need to know if Cargo is doing it, or is that a rustc option, or some gcc thing. It just works. IMHO linkers should work like that. I say
linker = "mold", and Cargo makes it work.
It would be good to have more of the flags exposed through native cargo configs. But there'll always be flags that have been added to rustc and haven't yet been exposed by cargo that I really think some way to separate the "user's flags" from the "project's flags" and combine them is necessary. I set some unstable flags like
-Zrandomize-layout globally that I doubt will be exposed by cargo anytime soon.
Maybe there's a need for
EXTRA_RUSTFLAGS that adds to the others?
EXTRA_CFLAGS is a common Makefile idiom.)