我怎样才能激活我所有箱子中的功能?
How can I activate features in all my crates?
我想有条件地启用 运行-time 检查和日志记录,它们彼此独立,并且与调试和发布模式无关。所以我开始在我的项目中添加两个 features,一个叫做 "invariant-checking",一个叫做 "logging"。最终,我希望通过我在项目范围内可见的板条箱中定义的宏来使用它们。
我假设如果我以相同的方式在所有箱子中以相同的方式填写 features section 然后当我在编译 bin crate 时激活该功能,那么所有的 lib crates 也会有该功能已启用,但事实并非如此!如何跨多个 crate 启用和禁用功能?希望这可以通过只改变一个东西来完成,比如 cargo 的命令行参数。
为了准确说明我想要什么,here's an example,我也将在下面重现:
共有三个 crate,main、bin、crate 和两个 lib crate,分别称为 "middle" 和 "common"。以下是相关文件的相关部分:
main.rs
extern crate common;
extern crate middle;
fn main() {
common::check!();
middle::run();
println!("done");
}
主要Cargo.toml
[dependencies]
[dependencies.common]
path = "libs/common"
[dependencies.middle]
path = "libs/middle"
[features]
default = []
invariant-checking = []
logging = []
中间的lib.rs
extern crate common;
pub fn run() {
common::check!();
common::run();
}
中间的Cargo.toml
[dependencies]
[dependencies.common]
path = "../common"
[features]
default = []
invariant-checking = []
logging = []
普通的lib.rs
#[macro_export]
macro_rules! check {
() => {{
if cfg!(feature = "invariant-checking") {
println!("invariant-checking {}:{}", file!(), line!());
}
if cfg!(feature = "logging") {
println!("logging {}:{}", file!(), line!());
}
}};
}
pub fn run() {
check!()
}
最后是普通的Cargo.toml
[dependencies]
[features]
default = []
invariant-checking = []
logging = []
当我 运行 cargo run --features "invariant-checking,logging"
我得到以下输出
invariant-checking src\main.rs:5
logging src\main.rs:5
done
但希望它也能登录中间和普通。我怎样才能改造这个项目,让它做到这一点,并且仍然允许我通过只改变一个地方来获得 "done" 作为输出?
How can I enable and disable features across multiple crates?
A Cargo.toml
可以添加功能,这些功能可传递地启用允许属于依赖项的其他功能。
例如,在依赖于 crate foo
和 bar
的 crate 的 Cargo.toml
中:
[dependencies]
foo = "0.1"
bar = "0.1"
[features]
default = []
invariant-checking = [ "foo/invariant-checking", "bar/invariant-checking" ]
logging = [ "foo/logging", "bar/logging" ]
此 crate 添加了 invariant-checking
和 logging
功能。启用它们可传递地启用板条箱 foo
和 bar
的各自功能,因此
cargo build --features=logging,invariant-checking
将启用此 crate 及其依赖项 foo
和 bar
中的 logging
和 invariant-checking
功能。
在您的特定情况下,您可能希望 main
传递启用 middle
和 common
的功能,而 middle
传递启用 common
。
当前形式的宏定义有一个问题:只要使用宏,宏内部的代码就会被内联,然后在被内联的上下文中进行编译。由于您使用
等运行时功能检查
if cfg!(feature = "invariant-checking")
这意味着您需要在使用宏的每个 crate 中定义功能。另一方面,在 common
板条箱本身中,该功能永远不会被查询,因此是多余的。
这对我来说似乎完全倒退了。功能标志应该 仅 在公共包中查询,使用宏不需要首先在使用它的包中定义功能标志。出于这个原因,我建议使用编译时检查来 select 定义什么宏:
#[cfg(feature = "invariant-checking")]
macro_rules! check_invariant {
() => ( println!("invariant-checking {}:{}", file!(), line!()); )
}
#[cfg(not(feature = "invariant-checking"))]
macro_rules! check_invariant {
() => ()
}
#[cfg(feature = "logging")]
macro_rules! logging {
() => ( println!("logging {}:{}", file!(), line!()); )
}
#[cfg(not(feature = "logging"))]
macro_rules! logging {
() => ()
}
#[macro_export]
macro_rules! check {
() => ( check_invariant!(); logging!(); )
}
这样,您只需要在 common
包中定义功能,这是应该的。只要你只使用那个箱子的一个版本,打开和关闭标志就会有全局效果。
我想有条件地启用 运行-time 检查和日志记录,它们彼此独立,并且与调试和发布模式无关。所以我开始在我的项目中添加两个 features,一个叫做 "invariant-checking",一个叫做 "logging"。最终,我希望通过我在项目范围内可见的板条箱中定义的宏来使用它们。
我假设如果我以相同的方式在所有箱子中以相同的方式填写 features section 然后当我在编译 bin crate 时激活该功能,那么所有的 lib crates 也会有该功能已启用,但事实并非如此!如何跨多个 crate 启用和禁用功能?希望这可以通过只改变一个东西来完成,比如 cargo 的命令行参数。
为了准确说明我想要什么,here's an example,我也将在下面重现:
共有三个 crate,main、bin、crate 和两个 lib crate,分别称为 "middle" 和 "common"。以下是相关文件的相关部分:
main.rs
extern crate common;
extern crate middle;
fn main() {
common::check!();
middle::run();
println!("done");
}
主要Cargo.toml
[dependencies]
[dependencies.common]
path = "libs/common"
[dependencies.middle]
path = "libs/middle"
[features]
default = []
invariant-checking = []
logging = []
中间的lib.rs
extern crate common;
pub fn run() {
common::check!();
common::run();
}
中间的Cargo.toml
[dependencies]
[dependencies.common]
path = "../common"
[features]
default = []
invariant-checking = []
logging = []
普通的lib.rs
#[macro_export]
macro_rules! check {
() => {{
if cfg!(feature = "invariant-checking") {
println!("invariant-checking {}:{}", file!(), line!());
}
if cfg!(feature = "logging") {
println!("logging {}:{}", file!(), line!());
}
}};
}
pub fn run() {
check!()
}
最后是普通的Cargo.toml
[dependencies]
[features]
default = []
invariant-checking = []
logging = []
当我 运行 cargo run --features "invariant-checking,logging"
我得到以下输出
invariant-checking src\main.rs:5
logging src\main.rs:5
done
但希望它也能登录中间和普通。我怎样才能改造这个项目,让它做到这一点,并且仍然允许我通过只改变一个地方来获得 "done" 作为输出?
How can I enable and disable features across multiple crates?
A Cargo.toml
可以添加功能,这些功能可传递地启用允许属于依赖项的其他功能。
例如,在依赖于 crate foo
和 bar
的 crate 的 Cargo.toml
中:
[dependencies]
foo = "0.1"
bar = "0.1"
[features]
default = []
invariant-checking = [ "foo/invariant-checking", "bar/invariant-checking" ]
logging = [ "foo/logging", "bar/logging" ]
此 crate 添加了 invariant-checking
和 logging
功能。启用它们可传递地启用板条箱 foo
和 bar
的各自功能,因此
cargo build --features=logging,invariant-checking
将启用此 crate 及其依赖项 foo
和 bar
中的 logging
和 invariant-checking
功能。
在您的特定情况下,您可能希望 main
传递启用 middle
和 common
的功能,而 middle
传递启用 common
。
当前形式的宏定义有一个问题:只要使用宏,宏内部的代码就会被内联,然后在被内联的上下文中进行编译。由于您使用
等运行时功能检查if cfg!(feature = "invariant-checking")
这意味着您需要在使用宏的每个 crate 中定义功能。另一方面,在 common
板条箱本身中,该功能永远不会被查询,因此是多余的。
这对我来说似乎完全倒退了。功能标志应该 仅 在公共包中查询,使用宏不需要首先在使用它的包中定义功能标志。出于这个原因,我建议使用编译时检查来 select 定义什么宏:
#[cfg(feature = "invariant-checking")]
macro_rules! check_invariant {
() => ( println!("invariant-checking {}:{}", file!(), line!()); )
}
#[cfg(not(feature = "invariant-checking"))]
macro_rules! check_invariant {
() => ()
}
#[cfg(feature = "logging")]
macro_rules! logging {
() => ( println!("logging {}:{}", file!(), line!()); )
}
#[cfg(not(feature = "logging"))]
macro_rules! logging {
() => ()
}
#[macro_export]
macro_rules! check {
() => ( check_invariant!(); logging!(); )
}
这样,您只需要在 common
包中定义功能,这是应该的。只要你只使用那个箱子的一个版本,打开和关闭标志就会有全局效果。