我可以创建自己的条件编译属性吗?
Can I create my own conditional compilation attributes?
在我的 crate 中有几种方法可以执行某些操作,一些可以快速执行,一些可以降低二进制大小,一些具有其他优点,因此我为所有这些方法提供了用户界面。未使用的函数将被编译器优化掉。我 crate 中的内部函数也必须使用这些接口,我希望它们在编译时尊重用户的选择。
有像target_os
这样的条件编译属性,它存储了像linux
或windows
这样的值。我如何创建这样的属性,例如 prefer_method
,以便我和用户可以像以下代码片段一样使用它?
我的箱子:
#[cfg(not(any(
not(prefer_method),
prefer_method = "fast",
prefer_method = "small"
)))]
compile_error("invalid `prefer_method` value");
pub fn bla() {
#[cfg(prefer_method = "fast")]
foo_fast();
#[cfg(prefer_method = "small")]
foo_small();
#[cfg(not(prefer_method))]
foo_default();
}
pub fn foo_fast() {
// Fast execution.
}
pub fn foo_small() {
// Small binary file.
}
pub fn foo_default() {
// Medium size, medium fast.
}
用户箱子:
#[prefer_method = "small"]
extern crate my_crate;
fn f() {
// Uses the `foo_small` function, the other `foo_*` functions will not end up in the binary.
my_crate::bla();
// But the user can also call any function, which of course will also end up in the binary.
my_crate::foo_default();
}
我知道有 --cfg
个属性,但 AFAIK 这些仅表示布尔标志,而不是枚举值,这允许在只有一个枚举值有效时设置多个标志。
首先,--cfg
标志支持使用语法 --cfg 'prefer_method="fast"'
的键值对。这将允许您编写如下代码:
#[cfg(prefer_method = "fast")]
fn foo_fast() { }
您还可以设置这些 cfg 选项 from a build script。例如:
// build.rs
fn main() {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
}
// src/main.rs
#[cfg(prefer_method = "method_a")]
fn main() {
println!("It's A");
}
#[cfg(prefer_method = "method_b")]
fn main() {
println!("It's B");
}
#[cfg(not(any(prefer_method = "method_a", prefer_method = "method_b")))]
fn main() {
println!("No preferred method");
}
上面的代码将产生一个打印 "It's A".
的可执行文件
没有您建议的用于指定 cfg 设置的语法。将这些选项暴露给你的板条箱用户的最好方法是通过 Cargo features.
例如:
# Library Cargo.toml
# ...
[features]
method_a = []
method_b = []
// build.rs
fn main() {
// prefer method A if both method A and B are selected
if cfg!(feature = "method_a") {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
} else if cfg!(feature = "method_b") {
println!("cargo:rustc-cfg=prefer_method=\"method_b\"");
}
}
# User Cargo.toml
# ...
[dependencies.my_crate]
version = "..."
features = ["method_a"]
但是,在这种情况下,我建议直接在您的代码中使用 Cargo 功能(即 #[cfg(feature = "fast")]
),而不是添加构建脚本,因为货物之间存在一对一的对应关系正在添加功能和 rustc-cfg。
在我的 crate 中有几种方法可以执行某些操作,一些可以快速执行,一些可以降低二进制大小,一些具有其他优点,因此我为所有这些方法提供了用户界面。未使用的函数将被编译器优化掉。我 crate 中的内部函数也必须使用这些接口,我希望它们在编译时尊重用户的选择。
有像target_os
这样的条件编译属性,它存储了像linux
或windows
这样的值。我如何创建这样的属性,例如 prefer_method
,以便我和用户可以像以下代码片段一样使用它?
我的箱子:
#[cfg(not(any(
not(prefer_method),
prefer_method = "fast",
prefer_method = "small"
)))]
compile_error("invalid `prefer_method` value");
pub fn bla() {
#[cfg(prefer_method = "fast")]
foo_fast();
#[cfg(prefer_method = "small")]
foo_small();
#[cfg(not(prefer_method))]
foo_default();
}
pub fn foo_fast() {
// Fast execution.
}
pub fn foo_small() {
// Small binary file.
}
pub fn foo_default() {
// Medium size, medium fast.
}
用户箱子:
#[prefer_method = "small"]
extern crate my_crate;
fn f() {
// Uses the `foo_small` function, the other `foo_*` functions will not end up in the binary.
my_crate::bla();
// But the user can also call any function, which of course will also end up in the binary.
my_crate::foo_default();
}
我知道有 --cfg
个属性,但 AFAIK 这些仅表示布尔标志,而不是枚举值,这允许在只有一个枚举值有效时设置多个标志。
首先,--cfg
标志支持使用语法 --cfg 'prefer_method="fast"'
的键值对。这将允许您编写如下代码:
#[cfg(prefer_method = "fast")]
fn foo_fast() { }
您还可以设置这些 cfg 选项 from a build script。例如:
// build.rs
fn main() {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
}
// src/main.rs
#[cfg(prefer_method = "method_a")]
fn main() {
println!("It's A");
}
#[cfg(prefer_method = "method_b")]
fn main() {
println!("It's B");
}
#[cfg(not(any(prefer_method = "method_a", prefer_method = "method_b")))]
fn main() {
println!("No preferred method");
}
上面的代码将产生一个打印 "It's A".
的可执行文件没有您建议的用于指定 cfg 设置的语法。将这些选项暴露给你的板条箱用户的最好方法是通过 Cargo features.
例如:
# Library Cargo.toml
# ...
[features]
method_a = []
method_b = []
// build.rs
fn main() {
// prefer method A if both method A and B are selected
if cfg!(feature = "method_a") {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
} else if cfg!(feature = "method_b") {
println!("cargo:rustc-cfg=prefer_method=\"method_b\"");
}
}
# User Cargo.toml
# ...
[dependencies.my_crate]
version = "..."
features = ["method_a"]
但是,在这种情况下,我建议直接在您的代码中使用 Cargo 功能(即 #[cfg(feature = "fast")]
),而不是添加构建脚本,因为货物之间存在一对一的对应关系正在添加功能和 rustc-cfg。