Setting RUSTFLAGS globally?

Build Configuration - The Rust Performance Book

RUSTFLAGS="-C target-cpu=native" cargo build --release

works fine. But I am unable to set target-cpu=native globally in a configuration file. For example I tried a lot of variants like

$ cat ~/.cargo/config.toml 
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold", "-C", "target-cpu=native"]
#[build]
#rustflags = ["-C", "target-cpu=native"]

#[build]
# Use a single absolute path for all build artifacts
#target-dir = "/home/stefan/.cargo/target_shared"

[profile.dev]
# One debuginfo file per dependency, to reduce file size of tests/examples.
# Note that this value is not supported on Windows.
# See https://doc.rust-lang.org/cargo/reference/profiles.html#split-debuginfo
#split-debuginfo="unpacked"

What makes you think it has not been set?

Cargo has a bunch of rules for which of the many ways of setting RUSTFLAGS take precedence, and which are merged and which are replacing.

The global config will work if there are no per-target config sections. The per-target sections will work if there are no env vars replacing them. Various config files will merge settings when you use arrays, but won't when you set a single string.

1 Like

As we can learn from the performance book:

stefan@hx90 ~ $ rustc --print cfg
debug_assertions
panic="unwind"
target_abi=""
target_arch="x86_64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_feature="fxsr"
target_feature="sse"
target_feature="sse2"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="64"
target_has_atomic="8"
target_has_atomic="ptr"
target_os="linux"
target_pointer_width="64"
target_vendor="unknown"
unix
stefan@hx90 ~ $ rustc --print cfg -C target-cpu=native
debug_assertions
panic="unwind"
target_abi=""
target_arch="x86_64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_feature="adx"
target_feature="aes"
target_feature="avx"
target_feature="avx2"
target_feature="bmi1"
target_feature="bmi2"
target_feature="cmpxchg16b"
target_feature="f16c"
target_feature="fma"
target_feature="fxsr"
target_feature="lzcnt"
target_feature="movbe"
target_feature="pclmulqdq"
target_feature="popcnt"
target_feature="rdrand"
target_feature="rdseed"
target_feature="sha"
target_feature="sse"
target_feature="sse2"
target_feature="sse3"
target_feature="sse4.1"
target_feature="sse4.2"
target_feature="sse4a"
target_feature="ssse3"
target_feature="vaes"
target_feature="vpclmulqdq"
target_feature="xsave"
target_feature="xsavec"
target_feature="xsaveopt"
target_feature="xsaves"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="64"
target_has_atomic="8"
target_has_atomic="ptr"
target_os="linux"
target_pointer_width="64"
target_vendor="unknown"
unix
stefan@hx90 ~ $ 

Alternative test:

stefan@hx90 ~ $ cd /tmp/
stefan@hx90 /tmp $ cargo new flags
    Creating binary (application) `flags` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
stefan@hx90 /tmp $ cd flags/
stefan@hx90 /tmp/flags $ RUSTFLAGS="-C target-cpu=native" cargo build --release
   Compiling flags v0.1.0 (/tmp/flags)
    Finished `release` profile [optimized] target(s) in 0.28s
stefan@hx90 /tmp/flags $ ls -l target/release/flags
-rwxr-xr-x 2 stefan stefan 450640 Feb  5 09:55 target/release/flags
stefan@hx90 /tmp/flags $ cargo build --release
   Compiling flags v0.1.0 (/tmp/flags)
    Finished `release` profile [optimized] target(s) in 0.10s
stefan@hx90 /tmp/flags $ ls -l target/release/flags
-rwxr-xr-x 2 stefan stefan 484296 Feb  5 09:56 target/release/flags
stefan@hx90 /tmp/flags $ 

As you can see, target-cpu=native results in a smaller binary and I assume is some cases in faster code.

This will not use Cargo config. You might want cargo rustc --print cfg instead.

stefan@hx90 /tmp/flags $ cargo rustc --print cfg
error: the `print` flag is unstable, and only available on the nightly channel of Cargo, but this is the `stable` channel
See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels.
See https://github.com/rust-lang/cargo/issues/9357 for more information about the `print` flag.

But my test with cargo build --release comparing the executable sizes confirms that the native flag is not picked up.

Are you positive, that you un-commented the #[build] section as well?

Are you sure that (file size) is not from mold? (env replaces rather than supplements the config.)

Can use sudo forkstat -e exec to watch what processes get started.

Oh, that is a good hint.

In any case, it would be good if some experts could update the section Build Configuration - The Rust Performance Book as the note

If you are unsure whether -C target-cpu=native is working optimally, compare the output of rustc --print cfg and rustc --print cfg -C target-cpu=native to see if the CPU features are being detected correctly in the latter case.

might be incorrect as noted by Cerber-Ursi.

And the note

If not, you can use -C target-feature to target specific features.

is not very concrete, I have no idea how to do that.

I was even not sure if in ~/.cargo/config.toml

is should be

rustflags = ["-C", "link-arg=-fuse-ld=mold", "-C", "target-cpu=native"]

#or

rustflags = ["-C", "link-arg=-fuse-ld=mold", "target-cpu=native"]

#or 

rustflags = ["-C", "link-arg=-fuse-ld=mold", "-C target-cpu=native"]

But I tested different combinations, and will continue testing soon.

The different file sizes resulted indeed from use of mold linker.

But I have still no idea if target-cpu=native is active or not. The --verboseflag does not really help.

cargo build --verbose --release
       Dirty flags v0.1.0 (/tmp/flags): the file `src/main.rs` has changed (1770293433.791905572s, 2m 27s after last build at 1770293286.520223102s)
   Compiling flags v0.1.0 (/tmp/flags)
     Running `rustc --crate-name flags --edition=2024 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=230 --crate-type bin --emit=dep-info,link -C opt-level=3 -C embed-bitcode=no --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=b7d8b7787fd4e866 -C extra-filename=-c794e5da97ae3940 --out-dir /tmp/flags/target/release/deps -C strip=debuginfo -L dependency=/tmp/flags/target/release/deps`
    Finished `release` profile [optimized] target(s) in 0.07s

OK, I finally got a working solution:

$ cat ~/.cargo/config.toml 

[build]
rustflags = ["-C", "target-cpu=native"]

$ cargo build --release -v
       Dirty flags v0.1.0 (/tmp/flags): the file `src/main.rs` has changed (1770294539.084949853s, 23m 31s after last build at 1770293128.856573350s)
   Compiling flags v0.1.0 (/tmp/flags)
     Running `rustc --crate-name flags --edition=2024 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=230 --crate-type bin --emit=dep-info,link -C opt-level=3 -C embed-bitcode=no --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=b7d8b7787fd4e866 -C extra-filename=-8e851e1211211a49 --out-dir /tmp/flags/target/release/deps -C strip=debuginfo -L dependency=/tmp/flags/target/release/deps
 -C target-cpu=native`

confirming that target-cpu=native is actually enabled.

:slight_smile:

And now it work with the mold linker as well:

cat ~/.cargo/config.toml 


[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = [
    "-C", "link-arg=-fuse-ld=mold", 
    "-C", "target-cpu=native"
]


$ cargo build --release -v
        ... -C link-arg=-fuse-ld=mold -C target-cpu=native`

The main reason for my confusion was that in Rust performance book

If you are unsure whether -C target-cpu=native is working optimally, compare the output of rustc --print cfg and

is not correct and helpful, as noted by Cerber-Ursi