I have a procedural macro crate Proc
and binary crate Bin
. Bin
has a dependency on Proc
. Proc
needs a filled environment variable to function properly.
This is some code inside my build.rs
in Bin
. Proc
can successfully find the env value when using the following code:
fn main() {
println!("cargo:rustc-env=SOME_ENV_VALUE=somevalue");
}
However, Proc
fails to find the environment variable when using this code inside my build.rs
in Bin
(note: when checking the existence right after the dotenv
call, I can verify the key is actually present):
fn main() {
dotenv::dotenv().unwrap();
}
This is my Proc
crate:
use proc_macro::TokenStream;
#[proc_macro_derive(MyProcMacro)]
pub fn my_proc_macro(input: TokenStream) -> TokenStream {
if std::env::var("SOME_ENV_VALUE").is_err() {
panic!("Failed to retrieve env value")
}
TokenStream::new()
}
Why won't it fail with the println!
command? Can it work with dotenv
? Else I need to write some code that copies the keys from my env
file to the println!
command...
All the code is in my minimal reproduction project.
I encourage you to re-read the Build Scripts chapter of the Cargo docs. A build script is a separate executable that Cargo builds and executes before starting to build your source code.
rustc
to build the build scriptrustc
to build your code[dotenv] loads environment variables from a .env file, if available, and mashes those with the actual environment variables provided by the operating system.
Variables that it loads are placed into the current processes environment variables. In your example, that's the build script executable.
[
cargo:rustc-env
] tells Cargo to set the given environment variable when compiling the package
The stdout of the build script interacts with Cargo, which then modifies how the code is compiled, including what environment variables to set.
You need to load the dotenv file and set the environment variables for the subsequent compilation. Something like this compiling-but-untested example:
fn main() {
if let Ok(env) = dotenv::dotenv_iter() {
for (k,v) in env.flatten() {
println!("cargo:rustc-env={}={}", k, v);
}
}
}
Don't worry that this method is marked as deprecated. The maintainers changed their minds.