cargo icon indicating copy to clipboard operation
cargo copied to clipboard

Tracking Issue for profile-rustflags

Open ehuss opened this issue 2 years ago • 12 comments

Summary

Original issue: #7878 Implementation: #10217 Documentation: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option

The profile-rustflags feature allows setting RUSTFLAGS per-profile.

Unresolved Issues

  • [ ] How should things interact with rustdoc? If there is a flag that is required to correctly build a project, then cargo test may fail if they aren't passed to rustdoc. However, rustdoc doesn't accept all of rustc's flags. Adding a rustdocflags option seems to be adding more unwanted complexity, though.
  • [ ] This introduces potential backwards-compatibility hazards. For example, when Cargo adds new features or changes the way it invokes rustc, that can interfere with pre-existing flags. Is documenting this sufficient?
  • [ ] What should the behavior be with build scripts and proc-macros? Those have historically been a pain point with rustflags. Perhaps there should be a default build-override.rustflags = [].
  • [ ] Profile rustflags are not considered as part of TargetInfo, which impacts feature resolution and other things.

Future Extensions

No response

About tracking issues

Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

ehuss avatar Jan 07 '22 19:01 ehuss

I see something like this as necessary for the usability of RFC 3028 (artifact dependencies): https://github.com/rust-lang/cargo/issues/9096 . Historically Cargo has not supported passing arbitrary flags in profile overrides because many of them made no sense to pass to a dependency (e.g. -C linker). However, with binary artifacts, now literally all rustc flags become something that users will have valid reasons to want to specify. Currently this leads to lots of pain and workarounds with trying to use binary dependencies, either by hacking things up with Cargo config files (which don't work in all cases) or build scripts (which don't support all flags) or environment variables (which are difficult to set in all circumstances).

That doesn't mean that this feature is the only way to satisfy this need, but I think anything that does satisfy this need would have to be functionally equivalent to profile-rustflags.

bstrie avatar Apr 29 '22 14:04 bstrie

cargo-features = ["per-package-target", "profile-rustflags"] don't work together. By this I mean the target does not get applied when profile-rustflags get used.

cargo-features = ["per-package-target", "profile-rustflags"]

[package]
name = "perf_kernel"
version = "0.1.0"
authors = ["Luis Hebendanz <[email protected]>"]
edition = "2021"
forced-target = "x86_64-unknown-none"

[profile.dev]
rustflags = [ "-C", "link-args=--image-base=0x200000" ]

Will fail with gcc: error: unrecognized command-line option '--image-base=0x200000' even though target defines ld.lld as linker

Qubasa avatar Sep 29 '22 23:09 Qubasa

I can not get this to work with a no_std crate on Windows with the current nightly. Steps to reproduce the linker issue:

  1. Create a new binary project.
  2. Cargo.toml:
    [... default content ...]
    
    [profile.release]
    panic = "abort"
    
  3. src/main.rs:
    #![no_main]
    #![no_std]
    
    #[panic_handler]
    fn rust_begin_unwind(_: &core::panic::PanicInfo) -> ! { loop {} }
    
    #[no_mangle]
    fn WinMainCRTStartup() -> u32 { 0 }
    
  4. .cargo/config.toml:
    [target.'cfg(target_env = "msvc")']
    rustflags = [ "-C", "link-args=/Debug:None /SubSystem:Windows" ]
    
  5. Compile with cargo build --release --target x86_64-pc-windows-msvc -Z build-std=core -> it succeeds.
  6. Delete .cargo/config.toml.
  7. Cargo.toml:
    cargo-features = [ "profile-rustflags" ]
    
    [... previous content ...]
    
    rustflags = [ "-C", "link-args=/Debug:None /SubSystem:Windows" ]
    
  8. Compile with cargo build --release --target x86_64-pc-windows-msvc -Z build-std=core -> it succeeds.
  9. Delete the target build artifact directory to enforce a complete recompilation.
  10. Compile with cargo build --release --target x86_64-pc-windows-msvc -Z build-std=core -> it fails:
    Compiling compiler_builtins v0.1.85
    Compiling rustc-std-workspace-core v1.99.0
    
    error: linking with `link.exe` failed: exit code: 1120
    [... linker command arguments ...]
    note: msvcrt.lib(exe_winmain.obj) : error LNK2019: unresolved external symbol WinMain referenced in function "int __cdecl __scrt_common_main_seh(void)" (?__scrt_common_main_seh@@YAHXZ)
    build_script_build-[RandomHash].exe : fatal error LNK1120: 1 unresolved externals
    

It seems like it tries to link the things that should be excluded via no_std, like msvcrt and WinMain. By the way, is it possible to use something like cfg(target_env = "msvc") with profile-rustflags?

MauriceKayser avatar Jan 28 '23 20:01 MauriceKayser

As mentioned in the unresolved section, profile rustflags get applied to build scripts. You can override that with:

[profile.dev.build-override]
rustflags = []

Also, I might suggest using the #[windows_subsystem] attribute instead of setting it manually.

Conditional settings are not supported in profiles, you'll need to use separate profiles.

In the future, please file a new issue if you have a question or problem. See the "About tracking issues" section above.

ehuss avatar Jan 28 '23 23:01 ehuss

Sorry, I will read more carefully next time and create a separate issue instead. I did not realize that my example contained a build script, thanks for the hint! The #![windows_subsystem = "windows"] seems to be ignored, if applied to the example - it will look for mainCRTStartup, the console subsystem main function, instead of WinMainCRTStartup, the windows subsystem main function.

MauriceKayser avatar Jan 29 '23 11:01 MauriceKayser

I am getting an issue where workspace rustflags don't work for sub-crates.

For example, - in the workspace Cargo.toml:

# TODO: Remove when WebGPU is no longer an unstable
[target.'cfg(target_arch="wasm32")'.profile.dev]
rustflags = ["--cfg", "web_sys_unstable_apis"]

Subcrates won't compile that depend on this:

error[E0599]: no method named `gpu` found for struct `WorkerNavigator` in the current scope
   --> /Users/simbleau/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.17.2/src/backend/web.rs:950:18
    |
947 | /             global
948 | |                 .unchecked_into::<web_sys::WorkerGlobalScope>()
949 | |                 .navigator()
950 | |                 .gpu()
    | |                 -^^^ method not found in `WorkerNavigator`
    | |_________________|

cargo build --verbose confirms the flags are not passed down correctly.

Related: https://github.com/rust-lang/cargo/issues/4897

simbleau avatar Dec 05 '23 03:12 simbleau

# TODO: Remove when WebGPU is no longer an unstable
[target.'cfg(target_arch="wasm32")'.profile.dev]
rustflags = ["--cfg", "web_sys_unstable_apis"]

This is not a valid key in Cargo.toml. You might get a warning like

warning: /path/to/pkg/Cargo.toml: unused manifest key: target.cfg(target_arch="wasm32").profile

weihanglo avatar Dec 05 '23 04:12 weihanglo

# TODO: Remove when WebGPU is no longer an unstable
[target.'cfg(target_arch="wasm32")'.profile.dev]
rustflags = ["--cfg", "web_sys_unstable_apis"]

This is not a valid key in Cargo.toml. You might get a warning like

warning: /path/to/pkg/Cargo.toml: unused manifest key: target.cfg(target_arch="wasm32").profile

Confused what you mean by it's not a key.

It's documented here: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option

simbleau avatar Dec 05 '23 05:12 simbleau

Can we also have per-profile environment variables, for CFLAGS/CXXFLAGS? Before I make a corresponding issue, is this idea going to fly at all?

Rationale: RUSTFLAGS alone is not enough to have, for example, cross-language LTO on the release profile.

intelfx avatar Mar 20 '24 13:03 intelfx

Depends on how you use profile. For now we can leverage --config <alternative-config.toml> without waiting for such feature being implemented.

BTW I feel like this has been brought up, but couldn't find an issue of it.

weihanglo avatar Mar 20 '24 15:03 weihanglo

Depends on how you use profile. For now we can leverage --config <alternative-config.toml> without waiting for such feature being implemented.

BTW I feel like this has been brought up, but couldn't find an issue of it.

@weihanglo this sounds like a great solution, I just cant get it to work reasonably

let's say I have a default configuration that is used during development and in the dev profile. This should be a default and work without an extra command line which could be forgotten, because I want to put things like sanitizer support in there.

So this is my .cargo/config.toml:

[build]
target = "x86_64-unknown-linux-gnu"
rustflags = ["-Z", "sanitizer=address"]

[env]
BUILD_PROFILE = "debug"

Now in my build system I want to build the release build with a different configuration and the stable compiler. I create a new .cargo/config-release.toml with the following content:

[env]
BUILD_PROFILE = "release"

And use the command cargo +stable --config .cargo/config-release.toml to build it. Now it will still fall back to the .cargo/config.toml which will not work because there is no sanitizer in the stable compiler. Only once I delete the .cargo/config.toml, it will start using the config-release.toml.

How would you approach such a use case? I have a mixed C and Rust application, that needs different rustflags and environment variables for the debug and release builds.

I am really struggling with getting that right. Another really unfortunate thing with defining the rustflags in the config.toml, everytime I set the RUSTFLAGS env variable all the entries in the config.toml are silently thrown away. I just realized today, that I am setting RUSTFLAGS="${RUSTFLAGS} -D warnings" in the CI and by doing this am disabling all the flags I set in the config.

kamulos avatar Apr 09 '24 13:04 kamulos

@kamulos if config-include supports optional config.toml, that could be an approach to manage multiple config files. See https://github.com/rust-lang/cargo/issues/7723.

weihanglo avatar Apr 26 '24 00:04 weihanglo