Indeed, there is no clean / direct way to achieve this. There is a hacky-ish way though: do not directly call cargo build
, but call something that will perform some platform detection setting to only then tweak profile.release
.
Let's say cargo smart
.
cargo smart
First, make sure to add the following files:
.
├── .cargo // <--
│ └── config // <--
├── Cargo.toml
├── build.rs // <-- (Optional)
├── smart // <--
│ ├── Cargo.toml // <--
│ └── main.rs // <--
└── src
└── lib.rs
...
-
.cargo/config
[alias]
smart = ["r", "-q", "--manifest-path", "smart/Cargo.toml", "--"]
-
smart/Cargo.toml
[package]
name = "smart"
version = "0.0.0"
edition = "2018"
[[bin]]
name = "smart"
path = "main.rs"
[workspace]
-
smart/main.rs
use ::std::{env, ops::Not, process};
fn main ()
{
let mut cmd = process::Command::new(::std::env::var("CARGO").unwrap());
cmd.env("CARGO_SMART", "1"); // Optional, if used with the `build.rs`
let ref args = env::args().skip(1).collect::<Vec<_>>();
// dbg!(args); cmd.arg("-vv"); /* Uncomment when debugging this hack */
cmd.args(args);
// if args...contains... "--target" "...windows..." ...
if cfg!(windows) {
// See https://doc.rust-lang.org/cargo/reference/environment-variables.html#configuration-environment-variables
cmd.env("CARGO_PROFILE_RELEASE_OPT_LEVEL", "0");
}
if cmd.status().ok().map_or(false, |it| it.success()).not() {
process::exit(-1);
}
}
-
build.rs
(Optional, to make sure we don't forget to call cargo
using smart
)
use ::std::{env, ops::Not};
fn main ()
{
if env::var("CARGO_SMART").ok().map_or(false, |s| s == "1").not() {
panic!("Do not run `cargo ...`, run `cargo smart ...` instead")
}
}
With these changes, cargo smart <usual command>
ought to work, such as cargo smart build --release
Feel free to rename smart
to something else, and of course to tweak smart/main.rs
to correctly handle things like the windows
case if cross-compiling (since cfg!(windows)
on a build script will only be enabled when running cargo
from a Windows environment, not when compiling to one).