如何在 Cargo.toml 中创建目标特定配置文件?

How to create target specific profile in Cargo.toml?

我想在 cfg(target_os = "ios") 处于活动状态时为我的图书馆指定一个单独的 [profile.release]。我试过这个:

[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.

然而,当我现在尝试构建我的项目/工作区时,出现以下错误:

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.

这是意料之中的,因为根据 documentation 只允许 [profile.<name>]

是否有任何方法可以实现所需的行为?

P.S。如果需要,完整的目标名称将是 aarch64-apple-ios

这是在 issue #4897, Per-target profiles? 中提出的要求,但尚未实施。

同时,您可以使用脚本检查目标并设置 environment variables 来覆盖配置(例如,设置 CARGO_PROFILE_RELEASE_LTOCARGO_PROFILE_RELEASE_OPT_LEVEL),然后用它们调用 Cargo .

这是一个例子,来自users.rust-lang.org - How to modify profile.release only for a target?

在名为 e.g. 的工作区中创建一个二进制文件custom_build。在 custom_build/src/main.rs 中输入:

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);
    }
}

然后你可以创建一个build.rs文件来手动防止运行 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")
    }
}