How to conditionally compile if function/type exists?


#1

Is it possible to conditionally compile based on whether a function, type definition, etc. exists? For example, I’m thinking something along the lines of:

#[cfg(defined(foo::bar2))]
fn my_function() {
    /* use foo::bar2 */
}

#[cfg(not(defined(foo::bar2)))]
fn my_function() {
    /* use foo::bar as a fallback */
}

My goal here is interfacing with a system-installed C library and being able at compile-time to use new functions and types from that library while falling back to using older, more widely distributed functions and types as needed.


#2

No.

Conditional compilation happens at the syntactic level, before that information even exists. If you want a conditional compilation switch, you need to use a Cargo feature, or have a build script define a cfg flag.

Now, a build script can generate metadata that dependents can see. So, if the build script for the C library exports some metadata including the version of the library, your build script can read that and define cfg flags to enable/disable use of individual functions. Probably. I haven’t actually tried that before.


#3

The idiomatic way of doing this is with cargo features. Instead of checking whether a single function is defined or not, you’ll enable/disable types and functions depending on whether the corresponding feature is enabled/disabled. The reasoning is that this lets you work at a much higher level of abstraction.

As an example, imagine if you wanted to use some web client library and needed to remember to enable the ssl_verify() function and everything it uses, just to go to HTTPS sites. Whereas with features you’d just enable the ssl feature in your Cargo.toml.


#4

Thank you for the replies.

I suppose what I want is a build script that provides the autoconf/CMake/etc. behavior of generating a test program that uses the system library function I want, trying to compile the program, and generating a config module based on result of that attempted compilation. (I.e., something similar to the HAVE_FOO2 idiom in the C/C++ world.) I did a cursory search on crates.io for any crates to help with this but didn’t find anything other than the gcc crate as maybe a building block for doing this manually.

I understand that Cargo features are the idiomatic way of doing conditional compilation in Rust, but, in my case, a Cargo feature would just pass the buck up to my crate’s dependents, who would then need to determine whether the target system’s libraries are new enough to support the Cargo feature.


#5

Like others are saying Cargo features are ideal but these come before build.
To do what you want you can have your build.js create include! file(s).