Skip to content

Commit 2e2c3bd

Browse files
hjmjohnsonblowekamp
andcommitted
ENH: Auto-compute ITK_VERSION_TWEAK from git commit date
Set the fourth (tweak) version component at configure time to the YYYYMMDD date of the most recent commit, instead of a hand-edited date. The computation is pure CMake, so a native build gains no interpreter dependency: `.git_archival.txt` is read first, so an exported tarball -- or a fork that commits a substituted file -- pins the date it declares, and a working tree falls through to `git log`, which succeeds even in a shallow or tagless clone. ITK_VERSION_TWEAK and ITK_VERSION_FULL are exported through ITKConfig.cmake for downstream between-tag gating. The value never reaches itkConfigure.h, so the daily change cannot invalidate ccache. Supersedes the manual-file approach of #6667. Co-Authored-By: Bradley Lowekamp <321061+blowekamp@users.noreply.github.com>
1 parent c8d0f07 commit 2e2c3bd

7 files changed

Lines changed: 119 additions & 2 deletions

File tree

.git_archival.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node: $Format:%H$
2+
node-date: $Format:%cI$
3+
describe-name: $Format:%(describe:tags=true,match=v[0-9]*)$
4+
ref-names: $Format:%D$

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
.git* export-ignore
22
.hooks* export-ignore
33
.mailmap export-ignore
4+
# Override the .git* export-ignore above: this file MUST ship in archives, and
5+
# git substitutes the describe string into it so tarballs compute the tweak.
6+
.git_archival.txt -export-ignore export-subst
47

58
*.bat -crlf
69
*.bin -crlf

CMake/ITKConfig.cmake.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ set(ITK_REQUIRED_LINK_FLAGS "@ITK_REQUIRED_LINK_FLAGS@")
2525
set(ITK_VERSION_MAJOR "@ITK_VERSION_MAJOR@")
2626
set(ITK_VERSION_MINOR "@ITK_VERSION_MINOR@")
2727
set(ITK_VERSION_PATCH "@ITK_VERSION_PATCH@")
28+
# Tweak is the YYYYMMDD date of the most recent commit; enables fine-grained
29+
# downstream gating between release tags via ITK_VERSION_FULL.
30+
set(ITK_VERSION_TWEAK "@ITK_VERSION_TWEAK@")
31+
set(
32+
ITK_VERSION_FULL
33+
"@ITK_VERSION_MAJOR@.@ITK_VERSION_MINOR@.@ITK_VERSION_PATCH@.@ITK_VERSION_TWEAK@"
34+
)
2835

2936
# Remove all legacy code completely.
3037
set(ITK_LEGACY_REMOVE "@ITK_LEGACY_REMOVE@")

CMake/ITKConfigVersion.cmake.in

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
set(PACKAGE_VERSION "@ITK_VERSION_MAJOR@.@ITK_VERSION_MINOR@.@ITK_VERSION_PATCH@")
1+
set(
2+
PACKAGE_VERSION
3+
"@ITK_VERSION_MAJOR@.@ITK_VERSION_MINOR@.@ITK_VERSION_PATCH@.@ITK_VERSION_TWEAK@"
4+
)
25
if(NOT "${PACKAGE_FIND_VERSION}" VERSION_GREATER "${PACKAGE_VERSION}")
36
set(PACKAGE_VERSION_COMPATIBLE 1) # compatible with older
4-
if("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}")
7+
if(
8+
"${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}"
9+
OR "${PACKAGE_FIND_VERSION}" VERSION_EQUAL
10+
"@ITK_VERSION_MAJOR@.@ITK_VERSION_MINOR@.@ITK_VERSION_PATCH@"
11+
)
512
set(PACKAGE_VERSION_EXACT 1) # exact match for this version
613
endif()
714
endif()

CMake/itkVersionTweak.cmake

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Compute ITK_VERSION_TWEAK: the YYYYMMDD date of the most recent commit, at
2+
# configure time. The tweak must never reach itkConfigure.h, so a per-commit
3+
# change of this value cannot invalidate ccache.
4+
#
5+
# .git_archival.txt is consulted before git so that an archive, or a fork that
6+
# commits a substituted file, pins the date it declares. In this repository the
7+
# file holds unexpanded $Format:$ placeholders, so a working tree falls through
8+
# to `git log`, which succeeds even in a shallow or tagless clone.
9+
function(_itk_version_tweak_from_date date outvar)
10+
if(date MATCHES "([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])")
11+
set(
12+
${outvar}
13+
"${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}"
14+
PARENT_SCOPE
15+
)
16+
else()
17+
set(${outvar} "" PARENT_SCOPE)
18+
endif()
19+
endfunction()
20+
21+
function(_itk_compute_version_tweak outvar)
22+
set(tweak "")
23+
24+
if(EXISTS "${ITK_SOURCE_DIR}/.git_archival.txt")
25+
file(
26+
STRINGS
27+
"${ITK_SOURCE_DIR}/.git_archival.txt"
28+
archival
29+
REGEX "^node-date:"
30+
)
31+
if(archival)
32+
list(GET archival 0 node_date)
33+
# Unexpanded placeholders mean this is a checkout, not an archive.
34+
if(NOT node_date MATCHES "\\$Format:")
35+
_itk_version_tweak_from_date("${node_date}" tweak)
36+
endif()
37+
endif()
38+
endif()
39+
40+
if(NOT tweak MATCHES "^[0-9]+$")
41+
find_package(Git QUIET)
42+
if(Git_FOUND)
43+
execute_process(
44+
COMMAND
45+
"${GIT_EXECUTABLE}" -C "${ITK_SOURCE_DIR}" log -1 --format=%cd
46+
--date=short
47+
OUTPUT_VARIABLE commit_date
48+
OUTPUT_STRIP_TRAILING_WHITESPACE
49+
ERROR_QUIET
50+
)
51+
_itk_version_tweak_from_date("${commit_date}" tweak)
52+
endif()
53+
endif()
54+
55+
# Neither archive metadata nor git history, e.g. an unpacked plain tarball.
56+
if(NOT tweak MATCHES "^[0-9]+$")
57+
set(tweak "0")
58+
endif()
59+
set(${outvar} "${tweak}" PARENT_SCOPE)
60+
endfunction()
61+
62+
_itk_compute_version_tweak(ITK_VERSION_TWEAK)
63+
set(ITK_VERSION_FULL "${ITK_VERSION}.${ITK_VERSION_TWEAK}")

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ project(
6767
C
6868
)
6969

70+
# Fourth (tweak) version component, auto-computed as the YYYYMMDD date of the
71+
# most recent commit. Enables downstream between-tag gating via
72+
# ITK_VERSION_FULL; see Documentation/docs/migration_guides/index.md.
73+
include(itkVersionTweak)
74+
7075
# Required as a cache variable for FetchContent parent projects can
7176
# resolve ITK's CMake macros and config paths.
7277
set(

Documentation/docs/migration_guides/index.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
These migration guides explain how to update major versions of ITK, whic may contain breaking changes to the API.
44

5+
## Fine-grained versioning between release tags
6+
7+
ITK's fourth (tweak) version component is the `YYYYMMDD` date of the most
8+
recent commit, computed automatically at configure time. It exists so
9+
downstream projects building against untagged ITK commits — for example during
10+
a `git bisect` — can make configure-time decisions at day granularity between
11+
release tags:
12+
13+
```cmake
14+
find_package(ITK REQUIRED)
15+
if(ITK_VERSION_FULL VERSION_GREATER_EQUAL 6.0.0.20260722)
16+
set(BASELINE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Baseline/post-change)
17+
else()
18+
set(BASELINE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Baseline/legacy)
19+
endif()
20+
```
21+
22+
`ITK_VERSION_FULL` and `ITK_VERSION_TWEAK` are exported through
23+
`ITKConfig.cmake`. Against an older ITK that predates the tweak component,
24+
`ITK_VERSION_FULL` is unset and the comparison is false, so the legacy branch
25+
is taken.
26+
27+
The date comes from `git log` in a working tree — including a shallow or
28+
tagless clone — and from the `git archive`-substituted `.git_archival.txt` in
29+
an exported source tarball; it falls back to `0` only when neither git history
30+
nor that substitution is available. No manual edits are needed — the tweak
31+
advances with every commit.
32+
533
```{toctree}
634
:hidden:
735
:maxdepth: 3

0 commit comments

Comments
 (0)