Files
source/Ja2/CMakeLists.txt
1e2ce70315 Stamp the build's identity into GameVersion.cpp from CMake
GameVersion.cpp becomes a configure_file template, so the version strings are a
build input rather than something a CI step seds into the working tree mid-run.
That is what lets a crash report be matched to its exact build's PDB for offline
symbolization.

The two strings get distinct jobs. czVersionString is the machine-readable build
identity: the bare short commit SHA and nothing else. A `git describe` string
cannot serve here -- czVersionString is 16 bytes because it is stored in the
savegame header as SAVED_GAME_HEADER::zGameVersionNumber and strcmp'd on load,
and describe puts the SHA last, so truncation ate exactly the discriminating part
and could make two different commits compare equal. CI passes 9 hex; anything
that would not fit is now a configure error rather than a silent clip.

zBuildInformation is the display string, untruncated, and it is no longer printed
beside czVersionString: that drops the duplication in the version line ("JA2 1.13
V4-555-G6A941C0 2026-07-25 V4-555-G6A941C06") and stops showing a token that is
now machine-only. CI's copy leads with GAME_VERSION, because the version line is
now the only place a player reads which release they are running.

Finish what the sed step's TODO asked for: the workflow pins GAME_BUILD_INFORMATION
and GIT_SHA once, next to the gamedir SHAs it already pins, and hands them to CMake
with -D. Every parallel build job therefore stamps one agreed identity, and the
compile checkout needs no git history at all.

A build nobody identifies is a local build and says so -- czVersionString reads
"local" -- rather than deriving a SHA from HEAD. A derived SHA could not stay
true: nothing re-runs configure once HEAD moves, so an incremental build would
keep whatever it was configured with, and keeping it honest would mean
reconfiguring on every commit. It would also buy nothing, because only packaged
builds are archived with their PDBs; a local build's crash reports are symbolized
against the PDB sitting next to the exe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 10:25:47 -03:00

82 lines
3.7 KiB
CMake

# Stamp the build's identity into GameVersion.cpp. Both strings come from the
# caller with -D, and CI passes them: it pins them once, where it decides what the
# release is, so the parallel build jobs cannot stamp identities that disagree.
#
# A build nobody identified is a local build, and says so rather than guessing
# from HEAD. Keeping such a guess honest would mean re-running configure on every
# commit, and it would buy nothing: only what we package is archived with its PDB,
# and a local crash report is symbolized against the PDB next to the exe.
#
# GIT_SHA lands in czVersionString, which is both the savegame compatibility key
# and the crash-report key. It is the bare short SHA and nothing else — a `git
# describe` string cannot serve here, because czVersionString is only 16 bytes and
# describe puts the SHA last, so it is exactly the discriminating part that would
# get clipped off. The budget is 15 chars + NUL: the string is stored in the
# savegame header as SAVED_GAME_HEADER::zGameVersionNumber (GAME_VERSION_LENGTH),
# so its size is a binary format constant and cannot grow. CI passes 9 hex, well
# past what uniqueness needs (git's own auto-abbrev picks 8 for this repo).
# Overshooting it is an error rather than a truncation, because a clipped SHA is
# how two different builds end up claiming to be the same one.
if(NOT GIT_SHA)
set(GIT_SHA "local")
endif()
string(LENGTH "${GIT_SHA}" _length)
if(_length GREATER 15)
message(FATAL_ERROR "GIT_SHA is ${_length} characters; czVersionString holds 15")
endif()
# zBuildInformation is the version line shown on screen, CHAR16[256]. Nothing
# parses it, so it carries the version in full and truncation costs only
# readability.
if(NOT GAME_BUILD_INFORMATION)
string(TIMESTAMP _buildDate "%Y-%m-%d" UTC)
set(GAME_BUILD_INFORMATION "local build ${_buildDate}")
endif()
string(LENGTH "${GAME_BUILD_INFORMATION}" _length)
if(_length GREATER 255)
string(SUBSTRING "${GAME_BUILD_INFORMATION}" 0 255 GAME_BUILD_INFORMATION)
endif()
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/GameVersion.cpp.in"
"${CMAKE_CURRENT_BINARY_DIR}/GameVersion.cpp"
@ONLY)
set(Ja2Src
"${CMAKE_CURRENT_SOURCE_DIR}/aniviewscreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Credits.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Fade Screen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/FeaturesScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GameInitOptionsScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/gameloop.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/gamescreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GameSettings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/GameVersion.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/HelpScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Init.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Intro.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JA2 Splash.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Ja25Update.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/jascreens.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Loading Screen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MainMenuScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MessageBoxScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPChatScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPConnectScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPHostScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPJoinScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPScoreScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MPXmlTeams.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Options Screen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/profiler.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SaveLoadGame.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SaveLoadScreen.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Screens.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Sys Globals.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TimeLogging.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/ub_config.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/XML_DifficultySettings.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/XML_IntroFiles.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/XML_Layout_MainMenu.cpp"
PARENT_SCOPE)