Dealing with transitive dependencies of native libraries


I’m writing a Rust binding for a native library and I made a mistake of delving too deep into various theoretical linking issues.

The library itself is a wrapper over other native cryptographic library. It can depend on either OpenSSL, LibreSSL, or BoringSSL (the choice is made at build-time).

Currently I have factored raw FFF bindings into a sys crate, but I struggle to find an ideal way of linking to the native library and its dependencies. My sys crate does not depend on openssl-sys, for example. But I guess it should? At least, the Cargo book suggests so. However, what if the native library depends on LibreSSL or BoringSSL? Or what if OpenSSL in openssl-sys is different from the one expected by the library? How should I deal with static vs. dynamic linking of the library and its dependencies?

Are there any best practices is this area? (Aside from rewriting everything in Rust.)

There is the option to specify features, where the user of the lib can specify which features he wants to include. You could hide all those interchangeable dependencies behind such a feature and conditional-compile certain code only if feature xy is enabled. Then you declare some features as default ones. Then if the user just specifies your lib as a dependency, he gets your default set, but he can also choose to opt out of these default features and specify the alternative instead. Have a look into the UUID or Chrono crates (these are the ones that just popped up in my head using features)
They use it for example to include (serde) serialization for their types of the user uses serde, but leave it out if not needed. I think this pretty precisely matches your problem case :slight_smile: