如何设置cfg选项以有条件地进行编译?

5

我正在处理一些代码,其中缓冲区由固定大小的数组支持。由于Rust和其提供的构建工具提供了有条件编译的可能性,因此我可以像这样做:

struct Buffer {
    // default case, if none is set
    #[cfg(not(buffersize))]
    buffer: [f32; 16],

    #[cfg(buffersize = "32")]
    buffer: [f32; 32],

    #[cfg(buffersize = "64")]
    buffer: [f32; 64],
}

impl Buffer {
    fn new() -> Buffer {
        Buffer {
            #[cfg(not(buffersize))]
            buffer: [0.0; 16],

            #[cfg(buffersize = "32")]
            buffer: [0.0; 32],

            #[cfg(buffersize = "64")]
            buffer: [0.0; 64],
        }
    }
}

这里有另一个问题使用特性进行条件编译。仅使用特性,我必须将buffersize和实际值(例如buffersize16)组合在一起。是否可以向Cargo提供cfg标志,或者需要直接向rustc提供它们?


1
根据这个答案,我需要使用features。这是正确的吗? - user8725011
为什么你需要这样做?有没有什么理由不能期望用户传递一个切片作为缓冲区,而不是使用这个缓冲对象?这看起来非常繁琐,特别是当你可能想要同时拥有两个不同的缓冲区大小时。 - user11877195
这里有多个因素在起作用:首先,Buffer只是一个静态大小数组的包装器。我本可以使用类型别名例如 type Buffer = [f32; 256] 并对其实现必要的方法。Buffer最终将在某些并发上下文中使用/将在多个线程中处理。在这里使用正确的生命周期似乎更加麻烦,但我明白你的意思,提供的示例并不是很优雅。 - user8725011
公平的说,那多个缓冲区大小问题怎么解决? 我建议使用多个结构体,或者一个通用结构体并让用户在创建缓冲区之前选择需要的大小,而不是在编译时选择,即使他们只需要一个缓冲区类型。(用户是泛指,即使你只是为自己编写代码) - user11877195
2个回答

14
您可以设置环境变量RUSTFLAGS或在.cargo/config中设置rustflags变量。
来自环境变量

RUSTFLAGS——传递给Cargo执行的所有编译器调用的自定义标志的以空格分隔的列表。与cargo rustc相比,这对于将标志传递给所有编译器实例非常有用。

在您的示例中,您可以使用:

RUSTFLAGS='--cfg buffersize="32"' cargo build

2
我希望能够在我的问题中增加一个更新,提供一种在编译时传递(数字)配置值的额外选项,这可以通过构建脚本实现。
假设您的项目内有以下构建脚本:
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-env-changed=SIZE");
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest = Path::new(&out_dir).join("consts.rs");

    let mut out_file = File::create(&dest).expect("Cannot create file");
    let size: usize = env!("SIZE").parse().unwrap();

    write!(&out_file, "pub const S : usize = {};", size);
}

它在编译时读取一个环境变量,将其解析为usize并写入一个仅包含常量的rust文件(consts.rs)。现在,在您的应用程序代码中,您可以包含此文件并使用该常量来例如在堆栈上分配内存:

include!(concat!(env!("OUT_DIR"), "/consts.rs"));

fn main() {
    let array = [0.0f32; S];
    println!("array len= {:?}", array.len());
}

这个技巧的缺点是,每当环境变量的值发生变化时,你就必须重新编译整个项目(或其中的部分),因为不会被捕获。这也意味着必须始终了解这个配置选项,但可以将其包装在额外的构建脚本中,比如makefile。即使这不是最优雅的选择,但在某些情况下可能是一个选项。
不过,把它作为宏选项会更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接