Reputation:
I am working on some code where a buffer is backed by a statically sized array. Since Rust and the build tools provided by it offer the possibilities to compile conditionally, I can do something like this:
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],
}
}
}
There is another question that uses features to compile the code conditionally. Using features alone, I would have to combine buffersize
and the actual value e.g. buffersize16
. Is it possible to provide the cfg
flags to Cargo, or would I need to provide them directly to rustc
?
Upvotes: 6
Views: 8029
Reputation:
I want to post an update to my question as an additional option on how to pass (numeric) configuration values at compile time, that's possible through a build script.
Suppose you have following build script inside your project:
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);
}
It reads an environment variable at compile time, parses it as usize
and writes a rust file (consts.rs
) containing only the constant. Now, in your application code you can include this file and use the constant to eg. allocate memory on the stack:
include!(concat!(env!("OUT_DIR"), "/consts.rs"));
fn main() {
let array = [0.0f32; S];
println!("array len= {:?}", array.len());
}
The downside of this trick is, that you have to recompile the whole project (or parts of it) whenever the value of the environment variable changes, since cargo:rerun-if-env-changed=SIZE
doesn't get captured. It also implies to always keep knowledge of this configuration option, but this could be wrapped in an additional build script like a makefile. Even if this is not the most elegant path to choose, it might be an option on certain occasions.
It would be nice to have this as macro option, though.
Upvotes: 2
Reputation: 11952
You can set the environnment variable RUSTFLAGS
or set rustflags
variable in .cargo/config
.
From 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.
In your example, you could use :
RUSTFLAGS='--cfg buffersize="32"' cargo build
Upvotes: 15