英文:
How to build two versions of an application, using features, with a single `cargo build` command
问题
I need to build a CLI application that comes in two flavours. Most of the code is common to both, excepting some low-level layer.
So far, I've been able to specify the creation of multiple binaries using the [[bin]]
notation, and using ad-hoc features. However, that requires to invoke cargo build
twice, once with --features="flavour1"
and once with --features="flavour2"
.
- is there any way to have Cargo to build these two flavours with a single command?
- is this an anti-pattern? I appreciate features are additive, and it is recommended to avoid mutually exclusive features, but I couldn't find another way to do this.
To illustrate the question, here follows a sample Cargo.toml
and the corresponding src/main.rs
file:
Cargo.toml
[package]
name = "sample-flavours"
version = "0.1.0"
edition = "2021"
[features]
flavour1=[]
flavour2=[]
[[bin]]
name="bin-flavour1"
path="src/main.rs"
required-features=["flavour1"]
[[bin]]
name="bin-flavour2"
path="src/main.rs"
required-features=["flavour2"]
src/main.rs
#[cfg(feature="flavour1")]
fn sublayer() -> &'static str {
"flavour 1"
}
#[cfg(feature="flavour2")]
fn sublayer() -> &'static str {
"flavour 2"
}
#[cfg(not(any(feature="flavour1",feature="flavour2"))]
compile_error!("Need a flavour");
fn main() {
println!("{}", sublayer());
}
英文:
I need to build a CLI application that comes in two flavours. Most of the code is common to both, excepting some low-level layer.
So far, I've been able to specify the creation of multiple binaries using the [[bin]]
notation, and using ad-hoc features. However, that requires to invoke cargo build
twice, once with --features="flavour1"
and once with --features="flavour2"
.
- is there any way to have Cargo to build these two flavours with a single command?
- is this an anti-pattern? I appreciate features are additive, and it is recommended to avoid mutually exclusive features, but I couldn't find another way to do this.
To illustrate the question, here follows a sample Cargo.toml
and the corresponding src/main.rs
file:
Cargo.toml
[package]
name = "sample-flavours"
version = "0.1.0"
edition = "2021"
[features]
flavour1=[]
flavour2=[]
[[bin]]
name="bin-flavour1"
path="src/main.rs"
required-features=["flavour1"]
[[bin]]
name="bin-flavour2"
path="src/main.rs"
required-features=["flavour2"]
src/main.rs
#[cfg(feature="flavour1")]
fn sublayer() -> &'static str {
"flavour 1"
}
#[cfg(feature="flavour2")]
fn sublayer() -> &'static str {
"flavour 2"
}
#[cfg(not(any(feature="flavour1",feature="flavour2")))]
compile_error!("Need a flavour");
fn main() {
println!("{}", sublayer());
}
答案1
得分: 1
No. Cargo can build multiple binaries in one command, but only with a common feature set.
As you yourself noted, features should be additive. You haven't told us any detail about the code differences between flavour1
and flavour2
, but one possibility is that you can replace them with generics — perhaps struct SomeImportantStruct<F>
is instantiated as SomeImportantStruct<Flavour1>
and SomeImportantStruct<Flavour2>
— or simply have two different structs/modules/functions/whatever.
If you can achieve that, then it will be possible to compile both of your binaries with a single command. Now, this does not necessarily solve all build problems; for example, it might be desirable to disable a feature for smaller code size or performance, or a feature might be actually impossible to compile on a given target. Or, unrelated to features, you might want to use a different profile for the two builds. In any of those cases, you'll want to use a separate build command anyway.
英文:
> Is there any way to have Cargo to build these two flavours with a single command?
No. Cargo can build multiple binaries in one command, but only with a common feature set.
If you find you need to run multiple build commands for your project, and want to automate this, you will need something external to invoke Cargo. I like the xtask
pattern, which lets you write your commands in Rust without any dependencies on additional command-line tools, but it may be overkill for your use case; a shell script might do.
> Is this an anti-pattern?
As you yourself noted, features should be additive. You haven't told us any detail about the code differences between flavour1
and flavour2
, but one possibility is that you can replace them with generics — perhaps struct SomeImportantStruct<F>
is instantiated as SomeImportantStruct<Flavour1>
and SomeImportantStruct<Flavour2>
— or simply have two different structs/modules/functions/whatever.
If you can achieve that, then it will be possible to compile both of your binaries with a single command. Now, this does not necessarily solve all build problems; for example, it might be desirable to disable a feature for smaller code size or performance, or a feature might be actually impossible to compile on a given target. Or, unrelated to features, you might want to use a different profile for the two builds. In any of those cases, you'll want to use a separate build command anyway.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论