Compilation 如何激活所有板条箱中的功能?

Compilation 如何激活所有板条箱中的功能?,compilation,rust,rust-cargo,Compilation,Rust,Rust Cargo,我希望有条件地启用运行时检查和日志记录,彼此独立,并从调试和发布模式独立。所以我开始在我的项目中添加两个,一个叫做“不变检查”,另一个叫做“日志记录”。最终,我希望通过在项目范围内可见的板条箱中定义的宏来使用它们 我假设,如果我在所有板条箱中以相同的方式填写,那么当我在编译箱子板条箱时激活该功能时,所有的lib板条箱也会启用该功能,但事实并非如此!如何跨多个板条箱启用和禁用功能?希望通过将命令行参数之类的一件事更改为cargo就可以做到这一点 为了明确我想要什么,我还将在下面复制: 有三个板条箱

我希望有条件地启用运行时检查和日志记录,彼此独立,并从调试和发布模式独立。所以我开始在我的项目中添加两个,一个叫做“不变检查”,另一个叫做“日志记录”。最终,我希望通过在项目范围内可见的板条箱中定义的宏来使用它们

我假设,如果我在所有板条箱中以相同的方式填写,那么当我在编译箱子板条箱时激活该功能时,所有的lib板条箱也会启用该功能,但事实并非如此!如何跨多个板条箱启用和禁用功能?希望通过将命令行参数之类的一件事更改为cargo就可以做到这一点

为了明确我想要什么,我还将在下面复制:

有三个板条箱,主板条箱、箱、板条箱和两个lib板条箱,称为“中间”和“普通”。以下是相关文件的相关部分:

梅因

主要货物

中间人的自由

middle’s Cargo.toml

公共图书馆

最后是common的Cargo.toml

当我运行
cargo-run时--features“invariant checking,logging”
我得到以下输出

invariant-checking src\main.rs:5
logging src\main.rs:5
done
但我希望它也能登录到中间和公共位置。我如何转换这个项目,使它能够做到这一点,并且仍然允许我只通过更改一个位置来“完成”输出

如何跨多个板条箱启用和禁用功能

A
Cargo.toml
可以添加一些特性,这些特性可以过渡地启用允许属于依赖项的其他特性

例如,在板条箱的
Cargo.toml
中,取决于板条箱
foo
bar

[dependencies]
foo = "0.1"
bar = "0.1"

[features]
default = []
invariant-checking = [ "foo/invariant-checking", "bar/invariant-checking" ]
logging = [ "foo/logging", "bar/logging" ]
此板条箱添加了
不变检查
日志记录
功能。通过过渡方式启用板条箱
foo
bar
的相应功能,以便

cargo build--features=日志记录、不变检查
将启用此板条箱及其依赖项
foo
栏中的
日志记录
不变检查
功能


在您的特定情况下,您可能希望
main
以过渡方式启用
middle
common
的功能,并希望
middle
以过渡方式启用
common
的功能

当前形式的宏定义有一个问题:每当使用宏时,宏中的代码都会内联,然后在内联的上下文中编译。由于您使用运行时功能检查,如

if cfg!(feature = "invariant-checking")
这意味着您需要在使用宏的每个板条箱中定义特征。另一方面,在
通用
板条箱本身中,该特征从不被查询,因此是冗余的

这在我看来完全是倒退。应仅在公共板条箱中查询特征标志,并且使用宏不应要求首先在使用它的板条箱中定义特征标志。因此,我建议使用编译时检查来选择要定义的宏:

#[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
板条箱中按原样定义功能。只要您只使用该板条箱的一个版本,打开和关闭标志就具有全局效果。

您应该根据在
common
中选择的功能定义不同的宏,因此功能选择在编译时进行,并且仅在
common
板条箱中进行。然后,您只需声明该板条箱中的功能,只要所有板条箱使用相同版本的
common
,切换功能将具有全局效果。我相信您的问题已由的答案回答。如果你不同意,请用你的问题来解释不同之处。否则,我们可以将这个问题标记为已回答。@SvenMarnach这听起来肯定比将旗帜传递到每个板条箱要少一些设置和维护。如果我理解正确,您建议使用相同的名称定义多个宏,并选择使用诸如
[cfg(feature=“logging”)]
[cfg(not(feature=“logging”)]
等属性启用的宏。这很有效。至少在我的玩具示例中,我只需要提到main和
common
Cargo.toml
文件中的特性@Shepmaster我想前面的答案可能在技术上让我能够找出答案,但我发现gnzlbg的解释比仅仅指出我错过的一小段文档更有帮助。尽管如此,你可以随意标记这个问题。@Ryan1729是的,这就是我的意思。现在我在办公桌上(在手机上写下了评论),我可以在回答中进行扩展。我假设
如果cfg!(…){/*…*/}
很容易被编译器删除。我在上尝试了一些简单的示例,似乎这些示例已成功删除。更复杂的情况下可能会出现大量的
cfg调用不是这样,所以这种技术似乎很有用,因为它在任何情况下都可以工作。@Ryan1729如果在编译时静态地知道配置设置,那么优化器应该始终能够静态地解析分支。然而,这是一个运行时检查这一事实只是一个旁注。更重要的一点是解析特性的上下文。此版本解析
通用
板条箱中的所有功能查询,而您的版本在使用宏的板条箱中解析它们。
#[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!()
}
[dependencies]

[features]
default = []
invariant-checking = []
logging = []
invariant-checking src\main.rs:5
logging src\main.rs:5
done
[dependencies]
foo = "0.1"
bar = "0.1"

[features]
default = []
invariant-checking = [ "foo/invariant-checking", "bar/invariant-checking" ]
logging = [ "foo/logging", "bar/logging" ]
if cfg!(feature = "invariant-checking")
#[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!(); )
}