One thing that has always bugged me with Rust is when you are interacting with complex non-Rust software. Yes LLVM, I’m looking at you! LLVM nearly always requires you to either a) have llvm-config on the path already, or b) find an LLVM install in some random place on the filesystem. I generally like to have a version of LLVM built myself (using RelWithDebInfo and forcing asserts on) that will naturally live at some arbitrary point in the filesystem - and then I want to somehow point my Rust code that is using LLVM at that folder.

The general way to do this in Rust is to use an environment variable, and then in a build.rs you can grab all the paths to the LLVM libraries for linking in.

For instance the llvm-sys crate has an optional feature no-llvm-linking that lets you control where LLVM is sourced from. I use this in a project I’m cooking up to control how LLVM is brought into my project. At present my workflow is something like:

LLVM_INSTALL_DIR=llvm-install cargo test
cargo clippy

If you can see the problem already - when I run other commands on auto-pilot like running cargo clippy, and I do not specify the LLVM_INSTALL_DIR, the command fails to run because it requires LLVM_INSTALL_DIR to be specified.

Coming from a primarily CMake based workflow with my day-to-day job working with LLVM, this completely does my head in. CMake has a way to cache variables and then subsequent commands re-use the cached value. So I got thinking - why can’t I do something similar in Rust?

I’d like to introduce a simple, dumb, but useful little crate - envcache. This crate lets you cache any environment variables you want so they can be used across cargo commands. For example, in a build.rs:

extern crate envcache;

use envcache::EnvCache;

fn main() {
    let mut envcache = EnvCache::new();
    envcache.cache("LLVM_INSTALL_DIR");
}

By doing this simple thing above, it’ll let me specify LLVM_INSTALL_DIR once, and then have this cached value used thereafter for subsequent commands.

This works by saving a file in the OUT_DIR that you can write to with build.rs - envcache.config. Crucially this means that if you run cargo clean it’ll wipe out the cache, and you’ll need to re-specify the environment variable. But it does mean you have to specify the environment variable much less in general development which I find to be much nicer.

The source code is available here, and I hope this is useful to some of you.