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

How to set cfg options to compile conditionally?

我正在编写一些代码,其中缓冲区由静态大小的数组支持。由于 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],
        }
    }
}

another question使用特性有条件地编译代码。单独使用功能,我将不得不结合 buffersize 和实际值,例如buffersize16。是否可以向 Cargo 提供 cfg 标志,或者我需要直接向 rustc 提供它们吗?

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

RUSTFLAGS — A space-separated list of custom flags to pass to all compiler invocations that Cargo performs. In contrast with cargo rustc, this is useful for passing a flag to all compiler instances.

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

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

我想post更新我的问题,作为关于如何在编译时传递(数字)配置值的附加选项,这可以通过构建脚本实现。

假设您的项目中有以下构建脚本:

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());
}

这个技巧的缺点是,只要环境变量的值发生变化,您就必须重新编译整个项目(或部分项目),因为 cargo:rerun-if-env-changed=SIZE 不会被捕获。它还意味着始终了解此配置选项,但这可以包装在一个额外的构建脚本中,如 makefile。即使这不是最优雅的选择方式,在某些情况下也可能是一种选择。

不过,最好将其作为宏选项。