Discovering max API version when building out-of-tree bindings

I’ve been looking to make some small improvements to the build system for our FDB Erlang bindings, one of which is to dynamically set FDB_API_VERSION based on the version of the underlying C library available at build time. As you might expect, the goal is to allow users who have the latest FDB client installed to use the current API, while ensuring the bindings still build successfully without any code changes on systems that are using older versions.

So the question is, what’s the best way to extract the maximum supported version? I see a few options:

  • the 6.3.x releases include pkgconfig metadata for foundationdb-client so we could extract the client version from there and map it to an API version
  • fdbcli --version includes a protocol field like fdb00b062010001 - are the bytes in that field documented? The API Version is certainly buried in there.
  • fdb_c_version.py looks like it is probably an extraction of the dance that fdbcli is doing to derive the protocol version, but it too reports the protocol in this format that is not quite the same as what we need to supply for FDB_API_VERSION

I see other out-of-tree maintainers struggling with similar issues, so I’m hoping we can come up with some best practice that we can apply uniformly across the out-of-tree bindings. My guess would be to parse the protocol field of the fdbcli output.

1 Like

Generally I don’t think setting the FDB_API_VERSION based on the underlying C library is a good idea. Certain API changes include behavior changes for existing functions. In some cases we remove functions when we change the API version… Or in other words: API changes usually require application code changes. There’s nothing wrong with setting the API version to 600 even though you’re running a client that supports 630.

Oh for sure – I’d expect users to set the API version as they see fit, and that’s controlled by a different flag within our binding’s runtime configuration. What I’m trying to do is figure out the right ./configure dance for building our bindings against the installed version of the FoundationDB client, so it can support the widest-possible range of API versions. Does that make sense?

fdb_c_version.py is more or less just calling one of the C functions exposed in our API (fdb_get_client_version) and parsing the version string. If you are happy to do something like this, then there is another function in the C API that you can call instead to report the maximum API version supported: fdb_get_max_api_version.

That said, you need to be sure that your bindings are actually calling the C functions that are present and with the same signature as provided by the API version you select. Presumably if your bindings are not written with a static header API version, then they should be able to choose what C API functions they call based on the chosen version.

Yes we have a handful #if FDB_API_VERSION preprocessor macros scattered through the code that wraps the C client and makes it available to Erlang applications.

Calling fdb_get_max_api_version() in the same manner as fdb_get_client_version() in fdb_c_version.py makes sense and I confirmed it works just fine. Might see if I can do the same thing in an escript to avoid introducing a Python dependency for the build system – although, honestly, we already have one with bindingtester.py so it’s not a big deal. Thanks,

Adam