How can I set CC and AR environment variables programmatically based on the OS and path presence?

Due to WASM nuance, I have a situation where CC and AR environment variables should only be set in MacOS, only if a specific path is found (basically, if llvm is installed with brew). Otherwise, they shouldn't be set. Is there a way to do this in cargo or build.rs or something?

Edit: This is to build the crate secp256k1. Attempting to build it on MacOS with cargo build --target=wasm32-wasip1 without these env vars (and without llvm being installed with brew) causes issues, because the underlying C library doesn't compile by using the default clang compiler.

You can use CC_wasm32-wasip1 to set set a C compiler that is only used when building for wasm32-wasip1.

That doesn't work, because there has to be programming logic in this. I have to check whether a specific CC exists, and it has to be done only in MacOS.

I'm afraid with these requirements your best option is to write a shell script (or in a language of your choice) that determines these values, sets the variables and ultimately runs cargo build.

The sys crate is built using the cc crate, so it has its own build script that can have custom compiler detection/workaround logic. File bugs with the sys crate to add whatever logic is needed, so that it will work for everybody using the crate, not just for your project.

If the issue with compiler detection affects C/wasm in general, then file issues with the cc crate to improve its compiler detection logic.

This isn't really a valid solution because IDEs (like VSCode) will need manual configuration of parameters, which is really annoying. The beauty of Rust is that you can open any project and it just works.

There is no problem in the default building behavior (AFAIU). The problem is in MacOS. The problem is that the default clang that comes with MacOS does not support wasm targets. So, we have to install a version of clang that supports wasm from brew (using brew install llvm), but then Cargo by default detects clang from PATH, which is in the OS. Given all that, the only way to fix the issue and make Cargo use the proper CC, i.e., clang that comes from brew's llvm, is to override the environment variable CC and AR. I don't believe there's a bug in the sys crate or cc... please let me know if I'm not thinking correctly about this.

So, what I want is: Try to detect CC from llvm, since it has a universal path. If that doesn't work, then we use the default CC in the OS, and all this is only needed in MacOS. Any suggestions are welcome.

It's perfectly normal for Rust sys crates to have dedicated workarounds for macOS's compilers, specific quirks of Homebrew, bugs in WASM support, and other issues that affect specific combinations of libraries and compilers. It's not about pointing out whose fault is it, it's about making the code work anyway.

openssl-sys has workarounds for homebrew, ffmpeg-sys has workarounds for libclang and problematic C headers, and the cc crate will parse Windows registry to find a working MSVC version. They are all full of hacks, so that your cargo build just works and you don't need to know how messy system dependencies are.

I see. I suppose I will attempt to patch it myself in the sys crate of secp256k1 and see if I can fix it, and submit a pull request. Thank you for the information and for your time.

1 Like