project: Keep leading 0 in PROJECT_VERSION components

Introduce CMake policy `CMP0096` to make `project()` keep leading zeros
in version components.  As a side effect, it now allows really long
version numbers.

Fixes: #19421
Co-Author: Brad King <brad.king@kitware.com>
This commit is contained in:
Alex Turbov
2019-07-16 07:48:40 -04:00
committed by Brad King
parent 5f84669806
commit 0ba5891ead
13 changed files with 186 additions and 29 deletions
+1
View File
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.16
.. toctree::
:maxdepth: 1
CMP0096: project() preserves leading zeros in version components. </policy/CMP0096>
CMP0095: RPATH entries are properly escaped in the intermediary CMake install script. </policy/CMP0095>
Policies Introduced by CMake 3.15
+25
View File
@@ -0,0 +1,25 @@
CMP0096
-------
The :command:`project` command preserves leading zeros in version components.
When a ``VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]`` argument is given
to the :command:`project` command, it stores the version string in the
``PROJECT_VERSION`` variable and stores individual integer version components
in ``PROJECT_VERSION_{MAJOR,MINOR,PATCH,TWEAK}`` variables (see policy
:policy:`CMP0048`). CMake 3.15 and below dropped leading zeros from each
component. CMake 3.16 and higher prefer to preserve leading zeros. This
policy provides compatibility for projects that have not been updated to
expect the new behavior.
The ``OLD`` behavior of this policy drops leading zeros in all components,
e.g. such that version ``1.07.06`` becomes ``1.7.6``. The ``NEW`` behavior
of this policy preserves the leading zeros in all components, such that
version ``1.07.06`` remains unchanged.
This policy was introduced in CMake version 3.16. Unlike many policies, CMake
version |release| does *not* warn when this policy is not set and simply uses
the ``OLD`` behavior. Use the :command:`cmake_policy` command to set it to
``OLD`` or ``NEW`` explicitly.
.. include:: DEPRECATED.txt
+5
View File
@@ -0,0 +1,5 @@
project-version-0
-----------------
* The :command:`project` no longer strips leading zeros in version components.
See policy :policy:`CMP0096`.
+4 -1
View File
@@ -283,7 +283,10 @@ class cmMakefile;
SELECT(POLICY, CMP0095, \
"RPATH entries are properly escaped in the intermediary CMake " \
"install script.", \
3, 16, 0, cmPolicies::WARN)
3, 16, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0096, \
"project() preserves leading zeros in version components.", 3, 16, \
0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
+56 -28
View File
@@ -3,9 +3,12 @@
#include "cmProjectCommand.h"
#include "cmsys/RegularExpression.hxx"
#include <array>
#include <cstdio>
#include <functional>
#include <limits>
#include <sstream>
#include <stdio.h>
#include <utility>
#include "cmAlgorithms.h"
#include "cmMakefile.h"
@@ -220,44 +223,69 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args,
return true;
}
cmPolicies::PolicyStatus const cmp0096 =
this->Makefile->GetPolicyStatus(cmPolicies::CMP0096);
constexpr std::size_t MAX_VERSION_COMPONENTS = 4u;
std::string vs;
char vb[MAX_VERSION_COMPONENTS][64];
unsigned int v[MAX_VERSION_COMPONENTS] = { 0, 0, 0, 0 };
int vc =
sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]);
for (auto i = 0u; i < MAX_VERSION_COMPONENTS; ++i) {
if (int(i) < vc) {
sprintf(vb[i], "%u", v[i]);
vs += &"."[size_t(i == 0)];
vs += vb[i];
} else {
vb[i][0] = 0;
std::string version_string;
std::array<std::string, MAX_VERSION_COMPONENTS> version_components;
if (cmp0096 == cmPolicies::OLD || cmp0096 == cmPolicies::WARN) {
char vb[MAX_VERSION_COMPONENTS][std::numeric_limits<unsigned>::digits10];
unsigned v[MAX_VERSION_COMPONENTS] = { 0, 0, 0, 0 };
const int vc = std::sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1],
&v[2], &v[3]);
for (auto i = 0u; i < MAX_VERSION_COMPONENTS; ++i) {
if (int(i) < vc) {
std::sprintf(vb[i], "%u", v[i]);
version_string += &"."[std::size_t(i == 0)];
version_string += vb[i];
version_components[i] = vb[i];
} else {
vb[i][0] = '\x00';
}
}
} else {
// The regex above verified that we have a .-separated string of
// non-negative integer components. Keep the original string.
version_string = std::move(version);
// Split the integer components.
auto components = cmSystemTools::SplitString(version_string, '.');
for (auto i = 0u; i < components.size(); ++i) {
version_components[i] = std::move(components[i]);
}
}
std::string vv;
vv = projectName + "_VERSION";
this->Makefile->AddDefinition("PROJECT_VERSION", vs.c_str());
this->Makefile->AddDefinition(vv, vs.c_str());
this->Makefile->AddDefinition("PROJECT_VERSION", version_string.c_str());
this->Makefile->AddDefinition(vv, version_string.c_str());
vv = projectName + "_VERSION_MAJOR";
this->Makefile->AddDefinition("PROJECT_VERSION_MAJOR", vb[0]);
this->Makefile->AddDefinition(vv, vb[0]);
this->Makefile->AddDefinition("PROJECT_VERSION_MAJOR",
version_components[0].c_str());
this->Makefile->AddDefinition(vv, version_components[0].c_str());
vv = projectName + "_VERSION_MINOR";
this->Makefile->AddDefinition("PROJECT_VERSION_MINOR", vb[1]);
this->Makefile->AddDefinition(vv, vb[1]);
this->Makefile->AddDefinition("PROJECT_VERSION_MINOR",
version_components[1].c_str());
this->Makefile->AddDefinition(vv, version_components[1].c_str());
vv = projectName + "_VERSION_PATCH";
this->Makefile->AddDefinition("PROJECT_VERSION_PATCH", vb[2]);
this->Makefile->AddDefinition(vv, vb[2]);
this->Makefile->AddDefinition("PROJECT_VERSION_PATCH",
version_components[2].c_str());
this->Makefile->AddDefinition(vv, version_components[2].c_str());
vv = projectName + "_VERSION_TWEAK";
this->Makefile->AddDefinition("PROJECT_VERSION_TWEAK", vb[3]);
this->Makefile->AddDefinition(vv, vb[3]);
this->Makefile->AddDefinition("PROJECT_VERSION_TWEAK",
version_components[3].c_str());
this->Makefile->AddDefinition(vv, version_components[3].c_str());
// Also, try set top level variables
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION", vs.c_str());
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_MAJOR", vb[0]);
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_MINOR", vb[1]);
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_PATCH", vb[2]);
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_TWEAK", vb[3]);
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION", version_string.c_str());
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_MAJOR",
version_components[0].c_str());
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_MINOR",
version_components[1].c_str());
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_PATCH",
version_components[2].c_str());
TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_TWEAK",
version_components[3].c_str());
} else if (cmp0048 != cmPolicies::OLD) {
// Set project VERSION variables to empty
std::vector<std::string> vv = { "PROJECT_VERSION",
@@ -0,0 +1,30 @@
-- PROJECT_VERSION='2019.07.06'
-- DateVersion_VERSION='2019.07.06'
-- PROJECT_VERSION_MAJOR='2019'
-- DateVersion_VERSION_MAJOR='2019'
-- PROJECT_VERSION_MINOR='07'
-- DateVersion_VERSION_MINOR='07'
-- PROJECT_VERSION_PATCH='06'
-- DateVersion_VERSION_PATCH='06'
-- PROJECT_VERSION_TWEAK=''
-- DateVersion_VERSION_TWEAK=''
-- PROJECT_VERSION='4294967297'
-- LongVersion_VERSION='4294967297'
-- PROJECT_VERSION_MAJOR='4294967297'
-- LongVersion_VERSION_MAJOR='4294967297'
-- PROJECT_VERSION_MINOR=''
-- LongVersion_VERSION_MINOR=''
-- PROJECT_VERSION_PATCH=''
-- LongVersion_VERSION_PATCH=''
-- PROJECT_VERSION_TWEAK=''
-- LongVersion_VERSION_TWEAK=''
-- PROJECT_VERSION='0009999999999.0009999999999.0009999999999.0009999999999'
-- VeryLongVersion_VERSION='0009999999999.0009999999999.0009999999999.0009999999999'
-- PROJECT_VERSION_MAJOR='0009999999999'
-- VeryLongVersion_VERSION_MAJOR='0009999999999'
-- PROJECT_VERSION_MINOR='0009999999999'
-- VeryLongVersion_VERSION_MINOR='0009999999999'
-- PROJECT_VERSION_PATCH='0009999999999'
-- VeryLongVersion_VERSION_PATCH='0009999999999'
-- PROJECT_VERSION_TWEAK='0009999999999'
-- VeryLongVersion_VERSION_TWEAK='0009999999999'
+6
View File
@@ -0,0 +1,6 @@
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0096 NEW)
include(CMP0096-common.cmake)
project(VeryLongVersion VERSION 0009999999999.0009999999999.0009999999999.0009999999999 LANGUAGES NONE)
print_versions(VeryLongVersion)
@@ -0,0 +1,20 @@
-- PROJECT_VERSION='2019.7.6'
-- DateVersion_VERSION='2019.7.6'
-- PROJECT_VERSION_MAJOR='2019'
-- DateVersion_VERSION_MAJOR='2019'
-- PROJECT_VERSION_MINOR='7'
-- DateVersion_VERSION_MINOR='7'
-- PROJECT_VERSION_PATCH='6'
-- DateVersion_VERSION_PATCH='6'
-- PROJECT_VERSION_TWEAK=''
-- DateVersion_VERSION_TWEAK=''
-- PROJECT_VERSION='(1|4294967295)'
-- LongVersion_VERSION='(1|4294967295)'
-- PROJECT_VERSION_MAJOR='(1|4294967295)'
-- LongVersion_VERSION_MAJOR='(1|4294967295)'
-- PROJECT_VERSION_MINOR=''
-- LongVersion_VERSION_MINOR=''
-- PROJECT_VERSION_PATCH=''
-- LongVersion_VERSION_PATCH=''
-- PROJECT_VERSION_TWEAK=''
-- LongVersion_VERSION_TWEAK=''
+3
View File
@@ -0,0 +1,3 @@
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0096 OLD)
include(CMP0096-common.cmake)
@@ -0,0 +1,20 @@
-- PROJECT_VERSION='2019.7.6'
-- DateVersion_VERSION='2019.7.6'
-- PROJECT_VERSION_MAJOR='2019'
-- DateVersion_VERSION_MAJOR='2019'
-- PROJECT_VERSION_MINOR='7'
-- DateVersion_VERSION_MINOR='7'
-- PROJECT_VERSION_PATCH='6'
-- DateVersion_VERSION_PATCH='6'
-- PROJECT_VERSION_TWEAK=''
-- DateVersion_VERSION_TWEAK=''
-- PROJECT_VERSION='(1|4294967295)'
-- LongVersion_VERSION='(1|4294967295)'
-- PROJECT_VERSION_MAJOR='(1|4294967295)'
-- LongVersion_VERSION_MAJOR='(1|4294967295)'
-- PROJECT_VERSION_MINOR=''
-- LongVersion_VERSION_MINOR=''
-- PROJECT_VERSION_PATCH=''
-- LongVersion_VERSION_PATCH=''
-- PROJECT_VERSION_TWEAK=''
-- LongVersion_VERSION_TWEAK=''
@@ -0,0 +1,3 @@
cmake_policy(SET CMP0048 NEW)
include(CMP0096-common.cmake)
@@ -0,0 +1,9 @@
include(PrintVersions.cmake)
# Test leading zeros motivating this policy.
project(DateVersion VERSION 2019.07.06 LANGUAGES NONE)
print_versions(DateVersion)
# Overflow version component in OLD behavior.
project(LongVersion VERSION 4294967297 #[[ uint32_max + 2 ]] LANGUAGES NONE)
print_versions(LongVersion)
@@ -27,3 +27,7 @@ run_cmake(CMP0048-OLD)
run_cmake(CMP0048-OLD-VERSION)
run_cmake(CMP0048-WARN)
run_cmake(CMP0048-NEW)
run_cmake(CMP0096-WARN)
run_cmake(CMP0096-OLD)
run_cmake(CMP0096-NEW)