Compile-time configuration of installation directories

Viewed 81

The autotools are providing a suite of utilities allowing the developer to configure the source code during compilation specifically to ease packaging.

One of the capabilities is the definition of several installation directory variables set during compilation and which avoids making assumptions on where the application is to be installed.

For example:

Variable Default
prefix /usr/local
datarootdir ${prefix}/share
sysconfdir ${prefix}/etc
localstatedir ${prefix}/var
...

How to mimic this behavior in Rust at compile time? Is there any existing standard or best practices for such need?

I'd like to make use of system paths but without having them fully hard-coded and allowing the packager to customize part of it.

1 Answers

You can use the std::env or std::option_env! macros to get an environment variable at compile time. This can be used to set install variables as environment variables when building your program.

If you want to additionally set defaults conveniently, here's a macro:

/// Get an environment variable during compile time, else return a default
macro_rules! env_or {
    ($name:expr, $default:expr) => {
        // This is needed because `Option.unwrap_or` is not a const fn:
        // https://github.com/rust-lang/rust/issues/91930
        if let Some(value) = option_env!($name) {
            value
        } else {
            $default
        }
    };
}

You can use this as follows:

const PREFIX: &str = env_or!("PREFIX", "/usr/local");

To concatenate PREFIX and /share, you can use the concatcp macro from the const_format crate as follows:

const DATAROOTDIR: &str = const_format::concatcp!(PREFIX, "/share");
Related