zeros in version numbers; cmake_policy(SET CMP0096 NEW) ?

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                                                                      
        DESCRIPTION "This is a tutorial for cmake"                                                    
        LANGUAGES CXX)                                                                                
set(CMAKE_CXX_STANDARD 11)                                                                            
set(CMAKE_CXX_STANDARD_REQUIRED True)                                                                 
configure_file( TutorialConfig.h)                                                  
add_executable(tutorial tutorial.cxx)                                                                 
target_include_directories(tutorial PRIVATE ${PROJECT_BINARY_DIR}) 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 it works and gives me version_minor variables and #defines correctly.
Using version causes the problem. adding or removing the

cmake_policy(SET CMP0096 NEW) 

line has no effect.

cmake --version

cmake version 3.22.1

CMake suite maintained and supported by Kitware (

This has nothing to do with policy CMP0096.

Please see the documentation of configure_file:
#cmakedefineany value not considered a false constant by the if() command

The tutorial should not use #cmakedefine here and instead just #define.

Cc: @betsy.mcphail

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                                                                    

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?

It also means the solution to the tutorial Step 1 Exercise 3

// 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                                                                    
#cmakedefine Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@                                          
#ifndef Tutorial_VERSION_MINOR                                                                        
#  define Tutorial_VERSION_MINOR 0                                                                    

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.

Thanks I see it works with

#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ 

The documentation for configure_file lead me down the wrong path mentioning #cmakedefine but not #define.
Apologies for my dimness.

It is there to emulate autoconf’s behavior when configuring files.

There’s nothing special about #define, so there’s nothing really to mention.

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.

std::string getFooBarVersion()
    return "@FooBar_VERSION@";

unsigned getFooBarVersionMajor()
    return @FooBar_VERSION_MAJOR@;

unsigned getFooBarVersionMinor()
    return @FooBar_VERSION_MINOR@ +0;

unsigned getFooBarVersionPatch()
    return @FooBar_VERSION_PATCH@ +0;

unsigned getFooBarVersionTweak()
    return @FooBar_VERSION_TWEAK@ +0;

Yes. It’s now so obvious that #define would work after substitution. God I’ve been so thick.

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.