R8. Each package should provide pre-processor macros that allow for version comparison (for languages that support it - like C/C++/Fortran). Using these macros, dependent software can potentially be compatible with multiple versions of the package.
Example implementations for a given package version 1.2.3
- Example 1: provide version macros only, via public include files (or can be done easily via CMake)
#define <PACKAGE>_VERSION_MAJOR 1
#define <PACKAGE>_VERSION_MINOR 2
#define <PACKAGE>_VERSION_PATCH 3
- Example 2: provide a single integer version macro to encode major, minor, patch version
#define <PACKAGE>_VERSION 1002003
Additional comparison macros can help usage
- With Example 1 (via public include files)
#define <PACKAGE>_VERSION_GE(Major, Minor, Patch) \
(((Major == <PACKAGE>_VERSION_MAJOR) && (Minor == <PACKAGE>_VERSION_MINOR) && (Patch <= <PACKAGE>_VERSION_PATCH)) || \
((Major == <PACKAGE>_VERSION_MAJOR) && (Minor < <PACKAGE>_VERSION_MINOR)) || (Major < <PACKAGE>_VERSION_MAJOR))
#define <PACKAGE>_VERSION_GT(Major, Minor, Patch) \
(((Major == <PACKAGE>_VERSION_MAJOR) && (Minor == <PACKAGE>_VERSION_MINOR) && (Patch < <PACKAGE>_VERSION_PATCH)) || \
((Major == <PACKAGE>_VERSION_MAJOR) && (Minor < <PACKAGE>_VERSION_MINOR)) || (Major < <PACKAGE>_VERSION_MAJOR))
#define <PACKAGE>_VERSION_EQ(Major, Minor, Patch) \
((Major == <PACKAGE>_VERSION_MAJOR) && (Minor == <PACKAGE>_VERSION_MINOR) && (Patch == <PACKAGE>_VERSION_PATCH))
#define <PACKAGE>_VERSION_LE(Major, Minor, Patch) \
!<PACKAGE>_VERSION_GT(Major, Minor, Patch)
#define <PACKAGE>_VERSION_LT(Major, Minor, Patch) \
!<PACKAGE>_VERSION_GE(Major, Minor, Patch)
- With Example 2 (via public include files)
#define <PACKAGE>_VERSION_GE(Major, Minor, Patch) \
(Major * 10000 + Minor * 100 + Patch <= <PACKAGE>_VERSION)
#define <PACKAGE>_VERSION_GT(Major, Minor, Patch) \
(Major * 10000 + Minor * 100 + Patch < <PACKAGE>_VERSION)
#define <PACKAGE>_VERSION_LE(Major, Minor, Patch) \
!<PACKAGE>_VERSION_GT(Major, Minor, Patch)
#define <PACKAGE>_VERSION_LT(Major, Minor, Patch) \
!<PACKAGE>_VERSION_GE(Major, Minor, Patch)
Implementations that are NOT acceptable include:
-
providing a string
#define <PACKAGE>_VERSION "1.2.3"
(as string version comparisons are not easy) -
expecting the user to "know" the version or expecting the user to manually edit source-code
-
requiring the use of external tools such as CMake or git (on the user application or library side) to generate and access package version macros
-
not having "namespaced" macros (as they could conflict with macros defined in other packages, using packagename as a prefix can avoid this issue)