I would like to specify a separate [profile.release]
for my library when cfg(target_os = "ios")
is active. I tried this:
[profile.'cfg(not(target_os = "ios"))'.release]
lto = true # Use link-time optimization.
[profile.'cfg(target_os = "ios")'.release]
lto = true # Use link-time optimization.
opt-level = "z" # Mobile devices are fast enough. Optimize for size instead.
strip = "symbols" # Not relevant for windows.
However when I now try to build my project / workspace I get the following error:
error: failed to parse manifest at `/path/to/Cargo.toml`
Caused by:
invalid character `(` in profile name `cfg(not(target_os = "ios"))`
Allowed characters are letters, numbers, underscore, and hyphen.
which is to be expected, because according to the documentation only [profile.<name>]
is allowed.
Is there any method to achieve the desired behaviour?
P.S. The full target name would be aarch64-apple-ios
in case this is needed.
This was requested in issue #4897, Per-target profiles?, but not yet implemented.
In the meantime, you can use a script that checks the target and set environment variables to override config (for example, set CARGO_PROFILE_RELEASE_LTO
or CARGO_PROFILE_RELEASE_OPT_LEVEL
) then invokes Cargo with them.
Here is an example, from users.rust-lang.org - How to modify profile.release only for a target?
Create a binary in the workspace named e.g. custom_build
. In custom_build/src/main.rs
put:
use std::env;
use std::process::Command;
fn main() {
let mut cargo = Command::new(env::var_os("CARGO").unwrap());
cargo.env("CARGO_CUSTOM_BUILD", "1"); // So we can disallow regular builds, to prevent mistakes
cargo.args(env::args_os().skip(1));
// You can determine the target OS by various way, but providing it manually to the build script is the simplest.
let for_ios = env::var("build_ios").is_ok();
if for_ios {
cargo.env("CARGO_PROFILE_RELEASE_LTO", "true");
cargo.env("CARGO_PROFILE_RELEASE_OPT_LEVEL", "z");
cargo.env("CARGO_PROFILE_RELEASE_STRIP", "symbols");
} else {
cargo.env("CARGO_PROFILE_RELEASE_LTO", "true");
}
let cargo_succeeded = cargo.status().ok().map_or(false, |status| status.success());
if !cargo_succeeded {
std::process::exit(1);
}
}
Then you can create a build.rs file to prevent manually running cargo
:
use std::env;
fn main() {
if !env::var("CARGO_CUSTOM_BUILD").ok().map_or(false, |s| s == "1") {
panic!("Do not run `cargo ...`, run `cargo custom_build ...` instead")
}
}