Is it possible to define a constant in source code that can be overridden by a compiler flag? That is, something like setting a #define
value in the C preprocessor with the -D key=val
option to the compiler.
I have read about conditional compilation via the #[cfg(...)]
attribute, but that only seems to support booleans. I want to allow the user to set the value of a constant during compilation.
Something like this:
#[from_cfg("max_dimensions")]
const MAX_DIMENSIONS: usize = 100_000;
Installation defaults: The default compiler options that were set up when your compiler was installed are in effect for your program unless you override those options. (In some installations, certain compiler options are fixed so that you cannot override them. If you have problems with the default options, contact your system administrator.)
You can direct and control your compilation by using compiler options or by using compiler-directing statements (compiler directives). Compiler options affect the aspects of your program that are listed in the table below.
You can declare a compiler constant in the following three ways: Each method produces slightly different results from the other two. First, it is important to understand the mechanics of declaration for each case.
override means that the class this is a member function of inherits from a class that contains a virtual function of the same name and signature; this function here is overriding that parent virtual function. const here is a promise that this function won't change any member variables, and won't call any functions that might.
No, you can't define constants (read: const
bindings) with a compiler flag. But you can use the env!
macro for something similar. It reads some environment variable at compile time.
const MAX_DIMENSIONS_RAW: &'static str = env!("MAX_DIMENSIONS");
Sadly, this returns a string and not an integer. Furthermore we can't yet call arbitrary functions (like parse
) at compile time to calculate a constant. You could use lazy_static
to achieve something similar:
lazy_static! {
static ref MAX_DIMENSIONS: usize = MAX_DIMENSIONS_RAW.parse().unwrap();
}
Of course you should add proper error handling. If your user doesn't need to define the environment variable, you can use option_env!
.
With this approach, you can pass the setting at build time:
$ MAX_DIMENSIONS=1000 cargo build
Building on Lukas Kalbertodt's answer, you can get the environment variable as a constant number with some extra indirection, namely by using a build script.
build.rs
use std::{env, fs::File, io::Write, path::Path};
fn main() {
let out_dir = env::var("OUT_DIR").expect("No out dir");
let dest_path = Path::new(&out_dir).join("constants.rs");
let mut f = File::create(&dest_path).expect("Could not create file");
let max_dimensions = option_env!("MAX_DIMENSIONS");
let max_dimensions = max_dimensions
.map_or(Ok(10_000), str::parse)
.expect("Could not parse MAX_DIMENSIONS");
write!(&mut f, "const MAX_DIMENSIONS: usize = {};", max_dimensions)
.expect("Could not write file");
println!("cargo:rerun-if-env-changed=MAX_DIMENSIONS");
}
main.rs
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
fn main() {
println!("The value is {} ({})", MAX_DIMENSIONS, MAX_DIMENSIONS + 1);
}
$ cargo run
The value is 10000 (10001)
$ MAX_DIMENSIONS=17 cargo run
The value is 17 (18)
$ MAX_DIMENSIONS=1 cargo run
The value is 1 (2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With