From c77580f15ef203172fb6d2180f72ed71712689eb Mon Sep 17 00:00:00 2001 From: Denis Arnst Date: Thu, 30 Jul 2026 13:16:20 +0200 Subject: [PATCH] ci: fix git version detection in the MSYS2 Windows job The Windows build has been reporting 0.0.0-unknown, for two independent reasons. Both are verified on a real Windows 11 + MSYS2 MINGW64 box. 1. The MSYS2 shell has no git at all. It is not part of base-devel, and the shell does not inherit Git for Windows from the runner PATH (confirmed: no "/Program Files/Git" entry in the MINGW64 PATH). So every git call in CMakeLists.txt failed. Fixed by installing the git package alongside the toolchain. 2. Once git is available, the --show-toplevel guard added in #551 would still reject every Windows build, permanently pinning it to 0.0.0-unknown. MSYS2 git reports POSIX paths while CMake reports Windows ones, and get_filename_component(REALPATH) does not reconcile them: PROJECT_SOURCE_DIR = C:/Users/Denis/hc-vtest/probe/sub git --show-toplevel = /c/Users/Denis/hc-vtest/probe/sub so the STREQUAL can never match. Replaced with --show-prefix, which is empty exactly when the source dir is the root of a work tree. That is a plain string test needing no path normalisation, and it drops both REALPATH calls. Measured on Windows with the same package set as CI: the old guard yields 0.0.0-unknown, the new one yields 4.0.0-11-g00ca695, a vendored copy correctly falls back to 0.0.0-unknown, and build + ctest pass. Both reject paths now explain themselves and point at -DHEADSETCONTROL_VERSION. Also renames the reused GIT_RESULT to GIT_DESCRIBE_RESULT. --- .github/workflows/build.yml | 9 ++++++++- CMakeLists.txt | 36 +++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6451bf1..18f30ac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,10 @@ jobs: with: msystem: MINGW64 update: true - install: base-devel mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-hidapi + # git is needed for the version detection in CMakeLists.txt; it is not + # part of base-devel and the MSYS2 shell does not inherit Git for + # Windows from the runner PATH. + install: base-devel git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-hidapi # Linux/macOS: Setup CMake and Ninja - name: Setup CMake and Ninja @@ -79,6 +82,10 @@ jobs: - name: Build and test (Windows) if: runner.os == 'Windows' run: | + # Precaution: actions/checkout records safe.directory in the runner + # user's global gitconfig, which the MSYS2 shell may not read because + # it uses a different HOME. + git config --global --add safe.directory "$(pwd)" mkdir build cd build cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. diff --git a/CMakeLists.txt b/CMakeLists.txt index ab2ef82..7e5ff35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,22 +85,32 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(DEFINED HEADSETCONTROL_VERSION AND HEADSETCONTROL_VERSION) set(GIT_VERSION "${HEADSETCONTROL_VERSION}") else() + # Only derive a version from Git when this source tree is itself the root of a + # work tree. --show-prefix is empty exactly in that case, and reports e.g. + # "vendor/HeadsetControl/" when the tree is vendored inside a parent + # repository, so the parent project's version is never picked up. + # + # Do not compare --show-toplevel against PROJECT_SOURCE_DIR instead: MSYS2 git + # reports POSIX paths ("/c/Users/...") while CMake uses Windows ones + # ("C:/Users/..."), REALPATH does not reconcile the two, and the comparison + # therefore never matches in the MinGW build. Testing the prefix is a plain + # string test that needs no path normalisation. execute_process( - COMMAND git rev-parse --show-toplevel + COMMAND git rev-parse --show-prefix WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - OUTPUT_VARIABLE GIT_TOP_LEVEL + OUTPUT_VARIABLE GIT_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET - RESULT_VARIABLE GIT_RESULT + RESULT_VARIABLE GIT_PREFIX_RESULT ) - get_filename_component(HEADSETCONTROL_SOURCE_DIR_REAL - "${PROJECT_SOURCE_DIR}" REALPATH) - get_filename_component(GIT_TOP_LEVEL_REAL "${GIT_TOP_LEVEL}" REALPATH) - - # Do not derive the version from a parent repository when this source tree is - # vendored without its own Git metadata. - if(NOT GIT_RESULT EQUAL 0 - OR NOT GIT_TOP_LEVEL_REAL STREQUAL HEADSETCONTROL_SOURCE_DIR_REAL) + + if(NOT GIT_PREFIX_RESULT EQUAL 0) + message(STATUS "Could not run git in ${PROJECT_SOURCE_DIR}; " + "pass -DHEADSETCONTROL_VERSION to set the version explicitly") + set(GIT_VERSION "0.0.0-unknown") + elseif(NOT GIT_PREFIX STREQUAL "") + message(STATUS "HeadsetControl is vendored inside another git repository; " + "pass -DHEADSETCONTROL_VERSION to set the version explicitly") set(GIT_VERSION "0.0.0-unknown") else() execute_process( @@ -109,11 +119,11 @@ else() OUTPUT_VARIABLE GIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET - RESULT_VARIABLE GIT_RESULT + RESULT_VARIABLE GIT_DESCRIBE_RESULT ) # Fallback if git describe fails (no tags, shallow clone, etc.) - if(NOT GIT_VERSION OR NOT GIT_RESULT EQUAL 0) + if(NOT GIT_VERSION OR NOT GIT_DESCRIBE_RESULT EQUAL 0) execute_process( COMMAND git rev-parse --short HEAD WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"