Closed mapsam closed 7 years ago
Here's how catch.hpp does their versioning: https://github.com/philsquared/Catch/blob/8a2ff209826a9b2f52535577c1567b26e28dfd1a/single_include/catch.hpp#L8319-L8347
👍 My thoughts are that it is important to version the library because:
ifdef
statements to adapt to differences. A version string is not enough in this case since you cannot compare strings in ifdef
macros.So, I feel like both a string and a number (suitable for comparing against) is important. I've done this in https://github.com/mapbox/vector-tile/blob/master/include/mapbox/vector_tile/version.hpp. Macros like VECTOR_TILE_VERSION_MAJOR
can be used like:
#if VECTOR_TILE_VERSION_MAJOR > 2
.... use new API code
#else
.... use pre version 2 code
#endif
Or maybe a feature was just added in release 2.0.1? How would you start using it when v2.0.1 is available?
#if VECTOR_TILE_VERSION_CODE > 20001
... use new feature
#endif
Note: this design comes from boost: http://www.boost.org/doc/libs/1_45_0/boost/version.hpp
Now, header only libraries, by design, are easy to include as dependencies. If a developer has full control over their version then ifdef
statements to control behavior are not needed: instead you just updated your version and make your code adapt to it. The reason you might need ifdefs
is if the header-only library is packaged in a system like debian or ubuntu and exists for years as an official package, and applications start to depend on it. While you might not anticipate this happening, it is out of your control. Adding the abilitity to detect and respond to the version dynamically by downstream applications will make it possible to for developers to use an older package safely and keep things working when they cannot control the version available.
Lastly a string is useful for quick comparisons. In the vector-tile lib it is used to assert on in the unit tests so that you (as the library maintainer) do not forget to update the version when you release: https://github.com/mapbox/vector-tile/blob/master/test/unit/tags.test.cpp
/cc @joto for further thoughts. I notice that libosmium does not have a boost-like combined number - only providing MAJOR, MINOR, and PATCH macros: https://github.com/osmcode/libosmium/blob/master/include/osmium/version.hpp. What this says to me is that downstream users have never needed to be able to do something like #if VECTOR_TILE_VERSION_CODE > 20001
and it has been easy enough to just use the MAJOR, MINOR, and PATCH macros directly.
I think as long as a library sticks to semver such that API breakages are major revisions and new features are minor revisions then using the MAJOR, MINOR, and PATCH directly is enough. Boost probably came up with this combined # because of the complexity over time of new features and bug fixes landing in minor and patch releases.
@springmeyer Both the MAJOR, MINOR, and PATCH macros and the boost versioning with ((MAJOR * 100) + MINOR * 100) + PATCH
or a similar formula are very common in C++ versioning and somewhat interchangeable. As you have guessed, I have just used the first one because it was all I needed. Having a string variant of the version also is useful for printing the version. For instance the version
command of osmium-tool prints the version numbers of osmium and libosmium straight from those macros.
Also while we are on the subject of versioning look at inline namespaces. I have never used them myself though and the only project I know that uses them is boost asio. I tried introducing them into libosmium recently but that experiment failed due to too much code bloat (lots of duplication of code) and general complexity without making things really easy enough for the user. But hat might be different in different cases, so it is good to know this mechanism exists.
Thanks for the info @springmeyer and @joto! I like these approaches, esp the vector-tile version file because of its simplicity and explicitness. I'll try that for now and we can experiment/update as we go.
👍 @mapsam
We have a version file added in #20 but the next step (once merged) is to carry out the plan discussed in the PR:
Per discussion with @springmeyer let's plan on NOT adding to the changelog by versions, but add by date to register changes we've made based on specific learnings. Versioning the hpp-skel is a little confusing, esp because no one in reality will be relying on it directly.
That being said, we'd like to get node-cpp-skel to pull in hpp-skel as an example header library. The plan is to remove the current releases and release 1.0.0 on Mason, make a deliberate API change and release 2.0.0 to mason. This way node-cpp-skel can showcase how to use the version flags appropriately. Once these releases are out we'll continue onward without worrying about documenting changes by version.
A version file was added in #20!
What's the best way to version a C++ header-only library?
cc @springmeyer @GretaCB