Per-target environment variables in cargo config

I need my project to set certain environment variables (needed for the build) only if the target is linux x86_64.

Nothing sticks out in Configuration - The Cargo Book.

It seems like this would be a generally useful/important feature

Is there a way to do this currently?

Did you look at std::env?

use std::env;

let key = "KEY";
env::set_var(key, "VALUE");
assert_eq!(env::var(key), Ok("VALUE".to_string()));
1 Like

The environment variables are needed for the building of a dependency, so I assume that using them in code would be too late?

I'm sorry, I misread this. Your later post explains it. Are you trying to create your own crate?

1 Like

Yes, it's a crate that has a dependency on boringssl. BoringSSL can take environment variables to control the behavior. I need to override the default behavior with these variables only when on linux x86_64.

So I believe that .cargo/config.toml is the place to do this. But it's just not clear if there's a way to specify the environment variable only for a specific target.

1 Like

If there's no way to do this today, I'm happy to raise a bug. Just need to know if it's possible.

Thanks!

Does it have to be inside cargo/config.toml? I don't think cargo can do that. Would a conditional compilation work instead?
https://doc.rust-lang.org/reference/conditional-compilation.html

1 Like

I'm not sure I understand. How would I use conditional compilation if the logic is contained within a dependency?

Can your own crate modify the environment variables you wish to modify not via cargo but via the target-os = <linux> property? The way I understand it is ... rustc would perform the operation instead of cargo(since cargo does not allow inside .toml operators).

1 Like

Thanks, @tyggja. I'm a bit new to rust/cargo .. could you provide more detail or point me to examples?

I'm sorry, I looked for a complete example, but I can only find bits and pieces. We can try to build one and post it here, if you'd like.

Depending on when you'd like to target and modify your ENV(s), we can do that programmatically, either by using the cfg!:

#![allow(unused)]
fn main() {
let machine_kind = if cfg!(unix) {
  "unix"
} else if cfg!(windows) {
  "windows"
} else {
  "unknown"
};

println!("I'm running on a {} machine!", machine_kind);
}

or like this:

#![allow(unused)]
fn main() {
// The function is only included in the build when compiling for linux
#[cfg(target_os = "linux")]
fn linux_only() {
  // ... add your ENV modifiers here
}

// This function is only included when either foo or bar is defined
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// This function is only included when compiling for a unixish OS with a 32-bit
// architecture
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
  // ...
}

// This function is only included when foo is not defined
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}

// This function is only included when the panic strategy is set to unwind
#[cfg(panic = "unwind")]
fn when_unwinding() {
  // ...
}
1 Like

My assumption was that the dependency was yours, as per

Thanks @tyggja. I'm pretty sure this won't work, since the problem is that I have to pass the environment variables to the boringssl dependency before the build is started. I don't own the boringssl dependency, I'm just using it.

It's ok, I think I'll just file a bug for this. Thanks for the help.

Now I am very curious! :smiley: How are you going to pass local ENV(s) into a dependency that you don't own? What I mean is: what would be the expected behavior of this procedure?

I've created an issue with more detail: Support per-target environment variables · Issue #11385 · rust-lang/cargo · GitHub

1 Like