Is it possible to use environment variables with #[cfg(...)]?


#1

I tried to find a way of doing this, but cfg isn’t amazingly documented - or rather the documentation for it is hard to find.

What I want to do is something this:

#[cfg(env("MY_ENVIRONMENT_VARIABLE"))]
println!("Environment variable was: {}", env!("MY_ENVIRONMENT_VARIABLE"));

#[cfg(not(env("MY_ENVIRONMENT_VARIABLE")))]
println!("Environment variable was not set!");

I know I could use a feature for the conditional compilation part of this - but then I’d be in a position where I have to always set a feature and an environment variable, instead of just setting one thing.

Is something like this possible?


#2

Would the option_env! macro work for your usecase?

cfg only exposes two things:

  • The intrinsic settings by the rust compiler, which you can view with rustc --print=cfg
  • Settings passed on the command-line to rustc with --cfg

You’re probably using cargo, which will pass --cfg options to rustc in two ways:


#3

I use the build script to set the feature based on an environment variable, that way I can set in one place (or use a buildbot-like setup if needs be).


#4

Alright, good to know!

Since this is within a macro, and I can’t rely on consumers doing anything in particular with their build scripts, I think option_env! is my best bet. It’s a tiny bit of extra work at runtime, but I guess I can probably rely on it being optimized away.


#5

As long as the dependency isn’t required later (see this issue), you can generally just get it to enable. If you need optional dependencies/building, then you have an issue.

That said, it really depends on your consumers. For me anyone who is using my Rust runtimes (i.e. binaries) either has the source and is using it as a library (typically speaking) or is happy with defaults/will ask (or I have to build it for them). In the case of the latter I use Python to pull a file conditionally from a webserver using an API token they’re given (set as an environment variable) and Python does the ENV checks. The same could be done much in a much neater way locally for compiling (if they have Rust installed, as seems to be the case). Just generate the build script for them using some kind of scripting (or even a Rust application that executes in the crate’s root).


#6

Is there a reason why you’re not using Cargo features? That’s the recommended way to optionally enable things in code.


#7

Yep - I mentioned in my first post. I’m using a feature at the moment, but the problem is that you either redundantly have to set both a feature and an environment variable, or neither.

Essentially, I have a boolean flag (the feature) and a nullable string (the environment variable) - but I’d rather combine the two and have an Option<String> (that I can use for conditional compilation).


#8

Could you use build.rs to enable the feature based on presence of an env var?


#9

Can’t really use build scripts since I don’t want a consumer of my crate to have to involve one.


#10

build.rs is run automatically, so it doesn’t make any difference to consumers.


#11

So I went to go try this out, expecting it not to work and… oh jeez, it turns out I was completely misunderstanding the interaction between features and macro expansion.

I have some bugs to fix, but at least the build.rs method should work after that.

Thanks for the advice. (And thanks to @aws for the same suggestion - which I hadn’t tested until now.)