I’m trying to have a zero in the minor part of version. Step1/CMakeLists.txt is
cmake_policy(SET CMP0096 NEW)
cmake_minimum_required(VERSION 3.22.1)
project(Tutorial VERSION 1.0.3.4
DESCRIPTION "This is a tutorial for cmake"
HOMEPAGE_URL cmake.org
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(TutorialConfig.h.in TutorialConfig.h)
add_executable(tutorial tutorial.cxx)
target_include_directories(tutorial PRIVATE ${PROJECT_BINARY_DIR})
TutorialConfig.h.in is
// the configured options and settings for Tutorial
#cmakedefine PROJECT_NAME "@PROJECT_NAME@"
#cmakedefine PROJECT_VERSION_MAJOR "@PROJECT_VERSION_MAJOR@"
#cmakedefine PROJECT_VERSION_MINOR "@PROJECT_VERSION_MINOR@"
#cmakedefine Tutorial_VERSION_MAJOR "@Tutorial_VERSION_MAJOR@"
#cmakedefine Tutorial_VERSION_MINOR "@Tutorial_VERSION_MINOR@"
But this produces undefined minor version numbers in TutorialConfig.h
// the configured options and settings for Tutorial
#define PROJECT_NAME "Tutorial"
#define PROJECT_VERSION_MAJOR "1"
/* #undef PROJECT_VERSION_MINOR */
#define Tutorial_VERSION_MAJOR "1"
/* #undef Tutorial_VERSION_MINOR */
Reading documentation it say old behaviour is to remove lead zeros from version numbers. Does this mean if it is only zero then it removes it entirely? I saw CMP0096 in policy options. Will this fix the problem and if so then how do I use it?
If I set the version to 1.2.3.4 it works and gives me version_minor variables and #defines correctly.
Using version 1.0.3.4 causes the problem. adding or removing the
cmake_policy(SET CMP0096 NEW)
line has no effect.
cmake --version
gives
cmake version 3.22.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
Thanks for your help explaining this.
Wow! That behaviour is unexpectedly crap. What could possibly be the rationale?
It means that whenever anyone defines a cmake variable that might have the value zero, and they want to use it in c++ code they then have to do something like
#cmakedefine VAR @VAR@
#ifndef VAR
# define VAR 0
#endif
And a similar kind of thing for all the other constants interpreted to be false (and there are a lot of them).
Unless there is some more elegant alternative?
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
I got it to work with:
// the configured options and settings for Tutorial
#cmakedefine Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#ifndef Tutorial_VERSION_MAJOR
# define Tutorial_VERSION_MAJOR 0
#endif
#cmakedefine Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#ifndef Tutorial_VERSION_MINOR
# define Tutorial_VERSION_MINOR 0
#endif
Looking at the code in cmProjectCommand.cxx for parsing the version number: a regular expression and sscanf… Hmmmm… At least it gets the right result before #cmakedefine throws it away.
Here’s an example taken from my Professional CMake book which may be of interest. It uses +0 in strategic places to conveniently handle version number components which might not be set. It has no problem with them being set to zero either.
Something else to consider. If you are using #define to provide your version numbers, I’m assuming you’re putting that in header files. This has the drawback that every time you change the version, all files that pull in that header will need to be rebuilt, even if nothing else in the header changes. A more build-friendly way to structure things is to provide the version details through functions like those in the example of my previous comment. In your header file, you just have function prototypes which never change. Only your private .cpp file implementation sees the changing version numbers, so only that .cpp file needs to be recompiled. With this arrangement, everyone who uses your library only needs to recompile the parts of their project which are affected by a change in your API. If your API doesn’t change, just its implementation, all a consuming project has to do is relink.
I’ll add that sometimes it is useful to provide compilation and runtime version information. Most users will care about runtime, but sometimes compile-time can matter.
Also, this seems to come from the tutorial, so maybe this can be better presented.
A -config.cmake file could provide the version details directly (so it can be made available at compile time), since it knows what package version it corresponds to. A Find module can’t do that, so there’s another reason to prefer a -config.cmake over a Find module.