From a2854a7740b97f304f9ab38a1f29050b58e13959 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Nov 2025 08:51:22 +0100 Subject: [PATCH] Added cmake modules to integrate version information into Windows DLLs --- cmake/modules/FileVersionInfo.rc.in | 29 +++++++++ cmake/modules/Versioning.cmake | 95 +++++++++++++++++++++++++++++ src/CMakeLists.txt | 2 + 3 files changed, 126 insertions(+) create mode 100644 cmake/modules/FileVersionInfo.rc.in create mode 100644 cmake/modules/Versioning.cmake diff --git a/cmake/modules/FileVersionInfo.rc.in b/cmake/modules/FileVersionInfo.rc.in new file mode 100644 index 0000000..812b1ae --- /dev/null +++ b/cmake/modules/FileVersionInfo.rc.in @@ -0,0 +1,29 @@ +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 + PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "My Company\0" + VALUE "FileDescription", "@PROJECT_NAME@\0" + VALUE "FileVersion", "@PROJECT_VERSION_STRING@\0" + VALUE "ProductVersion", "@PROJECT_VERSION_STRING@\0" + VALUE "GitCommitFull", "@PROJECT_GIT_HASH@\0" + VALUE "GitCommitShort", "@PROJECT_GIT_HASH_SHORT@\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END diff --git a/cmake/modules/Versioning.cmake b/cmake/modules/Versioning.cmake new file mode 100644 index 0000000..e492370 --- /dev/null +++ b/cmake/modules/Versioning.cmake @@ -0,0 +1,95 @@ +# ============================================================ +# Versioning.cmake (Reusable Version + Resource Generator) +# ============================================================ + +# Freeze the directory where this module lives +# This is critical — it prevents paths from breaking when the +# function is invoked from other CMakeLists.txt files. +set(_VERSIONING_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "Versioning module directory") + +# ------------------------------------------------------------ +# Extract version information from Git +# ------------------------------------------------------------ + +# Get tag (expected: v1.2.3 or 1.2.3 or 1.2.3-12-gHASH) +execute_process( + COMMAND git describe --tags --dirty + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_DESC_RAW + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Remove leading "v" if present +string(REGEX REPLACE "^v" "" GIT_DESC "${GIT_DESC_RAW}") + +# Extract major.minor.patch +string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ "${GIT_DESC}") +set(PROJECT_VERSION_MAJOR "${CMAKE_MATCH_1}") +set(PROJECT_VERSION_MINOR "${CMAKE_MATCH_2}") +set(PROJECT_VERSION_PATCH "${CMAKE_MATCH_3}") + +set(PROJECT_VERSION_STRING + "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" +) + +# Commit hash (full + short) +execute_process( + COMMAND git rev-parse HEAD + OUTPUT_VARIABLE PROJECT_GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND git rev-parse --short HEAD + OUTPUT_VARIABLE PROJECT_GIT_HASH_SHORT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Export variables to parent scope +set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE) +set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE) +set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE) +set(PROJECT_VERSION_STRING "${PROJECT_VERSION_STRING}" PARENT_SCOPE) +set(PROJECT_GIT_HASH "${PROJECT_GIT_HASH}" PARENT_SCOPE) +set(PROJECT_GIT_HASH_SHORT "${PROJECT_GIT_HASH_SHORT}" PARENT_SCOPE) + +# Public variable for users +set(PROJECT_AUTO_VERSION "${PROJECT_VERSION_STRING}" PARENT_SCOPE) + +# ------------------------------------------------------------ +# Reusable function: Attach Windows version resources to target +# ------------------------------------------------------------ +function(add_windows_version_resources target) + if(NOT WIN32) + return() + endif() + + if(NOT TARGET "${target}") + message(FATAL_ERROR "add_windows_version_resources: target '${target}' not found.") + endif() + + # Absolute path to the template (never changes) + get_filename_component(_rc_in + "${_VERSIONING_MODULE_DIR}/FileVersionInfo.rc.in" + ABSOLUTE + ) + + if(NOT EXISTS "${_rc_in}") + message(FATAL_ERROR + "FileVersionInfo.rc.in missing at: ${_rc_in}" + ) + endif() + + # Output in the caller's binary dir + set(_rc_out "${CMAKE_CURRENT_BINARY_DIR}/${target}_version.rc") + get_filename_component(_rc_out "${_rc_out}" ABSOLUTE) + + # Ensure directory exists + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + + # Configure the template + configure_file("${_rc_in}" "${_rc_out}" @ONLY) + + # Add to the target + target_sources(${target} PRIVATE "${_rc_out}") +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e386b0b..0cf7526 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(QtAdvancedDockingSystem LANGUAGES CXX VERSION ${VERSION_SHORT}) include(GNUInstallDirs) +include(Versioning) if (${QT_VERSION_MAJOR}) message(STATUS "Forced to use Qt version ${QT_VERSION_MAJOR}") find_package(QT NAMES Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) @@ -83,6 +84,7 @@ if(BUILD_STATIC) target_compile_definitions( ${library_name} PUBLIC ADS_STATIC) else() add_library( ${library_name} SHARED ${ads_SRCS} ${ads_HEADERS}) + add_windows_version_resources(${library_name}) target_compile_definitions( ${library_name} PRIVATE ADS_SHARED_EXPORT) endif()