From 55f9c3d1b226f884de0417c2ec6cb0c95664c92e Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 11:37:58 +0200 Subject: [PATCH 01/10] chore: Reformat everything Signed-off-by: Cristian Le --- .github/workflows/step_test.yaml | 2 +- CMakeLists.txt | 144 +- cmake/DynamicVersion.cmake | 1230 ++++++++-------- cmake/PackageComps.cmake | 1270 ++++++++--------- docs/README.md | 6 +- test/CMakeLists.txt | 138 +- test/DynamicVersion/src/commit.cpp | 16 +- test/DynamicVersion/src/version.cpp | 8 +- .../simple_provider/CMakeLists.txt | 22 +- .../simple_provider/src/hello.cpp | 4 +- test/package/CMakeLists.txt | 8 +- test/package/FetchContent/CMakeLists.txt | 14 +- 12 files changed, 1432 insertions(+), 1430 deletions(-) diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index 3d00dc3..e300d26 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - cmake: ["3.20", "latest", "latestrc"] + cmake: [ "3.20", "latest", "latestrc" ] steps: - uses: actions/checkout@v4 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e43fb4..74eb481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ # Minimum version follows the current Ubuntu LTS and RHEL version cmake_minimum_required(VERSION 3.20) if (POLICY CMP0140) - # Enable using return(PROPAGATE) - # TODO: Remove when cmake 3.25 is commonly distributed - cmake_policy(SET CMP0140 NEW) + # Enable using return(PROPAGATE) + # TODO: Remove when cmake 3.25 is commonly distributed + cmake_policy(SET CMP0140 NEW) endif () #[==============================================================================================[ @@ -16,25 +16,25 @@ list(APPEND CMAKE_MESSAGE_CONTEXT CMakeExtraUtils) list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) include(DynamicVersion) dynamic_version(PROJECT_PREFIX CMakeExtraUtils_ - FALLBACK_VERSION 0.0.0 + FALLBACK_VERSION 0.0.0 ) project(CMakeExtraUtils - VERSION ${PROJECT_VERSION} - DESCRIPTION "Extra utilities for cmake" - HOMEPAGE_URL https://github.com/LecrisUT/CmakeExtraUtils - LANGUAGES NONE + VERSION ${PROJECT_VERSION} + DESCRIPTION "Extra utilities for cmake" + HOMEPAGE_URL https://github.com/LecrisUT/CmakeExtraUtils + LANGUAGES NONE ) # Back-porting to PROJECT_IS_TOP_LEVEL to older cmake # TODO: Remove when requiring cmake >= 3.21 if (NOT DEFINED CMakeExtraUtils_IS_TOP_LEVEL) - if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(PROJECT_IS_TOP_LEVEL ON) - set(CMakeExtraUtils_IS_TOP_LEVEL ON) - else () - set(PROJECT_IS_TOP_LEVEL OFF) - set(CMakeExtraUtils_IS_TOP_LEVEL_IS_TOP_LEVEL OFF) - endif () + if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + set(PROJECT_IS_TOP_LEVEL ON) + set(CMakeExtraUtils_IS_TOP_LEVEL ON) + else () + set(PROJECT_IS_TOP_LEVEL OFF) + set(CMakeExtraUtils_IS_TOP_LEVEL_IS_TOP_LEVEL OFF) + endif () endif () @@ -50,10 +50,10 @@ option(CMAKEEXTRAUTILS_INSTALL "CMakeExtraUtils: Install project files" ${PROJEC ]==============================================================================================] if (CMAKEEXTRAUTILS_INSTALL) - include(CMakePackageConfigHelpers) - if (UNIX) - include(GNUInstallDirs) - endif () + include(CMakePackageConfigHelpers) + if (UNIX) + include(GNUInstallDirs) + endif () endif () #[==============================================================================================[ @@ -69,19 +69,19 @@ endif () # Copy the module files to build directory # This is needed to make the scripts importable by ${builddir}/CMakeExtraUtilsConfig.cmake foreach (module IN ITEMS - DynamicVersion - PackageComps + DynamicVersion + PackageComps ) - configure_file( - ${PROJECT_SOURCE_DIR}/cmake/${module}.cmake - ${CMAKE_CURRENT_BINARY_DIR}/${module}.cmake - COPYONLY - ) + configure_file( + ${PROJECT_SOURCE_DIR}/cmake/${module}.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${module}.cmake + COPYONLY + ) endforeach () if (CMAKEEXTRAUTILS_TESTS) - enable_testing() - add_subdirectory(test) + enable_testing() + add_subdirectory(test) endif () #[==============================================================================================[ @@ -90,52 +90,52 @@ endif () # Install package files if (CMAKEEXTRAUTILS_INSTALL) - # Will show developer warning, but can't supress it :( - # Package files - write_basic_package_version_file( - CMakeExtraUtilsConfigVersion.cmake - VERSION ${PROJECT_VERSION} - # TODO: Currently unstable api, change when v1.0 is released - COMPATIBILITY SameMinorVersion - ARCH_INDEPENDENT - ) - configure_package_config_file( - cmake/CMakeExtraUtilsConfig.cmake.in - CMakeExtraUtilsConfig.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils - ) - install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/CMakeExtraUtilsConfigVersion.cmake - ${CMAKE_CURRENT_BINARY_DIR}/CMakeExtraUtilsConfig.cmake - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils - ) - # Bundled cmake files - install(FILES - cmake/DynamicVersion.cmake - cmake/PackageComps.cmake - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils - ) + # Will show developer warning, but can't supress it :( + # Package files + write_basic_package_version_file( + CMakeExtraUtilsConfigVersion.cmake + VERSION ${PROJECT_VERSION} + # TODO: Currently unstable api, change when v1.0 is released + COMPATIBILITY SameMinorVersion + ARCH_INDEPENDENT + ) + configure_package_config_file( + cmake/CMakeExtraUtilsConfig.cmake.in + CMakeExtraUtilsConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils + ) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/CMakeExtraUtilsConfigVersion.cmake + ${CMAKE_CURRENT_BINARY_DIR}/CMakeExtraUtilsConfig.cmake + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils + ) + # Bundled cmake files + install(FILES + cmake/DynamicVersion.cmake + cmake/PackageComps.cmake + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/CMakeExtraUtils + ) endif () # Make project available for FetchContent if (NOT PROJECT_IS_TOP_LEVEL) - # Propagate variables for FetchContent - # All variables have to be consistent with CMakeExtraUtilsConfig.cmake - if (CMAKE_VERSION VERSION_LESS 3.25) - # TODO: Remove when cmake 3.25 is commonly distributed - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION ${CMakeExtraUtils_VERSION} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_MAJOR ${CMakeExtraUtils_VERSION_MAJOR} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_MINOR ${CMakeExtraUtils_VERSION_MINOR} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_PATCH ${CMakeExtraUtils_VERSION_PATCH} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_TWEAK ${CMakeExtraUtils_VERSION_TWEAK} PARENT_SCOPE) - endif () - return(PROPAGATE - CMAKE_MODULE_PATH - CMakeExtraUtils_VERSION - CMakeExtraUtils_VERSION_MAJOR - CMakeExtraUtils_VERSION_MINOR - CMakeExtraUtils_VERSION_PATCH - CMakeExtraUtils_VERSION_TWEAK - ) + # Propagate variables for FetchContent + # All variables have to be consistent with CMakeExtraUtilsConfig.cmake + if (CMAKE_VERSION VERSION_LESS 3.25) + # TODO: Remove when cmake 3.25 is commonly distributed + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE) + set(CMakeExtraUtils_VERSION ${CMakeExtraUtils_VERSION} PARENT_SCOPE) + set(CMakeExtraUtils_VERSION_MAJOR ${CMakeExtraUtils_VERSION_MAJOR} PARENT_SCOPE) + set(CMakeExtraUtils_VERSION_MINOR ${CMakeExtraUtils_VERSION_MINOR} PARENT_SCOPE) + set(CMakeExtraUtils_VERSION_PATCH ${CMakeExtraUtils_VERSION_PATCH} PARENT_SCOPE) + set(CMakeExtraUtils_VERSION_TWEAK ${CMakeExtraUtils_VERSION_TWEAK} PARENT_SCOPE) + endif () + return(PROPAGATE + CMAKE_MODULE_PATH + CMakeExtraUtils_VERSION + CMakeExtraUtils_VERSION_MAJOR + CMakeExtraUtils_VERSION_MINOR + CMakeExtraUtils_VERSION_PATCH + CMakeExtraUtils_VERSION_TWEAK + ) endif () diff --git a/cmake/DynamicVersion.cmake b/cmake/DynamicVersion.cmake index 28c0c91..a0fd87f 100644 --- a/cmake/DynamicVersion.cmake +++ b/cmake/DynamicVersion.cmake @@ -13,9 +13,9 @@ Helper module to get the project's version dynamically. Format is compatible wit include_guard() list(APPEND CMAKE_MESSAGE_CONTEXT DynamicVersion) if (POLICY CMP0140) - # Enable using return(PROPAGATE) - # TODO: Remove when cmake 3.25 is commonly distributed - cmake_policy(SET CMP0140 NEW) + # Enable using return(PROPAGATE) + # TODO: Remove when cmake 3.25 is commonly distributed + cmake_policy(SET CMP0140 NEW) endif () #[==============================================================================================[ @@ -29,322 +29,322 @@ endif () ]==============================================================================================] function(dynamic_version) - #[===[.md: - # dynamic_version + #[===[.md: + # dynamic_version - Configure project to use dynamic versioning + Configure project to use dynamic versioning - ## Synopsis - ```cmake - Main interface - dynamic_version(PROJECT_PREFIX ) - dynamic_version(PROJECT_PREFIX - [OUTPUT_VERSION ] [OUTPUT_VERSION_FULL ] - [OUTPUT_DESCRIBE ] [OUTPUT_COMMIT ] - [OUTPUT_DISTANCE ] [OUTPUT_SHORT_HASH ] - [VERSION_FULL_MODE ] - [PROJECT_SOURCE ] [GIT_ARCHIVAL_FILE ] - ) + ## Synopsis + ```cmake + Main interface + dynamic_version(PROJECT_PREFIX ) + dynamic_version(PROJECT_PREFIX + [OUTPUT_VERSION ] [OUTPUT_VERSION_FULL ] + [OUTPUT_DESCRIBE ] [OUTPUT_COMMIT ] + [OUTPUT_DISTANCE ] [OUTPUT_SHORT_HASH ] + [VERSION_FULL_MODE ] + [PROJECT_SOURCE ] [GIT_ARCHIVAL_FILE ] + ) - Fallbacks - dynamic_version(... - [ALLOW_FAILS] [FALLBACK_VERSION ] [FALLBACK_HASH ]) + Fallbacks + dynamic_version(... + [ALLOW_FAILS] [FALLBACK_VERSION ] [FALLBACK_HASH ]) - Additional configurations - dynamic_version(... - [TMP_FOLDER ] [FALLBACK_VERSION ] [FALLBACK_HASH ]) - ``` - - ## Options - `PROJECT_PREFIX` - Prefix to be used for namespacing targets, typically ${PROJECT_NAME} - - `OUTPUT_VERSION` [Default: PROJECT_VERSION] - Variable where to save the calculated version - - `OUTPUT_VERSION_FULL` [Default: PROJECT_VERSION_FULL] - Variable where to save the full version in the format - - `VERSION_FULL_MODE` [Default: DEV] - Format of the `OUTPUT_VERSION_FULL`. Must be one of [`DEV`, `POST`] - - `OUTPUT_DESCRIBE` [Default: GIT_DESCRIBE] - Variable where to save the pure `git describe` output - - `OUTPUT_COMMIT` [Default: GIT_COMMIT] - Variable where to save the current git commit hash - - `OUTPUT_DISTANCE` [Default: GIT_DISTANCE] - Variable where to save the distance from git tag - - `OUTPUT_SHORT_HASH` [Default: GIT_SHORT_HASH] - Variable where to save the shortened git commit hash - - `PROJECT_SOURCE` [Default: `${CMAKE_CURRENT_SOURCE_DIR}`] - Location of the project source. Has to be either an extracted git archive or a git clone - - `GIT_ARCHIVAL_FILE` [Default: `${PROJECT_SOURCE}/.git_archival.txt`] - Location of `.git_archival.txt` file. See [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm#git-archives) - for more details - - `FALLBACK_VERSION` - Fallback version to be set if version cannot be dynamically determined. Implies `ALLOW_FAILS` - - `FALLBACK_HASH` - Fallback git hash to be used in `OUTPUT_COMMIT` if commit cannot be determined. - If not defined target GitHash will not be created if project is not a git repo - - `ALLOW_FAILS` - Do not return with `FATAL_ERROR` if version cannot be dynamically determined. CMakeLists author is responsible - for setting appropriate version if fails - - ### Additional configuration options - - `TMP_FOLDER` [Default: `${CMAKE_CURRENT_BINARY_DIR}/tmp`] - Temporary path to store `DynamicVersion`'s temporary files - - `OUTPUT_FOLDER` [Default: `${CMAKE_CURRENT_BINARY_DIR}`] - Path where to store generated files - - ## Targets - `${PROJECT_PREFIX}Version` - Target that recalculates the dynamic version each time. See [](#Output-files) for using dependencies that only - change when the actual commit/describe/version change. - - `${PROJECT_PREFIX}GitHash` - Target that recalculates the git hash each time. - - ## Output files - :::{note} - These files are updated only when the contents change. You can use them as dependencies for files generated from - . See for more - info on how to add file-level dependency - ::: - - `${OUTPUT_FOLDER}/.DynamicVersion.json` - All computed data of `DynamicVersion` - - `${OUTPUT_FOLDER}/.version` - Computed version - - `${OUTPUT_FOLDER}/.git_describe` - Computed git describe - - `${OUTPUT_FOLDER}/.git_commit` - Current commit - - ## See also - - [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm) - - ]===] - - list(APPEND CMAKE_MESSAGE_CONTEXT dynamic_version) - set(ARGS_Options - ALLOW_FAILS - ) - set(ARGS_OneValue - PROJECT_PREFIX - OUTPUT_VERSION - OUTPUT_VERSION_FULL - VERSION_FULL_MODE - OUTPUT_DESCRIBE - OUTPUT_COMMIT - OUTPUT_DISTANCE - OUTPUT_SHORT_HASH - PROJECT_SOURCE - GIT_ARCHIVAL_FILE - FALLBACK_VERSION - FALLBACK_HASH - TMP_FOLDER - OUTPUT_FOLDER - ) - set(ARGS_MultiValue - ) - - cmake_parse_arguments(PARSE_ARGV 0 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") - - set(DynamicVersion_ARGS) - - # Set default values - if (NOT DEFINED ARGS_OUTPUT_VERSION) - set(ARGS_OUTPUT_VERSION PROJECT_VERSION) - endif () - if (NOT DEFINED ARGS_OUTPUT_VERSION_FULL) - set(ARGS_OUTPUT_VERSION_FULL PROJECT_VERSION_FULL) - endif () - if (NOT DEFINED ARGS_VERSION_FULL_MODE) - set(ARGS_VERSION_FULL_MODE DEV) - elseif (NOT ARGS_VERSION_FULL_MODE MATCHES "(DEV|POST)") - message(FATAL_ERROR "Unsupported VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") - endif () - if (NOT DEFINED ARGS_OUTPUT_DESCRIBE) - set(ARGS_OUTPUT_DESCRIBE GIT_DESCRIBE) - endif () - if (NOT DEFINED ARGS_OUTPUT_COMMIT) - set(ARGS_OUTPUT_COMMIT GIT_COMMIT) - endif () - if (NOT DEFINED ARGS_OUTPUT_DISTANCE) - set(ARGS_OUTPUT_DISTANCE GIT_DISTANCE) - endif () - if (NOT DEFINED ARGS_OUTPUT_SHORT_HASH) - set(ARGS_OUTPUT_SHORT_HASH GIT_SHORT_HASH) - endif () - if (NOT DEFINED ARGS_PROJECT_SOURCE) - set(ARGS_PROJECT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) - endif () - if (NOT DEFINED ARGS_GIT_ARCHIVAL_FILE) - set(ARGS_GIT_ARCHIVAL_FILE ${ARGS_PROJECT_SOURCE}/.git_archival.txt) - endif () - if (DEFINED ARGS_FALLBACK_VERSION OR ARGS_ALLOW_FAILS) - # If we have a fallback version or it is specified it is ok if this fails, don't make messages FATAL_ERROR - set(error_message_type AUTHOR_WARNING) - else () - # Otherwise it should - set(error_message_type FATAL_ERROR) - endif () - if (NOT ARGS_PROJECT_PREFIX) - message(AUTHOR_WARNING - "No PROJECT_PREFIX was given. Please provide one to avoid target name clashes" - ) - elseif (NOT ARGS_PROJECT_PREFIX MATCHES ".*_$") - # Append an underscore _ to the prefix if not provided - message(AUTHOR_WARNING - "PROJECT_PREFIX did not contain an underscore, please add it for clarity" - ) - set(ARGS_PROJECT_PREFIX ${ARGS_PROJECT_PREFIX}_) - endif () - if (NOT DEFINED ARGS_TMP_FOLDER) - set(ARGS_TMP_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/tmp) - endif () - if (NOT DEFINED ARGS_OUTPUT_FOLDER) - set(ARGS_OUTPUT_FOLDER ${CMAKE_CURRENT_BINARY_DIR}) - endif () - if (ARGS_OUTPUT_FOLDER EQUAL ARGS_TMP_FOLDER) - message(FATAL_ERROR - "OUTPUT_FOLDER and TMP_FOLDER cannot point to the same path" - ) - endif () - - list(APPEND DynamicVersion_ARGS - PROJECT_SOURCE ${ARGS_PROJECT_SOURCE} - GIT_ARCHIVAL_FILE ${ARGS_GIT_ARCHIVAL_FILE} - TMP_FOLDER ${ARGS_TMP_FOLDER} - VERSION_FULL_MODE ${ARGS_VERSION_FULL_MODE} - ) - if (DEFINED ARGS_FALLBACK_VERSION) - list(APPEND DynamicVersion_ARGS - FALLBACK_VERSION ${ARGS_FALLBACK_VERSION}) - endif () - if (DEFINED ARGS_FALLBACK_HASH) - list(APPEND DynamicVersion_ARGS - FALLBACK_HASH ${ARGS_FALLBACK_HASH}) - endif () - if (ARGS_ALLOW_FAILS) - list(APPEND DynamicVersion_ARGS ALLOW_FAILS) - endif () - # Normalize DynamicVersion_ARGS to be passed as string - list(JOIN DynamicVersion_ARGS "\\;" DynamicVersion_ARGS) - - # Execute get_dynamic_version once to know the current configuration - execute_process(COMMAND ${CMAKE_COMMAND} - -DDynamicVersion_RUN:BOOL=True - # Note: DynamicVersion_ARGS cannot be escaped with "" - -DDynamicVersion_ARGS:STRING=${DynamicVersion_ARGS} - -P ${CMAKE_CURRENT_FUNCTION_LIST_FILE} - COMMAND_ERROR_IS_FATAL ANY) - - # Copy all configured files - foreach (file IN ITEMS .DynamicVersion.json .version .git_describe .git_commit) - if (EXISTS ${ARGS_TMP_FOLDER}/${file}) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) - file(COPY_FILE ${ARGS_TMP_FOLDER}/${file} ${ARGS_OUTPUT_FOLDER}/${file}) - else () - file(COPY ${ARGS_TMP_FOLDER}/${file} DESTINATION ${ARGS_OUTPUT_FOLDER}/) - endif () - endif () - endforeach () - - # Check configuration state - file(READ ${ARGS_TMP_FOLDER}/.DynamicVersion.json data) - # failed, mode, and version are always set if get_dynamic_version did not exit with failure - string(JSON failed GET ${data} failed) - string(JSON ${ARGS_OUTPUT_VERSION} GET ${data} version) - string(JSON ${ARGS_OUTPUT_VERSION_FULL} GET ${data} version-full) - # Other outputs are optional, populate the variables if found - # These are populated if failed = false - string(JSON ${ARGS_OUTPUT_SHORT_HASH} ERROR_VARIABLE _ GET ${data} short-hash) - string(JSON ${ARGS_OUTPUT_DISTANCE} ERROR_VARIABLE _ GET ${data} distance) - # These may not be populated depending on mode - string(JSON ${ARGS_OUTPUT_COMMIT} ERROR_VARIABLE _ GET ${data} commit) - string(JSON ${ARGS_OUTPUT_DESCRIBE} ERROR_VARIABLE _ GET ${data} describe) - - # Configure targets - if (failed) - # If configuration failed, create dummy targets - add_custom_target(${ARGS_PROJECT_PREFIX}Version - COMMAND ${CMAKE_COMMAND} -E true) - add_custom_target(${ARGS_PROJECT_PREFIX}GitHash - COMMAND ${CMAKE_COMMAND} -E true) - else () - # Otherwise create the targets outputting to the appropriate files - add_custom_target(${ARGS_PROJECT_PREFIX}DynamicVersion ALL - BYPRODUCTS ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_TMP_FOLDER}/.version - COMMAND ${CMAKE_COMMAND} - -DDynamicVersion_RUN:BOOL=True - # Note: For some reason DynamicVersion_ARGS needs "" here, but it doesn't in execute_process - -DDynamicVersion_ARGS:STRING="${DynamicVersion_ARGS}" - -P ${CMAKE_CURRENT_FUNCTION_LIST_FILE} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${ARGS_OUTPUT_FOLDER}/.DynamicVersion.json - ) - set(extra_version_args) - # .git_describe might not be generated, e.g. if it's an sdist. Make it optional - if (EXISTS ${ARGS_OUTPUT_FOLDER}/.git_describe) - list(APPEND extra_version_args - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_OUTPUT_FOLDER}/.git_describe - ) - endif () - add_custom_target(${ARGS_PROJECT_PREFIX}Version ALL - DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.version ${ARGS_OUTPUT_FOLDER}/.version - ${extra_version_args} - ) - # .git_commit might not exist, make the target a no-op in that case - if (NOT EXISTS ${ARGS_OUTPUT_FOLDER}/.git_commit) - add_custom_target(${ARGS_PROJECT_PREFIX}GitHash - COMMAND ${CMAKE_COMMAND} -E true) - else () - add_custom_target(${ARGS_PROJECT_PREFIX}GitHash - DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_OUTPUT_FOLDER}/.git_commit - ) - endif () - endif () - - # This ensures that the project is reconfigured (at least at second run) whenever the version changes - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND - PROPERTY CMAKE_CONFIGURE_DEPENDS ${ARGS_OUTPUT_FOLDER}/.version) - - message(VERBOSE - "Calculated version = ${${ARGS_OUTPUT_VERSION}}" - ) - - if (CMAKE_VERSION VERSION_LESS 3.25) - # TODO: Remove when cmake 3.25 is commonly distributed - set(${ARGS_OUTPUT_DESCRIBE} ${${ARGS_OUTPUT_DESCRIBE}} PARENT_SCOPE) - set(${ARGS_OUTPUT_VERSION} ${${ARGS_OUTPUT_VERSION}} PARENT_SCOPE) - set(${ARGS_OUTPUT_VERSION_FULL} ${${ARGS_OUTPUT_VERSION_FULL}} PARENT_SCOPE) - set(${ARGS_OUTPUT_COMMIT} ${${ARGS_OUTPUT_COMMIT}} PARENT_SCOPE) - set(${ARGS_OUTPUT_DISTANCE} ${${ARGS_OUTPUT_DISTANCE}} PARENT_SCOPE) - set(${ARGS_OUTPUT_SHORT_HASH} ${${ARGS_OUTPUT_SHORT_HASH}} PARENT_SCOPE) - endif () - return(PROPAGATE - ${ARGS_OUTPUT_DESCRIBE} - ${ARGS_OUTPUT_VERSION} - ${ARGS_OUTPUT_VERSION_FULL} - ${ARGS_OUTPUT_COMMIT} - ${ARGS_OUTPUT_DISTANCE} - ${ARGS_OUTPUT_SHORT_HASH} - ) + Additional configurations + dynamic_version(... + [TMP_FOLDER ] [FALLBACK_VERSION ] [FALLBACK_HASH ]) + ``` + + ## Options + `PROJECT_PREFIX` + Prefix to be used for namespacing targets, typically ${PROJECT_NAME} + + `OUTPUT_VERSION` [Default: PROJECT_VERSION] + Variable where to save the calculated version + + `OUTPUT_VERSION_FULL` [Default: PROJECT_VERSION_FULL] + Variable where to save the full version in the format + + `VERSION_FULL_MODE` [Default: DEV] + Format of the `OUTPUT_VERSION_FULL`. Must be one of [`DEV`, `POST`] + + `OUTPUT_DESCRIBE` [Default: GIT_DESCRIBE] + Variable where to save the pure `git describe` output + + `OUTPUT_COMMIT` [Default: GIT_COMMIT] + Variable where to save the current git commit hash + + `OUTPUT_DISTANCE` [Default: GIT_DISTANCE] + Variable where to save the distance from git tag + + `OUTPUT_SHORT_HASH` [Default: GIT_SHORT_HASH] + Variable where to save the shortened git commit hash + + `PROJECT_SOURCE` [Default: `${CMAKE_CURRENT_SOURCE_DIR}`] + Location of the project source. Has to be either an extracted git archive or a git clone + + `GIT_ARCHIVAL_FILE` [Default: `${PROJECT_SOURCE}/.git_archival.txt`] + Location of `.git_archival.txt` file. See [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm#git-archives) + for more details + + `FALLBACK_VERSION` + Fallback version to be set if version cannot be dynamically determined. Implies `ALLOW_FAILS` + + `FALLBACK_HASH` + Fallback git hash to be used in `OUTPUT_COMMIT` if commit cannot be determined. + If not defined target GitHash will not be created if project is not a git repo + + `ALLOW_FAILS` + Do not return with `FATAL_ERROR` if version cannot be dynamically determined. CMakeLists author is responsible + for setting appropriate version if fails + + ### Additional configuration options + + `TMP_FOLDER` [Default: `${CMAKE_CURRENT_BINARY_DIR}/tmp`] + Temporary path to store `DynamicVersion`'s temporary files + + `OUTPUT_FOLDER` [Default: `${CMAKE_CURRENT_BINARY_DIR}`] + Path where to store generated files + + ## Targets + `${PROJECT_PREFIX}Version` + Target that recalculates the dynamic version each time. See [](#Output-files) for using dependencies that only + change when the actual commit/describe/version change. + + `${PROJECT_PREFIX}GitHash` + Target that recalculates the git hash each time. + + ## Output files + :::{note} + These files are updated only when the contents change. You can use them as dependencies for files generated from + . See for more + info on how to add file-level dependency + ::: + + `${OUTPUT_FOLDER}/.DynamicVersion.json` + All computed data of `DynamicVersion` + + `${OUTPUT_FOLDER}/.version` + Computed version + + `${OUTPUT_FOLDER}/.git_describe` + Computed git describe + + `${OUTPUT_FOLDER}/.git_commit` + Current commit + + ## See also + - [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm) + + ]===] + + list(APPEND CMAKE_MESSAGE_CONTEXT dynamic_version) + set(ARGS_Options + ALLOW_FAILS + ) + set(ARGS_OneValue + PROJECT_PREFIX + OUTPUT_VERSION + OUTPUT_VERSION_FULL + VERSION_FULL_MODE + OUTPUT_DESCRIBE + OUTPUT_COMMIT + OUTPUT_DISTANCE + OUTPUT_SHORT_HASH + PROJECT_SOURCE + GIT_ARCHIVAL_FILE + FALLBACK_VERSION + FALLBACK_HASH + TMP_FOLDER + OUTPUT_FOLDER + ) + set(ARGS_MultiValue + ) + + cmake_parse_arguments(PARSE_ARGV 0 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") + + set(DynamicVersion_ARGS) + + # Set default values + if (NOT DEFINED ARGS_OUTPUT_VERSION) + set(ARGS_OUTPUT_VERSION PROJECT_VERSION) + endif () + if (NOT DEFINED ARGS_OUTPUT_VERSION_FULL) + set(ARGS_OUTPUT_VERSION_FULL PROJECT_VERSION_FULL) + endif () + if (NOT DEFINED ARGS_VERSION_FULL_MODE) + set(ARGS_VERSION_FULL_MODE DEV) + elseif (NOT ARGS_VERSION_FULL_MODE MATCHES "(DEV|POST)") + message(FATAL_ERROR "Unsupported VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") + endif () + if (NOT DEFINED ARGS_OUTPUT_DESCRIBE) + set(ARGS_OUTPUT_DESCRIBE GIT_DESCRIBE) + endif () + if (NOT DEFINED ARGS_OUTPUT_COMMIT) + set(ARGS_OUTPUT_COMMIT GIT_COMMIT) + endif () + if (NOT DEFINED ARGS_OUTPUT_DISTANCE) + set(ARGS_OUTPUT_DISTANCE GIT_DISTANCE) + endif () + if (NOT DEFINED ARGS_OUTPUT_SHORT_HASH) + set(ARGS_OUTPUT_SHORT_HASH GIT_SHORT_HASH) + endif () + if (NOT DEFINED ARGS_PROJECT_SOURCE) + set(ARGS_PROJECT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) + endif () + if (NOT DEFINED ARGS_GIT_ARCHIVAL_FILE) + set(ARGS_GIT_ARCHIVAL_FILE ${ARGS_PROJECT_SOURCE}/.git_archival.txt) + endif () + if (DEFINED ARGS_FALLBACK_VERSION OR ARGS_ALLOW_FAILS) + # If we have a fallback version or it is specified it is ok if this fails, don't make messages FATAL_ERROR + set(error_message_type AUTHOR_WARNING) + else () + # Otherwise it should + set(error_message_type FATAL_ERROR) + endif () + if (NOT ARGS_PROJECT_PREFIX) + message(AUTHOR_WARNING + "No PROJECT_PREFIX was given. Please provide one to avoid target name clashes" + ) + elseif (NOT ARGS_PROJECT_PREFIX MATCHES ".*_$") + # Append an underscore _ to the prefix if not provided + message(AUTHOR_WARNING + "PROJECT_PREFIX did not contain an underscore, please add it for clarity" + ) + set(ARGS_PROJECT_PREFIX ${ARGS_PROJECT_PREFIX}_) + endif () + if (NOT DEFINED ARGS_TMP_FOLDER) + set(ARGS_TMP_FOLDER ${CMAKE_CURRENT_BINARY_DIR}/tmp) + endif () + if (NOT DEFINED ARGS_OUTPUT_FOLDER) + set(ARGS_OUTPUT_FOLDER ${CMAKE_CURRENT_BINARY_DIR}) + endif () + if (ARGS_OUTPUT_FOLDER EQUAL ARGS_TMP_FOLDER) + message(FATAL_ERROR + "OUTPUT_FOLDER and TMP_FOLDER cannot point to the same path" + ) + endif () + + list(APPEND DynamicVersion_ARGS + PROJECT_SOURCE ${ARGS_PROJECT_SOURCE} + GIT_ARCHIVAL_FILE ${ARGS_GIT_ARCHIVAL_FILE} + TMP_FOLDER ${ARGS_TMP_FOLDER} + VERSION_FULL_MODE ${ARGS_VERSION_FULL_MODE} + ) + if (DEFINED ARGS_FALLBACK_VERSION) + list(APPEND DynamicVersion_ARGS + FALLBACK_VERSION ${ARGS_FALLBACK_VERSION}) + endif () + if (DEFINED ARGS_FALLBACK_HASH) + list(APPEND DynamicVersion_ARGS + FALLBACK_HASH ${ARGS_FALLBACK_HASH}) + endif () + if (ARGS_ALLOW_FAILS) + list(APPEND DynamicVersion_ARGS ALLOW_FAILS) + endif () + # Normalize DynamicVersion_ARGS to be passed as string + list(JOIN DynamicVersion_ARGS "\\;" DynamicVersion_ARGS) + + # Execute get_dynamic_version once to know the current configuration + execute_process(COMMAND ${CMAKE_COMMAND} + -DDynamicVersion_RUN:BOOL=True + # Note: DynamicVersion_ARGS cannot be escaped with "" + -DDynamicVersion_ARGS:STRING=${DynamicVersion_ARGS} + -P ${CMAKE_CURRENT_FUNCTION_LIST_FILE} + COMMAND_ERROR_IS_FATAL ANY) + + # Copy all configured files + foreach (file IN ITEMS .DynamicVersion.json .version .git_describe .git_commit) + if (EXISTS ${ARGS_TMP_FOLDER}/${file}) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21) + file(COPY_FILE ${ARGS_TMP_FOLDER}/${file} ${ARGS_OUTPUT_FOLDER}/${file}) + else () + file(COPY ${ARGS_TMP_FOLDER}/${file} DESTINATION ${ARGS_OUTPUT_FOLDER}/) + endif () + endif () + endforeach () + + # Check configuration state + file(READ ${ARGS_TMP_FOLDER}/.DynamicVersion.json data) + # failed, mode, and version are always set if get_dynamic_version did not exit with failure + string(JSON failed GET ${data} failed) + string(JSON ${ARGS_OUTPUT_VERSION} GET ${data} version) + string(JSON ${ARGS_OUTPUT_VERSION_FULL} GET ${data} version-full) + # Other outputs are optional, populate the variables if found + # These are populated if failed = false + string(JSON ${ARGS_OUTPUT_SHORT_HASH} ERROR_VARIABLE _ GET ${data} short-hash) + string(JSON ${ARGS_OUTPUT_DISTANCE} ERROR_VARIABLE _ GET ${data} distance) + # These may not be populated depending on mode + string(JSON ${ARGS_OUTPUT_COMMIT} ERROR_VARIABLE _ GET ${data} commit) + string(JSON ${ARGS_OUTPUT_DESCRIBE} ERROR_VARIABLE _ GET ${data} describe) + + # Configure targets + if (failed) + # If configuration failed, create dummy targets + add_custom_target(${ARGS_PROJECT_PREFIX}Version + COMMAND ${CMAKE_COMMAND} -E true) + add_custom_target(${ARGS_PROJECT_PREFIX}GitHash + COMMAND ${CMAKE_COMMAND} -E true) + else () + # Otherwise create the targets outputting to the appropriate files + add_custom_target(${ARGS_PROJECT_PREFIX}DynamicVersion ALL + BYPRODUCTS ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_TMP_FOLDER}/.version + COMMAND ${CMAKE_COMMAND} + -DDynamicVersion_RUN:BOOL=True + # Note: For some reason DynamicVersion_ARGS needs "" here, but it doesn't in execute_process + -DDynamicVersion_ARGS:STRING="${DynamicVersion_ARGS}" + -P ${CMAKE_CURRENT_FUNCTION_LIST_FILE} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${ARGS_OUTPUT_FOLDER}/.DynamicVersion.json + ) + set(extra_version_args) + # .git_describe might not be generated, e.g. if it's an sdist. Make it optional + if (EXISTS ${ARGS_OUTPUT_FOLDER}/.git_describe) + list(APPEND extra_version_args + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_describe ${ARGS_OUTPUT_FOLDER}/.git_describe + ) + endif () + add_custom_target(${ARGS_PROJECT_PREFIX}Version ALL + DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.version ${ARGS_OUTPUT_FOLDER}/.version + ${extra_version_args} + ) + # .git_commit might not exist, make the target a no-op in that case + if (NOT EXISTS ${ARGS_OUTPUT_FOLDER}/.git_commit) + add_custom_target(${ARGS_PROJECT_PREFIX}GitHash + COMMAND ${CMAKE_COMMAND} -E true) + else () + add_custom_target(${ARGS_PROJECT_PREFIX}GitHash + DEPENDS ${ARGS_PROJECT_PREFIX}DynamicVersion + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_OUTPUT_FOLDER}/.git_commit + ) + endif () + endif () + + # This ensures that the project is reconfigured (at least at second run) whenever the version changes + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS ${ARGS_OUTPUT_FOLDER}/.version) + + message(VERBOSE + "Calculated version = ${${ARGS_OUTPUT_VERSION}}" + ) + + if (CMAKE_VERSION VERSION_LESS 3.25) + # TODO: Remove when cmake 3.25 is commonly distributed + set(${ARGS_OUTPUT_DESCRIBE} ${${ARGS_OUTPUT_DESCRIBE}} PARENT_SCOPE) + set(${ARGS_OUTPUT_VERSION} ${${ARGS_OUTPUT_VERSION}} PARENT_SCOPE) + set(${ARGS_OUTPUT_VERSION_FULL} ${${ARGS_OUTPUT_VERSION_FULL}} PARENT_SCOPE) + set(${ARGS_OUTPUT_COMMIT} ${${ARGS_OUTPUT_COMMIT}} PARENT_SCOPE) + set(${ARGS_OUTPUT_DISTANCE} ${${ARGS_OUTPUT_DISTANCE}} PARENT_SCOPE) + set(${ARGS_OUTPUT_SHORT_HASH} ${${ARGS_OUTPUT_SHORT_HASH}} PARENT_SCOPE) + endif () + return(PROPAGATE + ${ARGS_OUTPUT_DESCRIBE} + ${ARGS_OUTPUT_VERSION} + ${ARGS_OUTPUT_VERSION_FULL} + ${ARGS_OUTPUT_COMMIT} + ${ARGS_OUTPUT_DISTANCE} + ${ARGS_OUTPUT_SHORT_HASH} + ) endfunction() @@ -353,301 +353,301 @@ endfunction() ]==============================================================================================] function(get_dynamic_version) - #[===[.md: - # get_dynamic_version - - Internal function that is called to calculate the dynamic version. This function is called by the - `${PROJECT_PREFIX}DynamicVersion` targets generated by {command}`dynamic_version`. - - In a nutshell, the `DynamicVersion.cmake` is executed with the variable `DynamicVersion_RUN` set to true. - - ## Synopsis - ```cmake - get_dynamic_version(PROJECT_SOURCE GIT_ARCHIVAL_FILE - TMP_FOLDER VERSION_FULL_MODE - [FALLBACK_VERSION ] [FALLBACK_HASH ] - ) - ``` - - ## Options - See {command}`dynamic_version` for details - - ## See also - - [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm) - - ]===] - - list(APPEND CMAKE_MESSAGE_CONTEXT get_dynamic_version) - set(ARGS_Options - ALLOW_FAILS - ) - set(ARGS_OneValue - PROJECT_SOURCE - VERSION_FULL_MODE - GIT_ARCHIVAL_FILE - FALLBACK_VERSION - FALLBACK_HASH - TMP_FOLDER - ) - set(ARGS_MultiValue - ) - - cmake_parse_arguments(PARSE_ARGV 0 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") - - if (DEFINED ARGS_FALLBACK_VERSION OR ARGS_ALLOW_FAILS) - # If we have a fallback version or it is specified it is ok if this fails, don't make messages FATAL_ERROR - set(error_message_type AUTHOR_WARNING) - else () - # Otherwise it should fail - set(error_message_type FATAL_ERROR) - endif () - - set(data "{}") - # Default set - string(JSON data SET ${data} failed true) - if (ARGS_ALLOW_FAILS) - string(JSON data SET ${data} allow-fails true) - else () - string(JSON data SET ${data} allow-fails false) - endif () - - # Set fallback values - if (DEFINED ARGS_FALLBACK_VERSION) - string(JSON data SET - ${data} version \"${ARGS_FALLBACK_VERSION}\") - string(JSON data SET - ${data} version-full \"${ARGS_FALLBACK_VERSION}\") - file(WRITE ${ARGS_TMP_FOLDER}/.version ${ARGS_FALLBACK_VERSION}) - endif () - if (DEFINED ARGS_FALLBACK_HASH) - string(JSON data SET - ${data} commit \"${ARGS_FALLBACK_HASH}\") - file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_FALLBACK_HASH}) - endif () - - file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) - - # Check git_archival.txt file is present and properly written - if (NOT EXISTS ${ARGS_GIT_ARCHIVAL_FILE}) - # If git_archival.txt is missing, project is ill-formed - message(${error_message_type} - "Missing file .git_archival.txt\n" - " .git_archival.txt: ${ARGS_GIT_ARCHIVAL_FILE}" - ) - return() - endif () - file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} describe-name - REGEX "^describe-name:.*") - if (NOT describe-name) - # If git_archival.txt does not contain the field "describe-name:", it is ill-formed - message(${error_message_type} - "Missing string \"describe-name\" in .git_archival.txt\n" - " .git_archival.txt: ${ARGS_GIT_ARCHIVAL_FILE}" - ) - return() - endif () - - # Try to get the version statically, and if it fails, get it from VCS - if (EXISTS ${ARGS_PROJECT_SOURCE}/PKG-INFO) - # Case1: Python sdist archive. Get everything from PKG-INFO file - set(mode pkg-info) - file(STRINGS ${ARGS_PROJECT_SOURCE}/PKG-INFO version - REGEX "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$") - # Cannot use Regex match from here, need to run string(REGEX MATCH) again - # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 - string(REGEX MATCH "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$" version "${version}") - # Regex match groups: https://regex101.com/r/G4Ox4X/5 - # 1: Full version string - # 2: Version string - # 3: Version suffix (e.g. rc, alpha, etc.) - # 4: Development suffix - # 5: dev/post - # 6: git distance - # 7: short_hash - set(version-full ${CMAKE_MATCH_1}) - set(version ${CMAKE_MATCH_2}) - set(version-suffix ${CMAKE_MATCH_3}) - if (CMAKE_MATCH_4) - set(distance ${CMAKE_MATCH_6}) - set(short-hash ${CMAKE_MATCH_7}) - string(JSON data SET - ${data} dev-type \"${CMAKE_MATCH_5}\") - else () - set(distance 0) - endif () - message(DEBUG "Found version in PKG-INFO") - elseif (describe-name MATCHES "^describe-name:[ ]?(v?([0-9\\.]+)(-?[a-zA-z0-9]*)?(-([0-9]+)-g([a-f0-9]+))?)$") - # Case2: Git archive. Get everything from git_archival.txt file - set(mode git-archive) - # Regex match groups: https://regex101.com/r/osVZpm/4 - # 1: Git describe - # 2: Version string - # 3: Version suffix (e.g. rc, alpha, etc.) - # 4: Development suffix - # 5: git distance - # 6: short_hash - set(describe ${CMAKE_MATCH_1}) - set(version ${CMAKE_MATCH_2}) - set(version-suffix ${CMAKE_MATCH_3}) - if (CMAKE_MATCH_4) - set(distance ${CMAKE_MATCH_5}) - set(short-hash ${CMAKE_MATCH_6}) - else () - set(distance 0) - endif () - # Get commit hash - file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} node - REGEX "^node:[ ]?(.*)") - # Cannot use Regex match from here, need to run string(REGEX MATCH) again - # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 - string(REGEX MATCH "^node:[ ]?(.*)" node "${node}") - set(commit ${CMAKE_MATCH_1}) - message(DEBUG "Found version in git-archival.txt") - else () - # Default: Git repository. Call git commands - set(mode git) - find_package(Git REQUIRED) - # Test if project is a git repository - execute_process(COMMAND ${GIT_EXECUTABLE} status - WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} - RESULT_VARIABLE git_status_result - OUTPUT_QUIET) - if (NOT git_status_result EQUAL 0) - message(${error_message_type} - "Project source is neither a git repository nor a git archive:\n" - " Source: ${ARGS_PROJECT_SOURCE}" - ) - return() - endif () - # Get version and describe-name - execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --match=?[0-9.]* - WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} - OUTPUT_VARIABLE describe-name - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE git_describe_result - ) - if (NOT git_status_result EQUAL 0) - message(${error_message_type} - "Git describe failed:\n" - " Source: ${ARGS_PROJECT_SOURCE}" - ) - return() - endif () - # Match any part containing digits and periods (strips out rc and so on) + #[===[.md: + # get_dynamic_version + + Internal function that is called to calculate the dynamic version. This function is called by the + `${PROJECT_PREFIX}DynamicVersion` targets generated by {command}`dynamic_version`. + + In a nutshell, the `DynamicVersion.cmake` is executed with the variable `DynamicVersion_RUN` set to true. + + ## Synopsis + ```cmake + get_dynamic_version(PROJECT_SOURCE GIT_ARCHIVAL_FILE + TMP_FOLDER VERSION_FULL_MODE + [FALLBACK_VERSION ] [FALLBACK_HASH ] + ) + ``` + + ## Options + See {command}`dynamic_version` for details + + ## See also + - [pypa/setuptools_scm](https://github.com/pypa/setuptools_scm) + + ]===] + + list(APPEND CMAKE_MESSAGE_CONTEXT get_dynamic_version) + set(ARGS_Options + ALLOW_FAILS + ) + set(ARGS_OneValue + PROJECT_SOURCE + VERSION_FULL_MODE + GIT_ARCHIVAL_FILE + FALLBACK_VERSION + FALLBACK_HASH + TMP_FOLDER + ) + set(ARGS_MultiValue + ) + + cmake_parse_arguments(PARSE_ARGV 0 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") + + if (DEFINED ARGS_FALLBACK_VERSION OR ARGS_ALLOW_FAILS) + # If we have a fallback version or it is specified it is ok if this fails, don't make messages FATAL_ERROR + set(error_message_type AUTHOR_WARNING) + else () + # Otherwise it should fail + set(error_message_type FATAL_ERROR) + endif () + + set(data "{}") + # Default set + string(JSON data SET ${data} failed true) + if (ARGS_ALLOW_FAILS) + string(JSON data SET ${data} allow-fails true) + else () + string(JSON data SET ${data} allow-fails false) + endif () + + # Set fallback values + if (DEFINED ARGS_FALLBACK_VERSION) + string(JSON data SET + ${data} version \"${ARGS_FALLBACK_VERSION}\") + string(JSON data SET + ${data} version-full \"${ARGS_FALLBACK_VERSION}\") + file(WRITE ${ARGS_TMP_FOLDER}/.version ${ARGS_FALLBACK_VERSION}) + endif () + if (DEFINED ARGS_FALLBACK_HASH) + string(JSON data SET + ${data} commit \"${ARGS_FALLBACK_HASH}\") + file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${ARGS_FALLBACK_HASH}) + endif () + + file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) + + # Check git_archival.txt file is present and properly written + if (NOT EXISTS ${ARGS_GIT_ARCHIVAL_FILE}) + # If git_archival.txt is missing, project is ill-formed + message(${error_message_type} + "Missing file .git_archival.txt\n" + " .git_archival.txt: ${ARGS_GIT_ARCHIVAL_FILE}" + ) + return() + endif () + file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} describe-name + REGEX "^describe-name:.*") + if (NOT describe-name) + # If git_archival.txt does not contain the field "describe-name:", it is ill-formed + message(${error_message_type} + "Missing string \"describe-name\" in .git_archival.txt\n" + " .git_archival.txt: ${ARGS_GIT_ARCHIVAL_FILE}" + ) + return() + endif () + + # Try to get the version statically, and if it fails, get it from VCS + if (EXISTS ${ARGS_PROJECT_SOURCE}/PKG-INFO) + # Case1: Python sdist archive. Get everything from PKG-INFO file + set(mode pkg-info) + file(STRINGS ${ARGS_PROJECT_SOURCE}/PKG-INFO version + REGEX "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$") + # Cannot use Regex match from here, need to run string(REGEX MATCH) again + # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 + string(REGEX MATCH "^Version:[ ]?(([0-9\\.]+)([a-zA-Z0-9]*)?(\\.(dev|post)([0-9]+)\\+g([a-f0-9]+))?)$" version "${version}") + # Regex match groups: https://regex101.com/r/G4Ox4X/5 + # 1: Full version string + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: dev/post + # 6: git distance + # 7: short_hash + set(version-full ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_6}) + set(short-hash ${CMAKE_MATCH_7}) + string(JSON data SET + ${data} dev-type \"${CMAKE_MATCH_5}\") + else () + set(distance 0) + endif () + message(DEBUG "Found version in PKG-INFO") + elseif (describe-name MATCHES "^describe-name:[ ]?(v?([0-9\\.]+)(-?[a-zA-z0-9]*)?(-([0-9]+)-g([a-f0-9]+))?)$") + # Case2: Git archive. Get everything from git_archival.txt file + set(mode git-archive) + # Regex match groups: https://regex101.com/r/osVZpm/4 + # 1: Git describe + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: git distance + # 6: short_hash + set(describe ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_5}) + set(short-hash ${CMAKE_MATCH_6}) + else () + set(distance 0) + endif () + # Get commit hash + file(STRINGS ${ARGS_GIT_ARCHIVAL_FILE} node + REGEX "^node:[ ]?(.*)") + # Cannot use Regex match from here, need to run string(REGEX MATCH) again + # https://gitlab.kitware.com/cmake/cmake/-/issues/23770 + string(REGEX MATCH "^node:[ ]?(.*)" node "${node}") + set(commit ${CMAKE_MATCH_1}) + message(DEBUG "Found version in git-archival.txt") + else () + # Default: Git repository. Call git commands + set(mode git) + find_package(Git REQUIRED) + # Test if project is a git repository + execute_process(COMMAND ${GIT_EXECUTABLE} status + WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} + RESULT_VARIABLE git_status_result + OUTPUT_QUIET) + if (NOT git_status_result EQUAL 0) + message(${error_message_type} + "Project source is neither a git repository nor a git archive:\n" + " Source: ${ARGS_PROJECT_SOURCE}" + ) + return() + endif () + # Get version and describe-name + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long --match=?[0-9.]* + WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} + OUTPUT_VARIABLE describe-name + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE git_describe_result + ) + if (NOT git_status_result EQUAL 0) + message(${error_message_type} + "Git describe failed:\n" + " Source: ${ARGS_PROJECT_SOURCE}" + ) + return() + endif () + # Match any part containing digits and periods (strips out rc and so on) if (NOT describe-name MATCHES "^(v?([0-9\\.]+)(-?[a-zA-z0-9]*)?(-([0-9]+)-g([a-f0-9]+))?)$") - message(${error_message_type} - "Version tag is ill-formatted\n" - " Describe-name: ${describe-name}" - ) - return() - endif () - # Regex match groups: https://regex101.com/r/GIfYI1/2 - # 1: Git describe - # 2: Version string - # 3: Version suffix (e.g. rc, alpha, etc.) - # 4: Development suffix - # 5: git distance - # 6: short_hash - set(describe ${CMAKE_MATCH_1}) - set(version ${CMAKE_MATCH_2}) - set(version-suffix ${CMAKE_MATCH_3}) - if (CMAKE_MATCH_4) - set(distance ${CMAKE_MATCH_5}) - set(short-hash ${CMAKE_MATCH_6}) - else () - set(distance 0) - endif () - # Get commit hash - execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD - WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} - OUTPUT_VARIABLE commit - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE git_rev_parser_result - ) - if (NOT git_rev_parser_result EQUAL 0) - message(${error_message_type} - "Could not get current git commit:\n" - " Source: ${ARGS_PROJECT_SOURCE}" - ) - return() - endif () - message(DEBUG "Found version git repo") - endif () - - # Construct the version_full if it was not already provided - if (NOT version-full) - string(REGEX REPLACE "[-_]" "" version-suffix-sanitized "${version-suffix}") - if (distance EQUAL 0) - # If the distance is 0, just use the original tag version with sanitized suffix - set(version-full "${version}${version-suffix-sanitized}") - else () - # Otherwise construct it according to VERSION_FULL_MODE - if (ARGS_VERSION_FULL_MODE STREQUAL DEV) - # In DEV mode, we bump the last digit of the version. If this is in version-suffix, like `-rcX`, then - # this must be bumped instead - if (version-suffix-sanitized MATCHES "([a-zA-Z]*)([0-9]+)") - math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") - set(version-suffix-sanitized "${CMAKE_MATCH_1}${bumped_number}") - elseif (version MATCHES "([0-9\\.]*\\.)([0-9]+)") - math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") - set(version "${CMAKE_MATCH_1}${bumped_number}") - else () - message(FATAL_ERROR "Assert False: version = ${version}") - endif () - set(version-full "${version}${version-suffix-sanitized}.dev${distance}+g${short-hash}") - elseif (ARGS_VERSION_FULL_MODE STREQUAL POST) - set(version-full "${version}${version-suffix-sanitized}.post${distance}+g${short-hash}") - else () - message(FATAL_ERROR "Assert False: VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") - endif () - endif () - endif () - - # Construct the JSON data - string(JSON data SET ${data} - mode \"${mode}\" - ) - string(JSON data SET ${data} - version \"${version}\" - ) - file(WRITE ${ARGS_TMP_FOLDER}/.version ${version}) - string(JSON data SET ${data} - version-full \"${version-full}\" - ) - if (describe) - string(JSON data SET ${data} - describe \"${describe}\" - ) - file(WRITE ${ARGS_TMP_FOLDER}/.git_describe ${describe}) - endif () - if (commit) - string(JSON data SET ${data} - commit \"${commit}\" - ) - file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${commit}) - endif () - set(JSON data SET ${data} - version-full \"${version-full}\" - ) - string(JSON data SET ${data} - version-suffix \"${version-suffix}\" - ) - string(JSON data SET ${data} - distance ${distance} - ) - if (short-hash) - string(JSON data SET ${data} - short-hash \"${short-hash}\" - ) - endif () - - # Mark success and output results - string(JSON data SET ${data} failed false) - message(DEBUG - "Computed data:\n" - " data = ${data}" - ) - file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) + message(${error_message_type} + "Version tag is ill-formatted\n" + " Describe-name: ${describe-name}" + ) + return() + endif () + # Regex match groups: https://regex101.com/r/GIfYI1/2 + # 1: Git describe + # 2: Version string + # 3: Version suffix (e.g. rc, alpha, etc.) + # 4: Development suffix + # 5: git distance + # 6: short_hash + set(describe ${CMAKE_MATCH_1}) + set(version ${CMAKE_MATCH_2}) + set(version-suffix ${CMAKE_MATCH_3}) + if (CMAKE_MATCH_4) + set(distance ${CMAKE_MATCH_5}) + set(short-hash ${CMAKE_MATCH_6}) + else () + set(distance 0) + endif () + # Get commit hash + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD + WORKING_DIRECTORY ${ARGS_PROJECT_SOURCE} + OUTPUT_VARIABLE commit + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE git_rev_parser_result + ) + if (NOT git_rev_parser_result EQUAL 0) + message(${error_message_type} + "Could not get current git commit:\n" + " Source: ${ARGS_PROJECT_SOURCE}" + ) + return() + endif () + message(DEBUG "Found version git repo") + endif () + + # Construct the version_full if it was not already provided + if (NOT version-full) + string(REGEX REPLACE "[-_]" "" version-suffix-sanitized "${version-suffix}") + if (distance EQUAL 0) + # If the distance is 0, just use the original tag version with sanitized suffix + set(version-full "${version}${version-suffix-sanitized}") + else () + # Otherwise construct it according to VERSION_FULL_MODE + if (ARGS_VERSION_FULL_MODE STREQUAL DEV) + # In DEV mode, we bump the last digit of the version. If this is in version-suffix, like `-rcX`, then + # this must be bumped instead + if (version-suffix-sanitized MATCHES "([a-zA-Z]*)([0-9]+)") + math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") + set(version-suffix-sanitized "${CMAKE_MATCH_1}${bumped_number}") + elseif (version MATCHES "([0-9\\.]*\\.)([0-9]+)") + math(EXPR bumped_number "${CMAKE_MATCH_2} + 1") + set(version "${CMAKE_MATCH_1}${bumped_number}") + else () + message(FATAL_ERROR "Assert False: version = ${version}") + endif () + set(version-full "${version}${version-suffix-sanitized}.dev${distance}+g${short-hash}") + elseif (ARGS_VERSION_FULL_MODE STREQUAL POST) + set(version-full "${version}${version-suffix-sanitized}.post${distance}+g${short-hash}") + else () + message(FATAL_ERROR "Assert False: VERSION_FULL_MODE = ${ARGS_VERSION_FULL_MODE}") + endif () + endif () + endif () + + # Construct the JSON data + string(JSON data SET ${data} + mode \"${mode}\" + ) + string(JSON data SET ${data} + version \"${version}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.version ${version}) + string(JSON data SET ${data} + version-full \"${version-full}\" + ) + if (describe) + string(JSON data SET ${data} + describe \"${describe}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.git_describe ${describe}) + endif () + if (commit) + string(JSON data SET ${data} + commit \"${commit}\" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.git_commit ${commit}) + endif () + set(JSON data SET ${data} + version-full \"${version-full}\" + ) + string(JSON data SET ${data} + version-suffix \"${version-suffix}\" + ) + string(JSON data SET ${data} + distance ${distance} + ) + if (short-hash) + string(JSON data SET ${data} + short-hash \"${short-hash}\" + ) + endif () + + # Mark success and output results + string(JSON data SET ${data} failed false) + message(DEBUG + "Computed data:\n" + " data = ${data}" + ) + file(WRITE ${ARGS_TMP_FOLDER}/.DynamicVersion.json ${data}) endfunction() @@ -664,12 +664,12 @@ endfunction() # Logic to run get_dynamic_version() by running this script if (DynamicVersion_RUN) - if (NOT DEFINED DynamicVersion_ARGS) - message(FATAL_ERROR - "DynamicVersion_ARGS not defined" - ) - endif () - get_dynamic_version(${DynamicVersion_ARGS}) + if (NOT DEFINED DynamicVersion_ARGS) + message(FATAL_ERROR + "DynamicVersion_ARGS not defined" + ) + endif () + get_dynamic_version(${DynamicVersion_ARGS}) endif () list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/PackageComps.cmake b/cmake/PackageComps.cmake index 162f1c3..ef7ac34 100644 --- a/cmake/PackageComps.cmake +++ b/cmake/PackageComps.cmake @@ -10,647 +10,647 @@ list(APPEND CMAKE_MESSAGE_CONTEXT PackageComps) # TODO: Move these to functions with minimal macro that actually does the `include()` macro(get_component _comp) - # Import a specific package component - # - # Macro variables:: - # _comp (string): Package component name - # Named arguments:: - # PACKAGE (string): Project name. Also used as prefix - # LIB_PREFIX (string): Static/Shared library prefix - # FALLBACK_PREFIX (string): Allowed library fallback prefix - # Options - # PRINT: Print results when loading each component - # CHECK_REQUIRED: Check if component is required and not present - - list(APPEND CMAKE_MESSAGE_CONTEXT get_component) - set(ARGS_Options "") - set(ARGS_OneValue "") - set(ARGS_MultiValue "") - list(APPEND ARGS_Options - PRINT - CHECK_REQUIRED - ) - list(APPEND ARGS_OneValue - PACKAGE - LIB_PREFIX - FALLBACK_PREFIX - ) - - cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) - - - if (NOT DEFINED ARGS_PACKAGE) - message(AUTHOR_WARNING - "PACKAGE not passed to get_comp" - ) - set(ARGS_PACKAGE "${CMAKE_FIND_PACKAGE_NAME}") - endif () - if (ARGS_PRINT) - set(stdout_type STATUS) - else () - set(stdout_type VERBOSE) - endif () - - message(${stdout_type} - "Trying to include component: ${_comp}" - ) - - message(DEBUG - "Passed arguments:\n" - "PACKAGE = ${ARGS_PACKAGE}\n" - "_comp = ${_comp}\n" - "LIB_PREFIX = ${ARGS_LIB_PREFIX}\n" - "FALLBACK_PREFIX = ${ARGS_FALLBACK_PREFIX}\n" - "PRINT = ${ARGS_PRINT}\n" - "CHECK_REQUIRED = ${ARGS_CHECK_REQUIRED}\n" - "${ARGS_PACKAGE}_FIND_REQUIRED_${_comp} = ${${ARGS_PACKAGE}_FIND_REQUIRED_${_comp}}\n" - "${ARGS_PACKAGE}_${_comp}_SharedStatic = ${${ARGS_PACKAGE}_${_comp}_SharedStatic}" - ) - - # Set default component to not found - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - - if (DEFINED ARGS_LIB_PREFIX) - # We may have shared/static components - message(DEBUG - "Including ${_comp} with possible shared/static:" - ) - - if (${ARGS_PACKAGE}_${_comp}_SharedStatic) - # If we know it is a shared/static target parse it appropriately - message(DEBUG - "${_comp} has to have shared/static library:" - ) - - # Try to load shared/static library - if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) - # Load the correct library - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) - message(DEBUG - "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake: ${${ARGS_PACKAGE}_FOUND}" - ) - # Check if include was successful - if (${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_LIB_PREFIX}) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp} of type ${ARGS_LIB_PREFIX}" - ) - return() - endif () - elseif (ARGS_FALLBACK_PREFIX) - # Try to load the fallback library if have one - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake OPTIONAL - RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) - message(DEBUG - "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" - ) - # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful - if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_FALLBACK_PREFIX}) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not find component ${_comp} of type ${ARGS_LIB_PREFIX}" - ) - return() - endif () - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp} of either type ${ARGS_LIB_PREFIX} or ${ARGS_FALLBACK_PREFIX}" - ) - return() - endif () - elseif (NOT DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic) - # If we don't know what type of target it is try to load shared/static - message(DEBUG - "${_comp} is of unknown type. Trying to find shared/static:" - ) - if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) - # Load the correct library - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) - message(DEBUG - "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake: ${${ARGS_PACKAGE}_FOUND}" - ) - # Check if include was successful - if (${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_LIB_PREFIX}) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - # Return because we know it is a shared/static component from the presence of the file - message(${stdout_type} - "Could not load component ${_comp} of type ${ARGS_LIB_PREFIX}" - ) - return() - endif () - elseif (ARGS_FALLBACK_PREFIX) - # Try to load the fallback library if have one - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake OPTIONAL - RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) - message(DEBUG - "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" - ) - # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful - if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_FALLBACK_PREFIX}) - elseif (NOT ${ARGS_PACKAGE}_FOUND) - # File was present, but failed to load - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp} of type ${ARGS_FALLBACK_PREFIX}" - ) - return() - else () - unset(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - endif () - endif () - endif () - - # Handle the non-shared/static library targets - if (DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic AND NOT ${ARGS_PACKAGE}_${_comp}_SharedStatic) - # If we know the package is not shared/static library handle it as the main component file - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL - RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) - message(DEBUG - "Including ${ARGS_PACKAGE}Targets_${_comp}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" - ) - # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful - if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp}" - ) - return() - endif () - else () - # Otherwise still try to parse the non shared/static library - message(DEBUG - "Trying to include ${ARGS_PACKAGE}Targets_${_comp}.cmake (${ARGS_PACKAGE}_${_comp}_FOUND=${${ARGS_PACKAGE}_${_comp}_FOUND})" - ) - if (DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic) - # We know it is a static/shared library, only fail if the include has failed, not if it doesn't exist - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL) - if (NOT ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp}" - ) - return() - endif () - else () - # We don't know what type the component is. Try to set it to found ${${ARGS_PACKAGE}_${_comp}_FOUND} - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL - RESULT_VARIABLE _temp_flag) - message(DEBUG - "Include result:\n" - "_temp_flag=${_temp_flag}\n" - "${ARGS_PACKAGE}_${_comp}_FOUND = ${${ARGS_PACKAGE}_${_comp}_FOUND}" - ) - - # Check if either it was static/shared or arbitrary component - if ((${ARGS_PACKAGE}_${_comp}_FOUND OR _temp_flag) AND ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp}" - ) - return() - endif () - endif () - endif () - else () - # We do not have shared/static components - message(DEBUG - "Including ${_comp} without shared/static:" - ) - # Check if required component is installed - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL - RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) - # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful - if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) - set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) - else () - set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) - message(${stdout_type} - "Could not load component ${_comp}" - ) - return() - endif () - endif () - - message(${stdout_type} - "Found component ${_comp} ${${ARGS_PACKAGE}_${_comp}_LIB_TYPE}" - ) + # Import a specific package component + # + # Macro variables:: + # _comp (string): Package component name + # Named arguments:: + # PACKAGE (string): Project name. Also used as prefix + # LIB_PREFIX (string): Static/Shared library prefix + # FALLBACK_PREFIX (string): Allowed library fallback prefix + # Options + # PRINT: Print results when loading each component + # CHECK_REQUIRED: Check if component is required and not present + + list(APPEND CMAKE_MESSAGE_CONTEXT get_component) + set(ARGS_Options "") + set(ARGS_OneValue "") + set(ARGS_MultiValue "") + list(APPEND ARGS_Options + PRINT + CHECK_REQUIRED + ) + list(APPEND ARGS_OneValue + PACKAGE + LIB_PREFIX + FALLBACK_PREFIX + ) + + cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) + + + if (NOT DEFINED ARGS_PACKAGE) + message(AUTHOR_WARNING + "PACKAGE not passed to get_comp" + ) + set(ARGS_PACKAGE "${CMAKE_FIND_PACKAGE_NAME}") + endif () + if (ARGS_PRINT) + set(stdout_type STATUS) + else () + set(stdout_type VERBOSE) + endif () + + message(${stdout_type} + "Trying to include component: ${_comp}" + ) + + message(DEBUG + "Passed arguments:\n" + "PACKAGE = ${ARGS_PACKAGE}\n" + "_comp = ${_comp}\n" + "LIB_PREFIX = ${ARGS_LIB_PREFIX}\n" + "FALLBACK_PREFIX = ${ARGS_FALLBACK_PREFIX}\n" + "PRINT = ${ARGS_PRINT}\n" + "CHECK_REQUIRED = ${ARGS_CHECK_REQUIRED}\n" + "${ARGS_PACKAGE}_FIND_REQUIRED_${_comp} = ${${ARGS_PACKAGE}_FIND_REQUIRED_${_comp}}\n" + "${ARGS_PACKAGE}_${_comp}_SharedStatic = ${${ARGS_PACKAGE}_${_comp}_SharedStatic}" + ) + + # Set default component to not found + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + + if (DEFINED ARGS_LIB_PREFIX) + # We may have shared/static components + message(DEBUG + "Including ${_comp} with possible shared/static:" + ) + + if (${ARGS_PACKAGE}_${_comp}_SharedStatic) + # If we know it is a shared/static target parse it appropriately + message(DEBUG + "${_comp} has to have shared/static library:" + ) + + # Try to load shared/static library + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) + # Load the correct library + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) + message(DEBUG + "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake: ${${ARGS_PACKAGE}_FOUND}" + ) + # Check if include was successful + if (${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_LIB_PREFIX}) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp} of type ${ARGS_LIB_PREFIX}" + ) + return() + endif () + elseif (ARGS_FALLBACK_PREFIX) + # Try to load the fallback library if have one + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake OPTIONAL + RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) + message(DEBUG + "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" + ) + # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful + if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_FALLBACK_PREFIX}) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not find component ${_comp} of type ${ARGS_LIB_PREFIX}" + ) + return() + endif () + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp} of either type ${ARGS_LIB_PREFIX} or ${ARGS_FALLBACK_PREFIX}" + ) + return() + endif () + elseif (NOT DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic) + # If we don't know what type of target it is try to load shared/static + message(DEBUG + "${_comp} is of unknown type. Trying to find shared/static:" + ) + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) + # Load the correct library + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake) + message(DEBUG + "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_LIB_PREFIX}.cmake: ${${ARGS_PACKAGE}_FOUND}" + ) + # Check if include was successful + if (${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_LIB_PREFIX}) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + # Return because we know it is a shared/static component from the presence of the file + message(${stdout_type} + "Could not load component ${_comp} of type ${ARGS_LIB_PREFIX}" + ) + return() + endif () + elseif (ARGS_FALLBACK_PREFIX) + # Try to load the fallback library if have one + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake OPTIONAL + RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) + message(DEBUG + "Including ${ARGS_PACKAGE}Targets_${_comp}_${ARGS_FALLBACK_PREFIX}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" + ) + # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful + if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + set(${ARGS_PACKAGE}_${_comp}_LIB_TYPE ${ARGS_FALLBACK_PREFIX}) + elseif (NOT ${ARGS_PACKAGE}_FOUND) + # File was present, but failed to load + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp} of type ${ARGS_FALLBACK_PREFIX}" + ) + return() + else () + unset(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + endif () + endif () + endif () + + # Handle the non-shared/static library targets + if (DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic AND NOT ${ARGS_PACKAGE}_${_comp}_SharedStatic) + # If we know the package is not shared/static library handle it as the main component file + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL + RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) + message(DEBUG + "Including ${ARGS_PACKAGE}Targets_${_comp}.cmake: ${${ARGS_PACKAGE}_${_comp}_FOUND}" + ) + # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful + if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp}" + ) + return() + endif () + else () + # Otherwise still try to parse the non shared/static library + message(DEBUG + "Trying to include ${ARGS_PACKAGE}Targets_${_comp}.cmake (${ARGS_PACKAGE}_${_comp}_FOUND=${${ARGS_PACKAGE}_${_comp}_FOUND})" + ) + if (DEFINED ${ARGS_PACKAGE}_${_comp}_SharedStatic) + # We know it is a static/shared library, only fail if the include has failed, not if it doesn't exist + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL) + if (NOT ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp}" + ) + return() + endif () + else () + # We don't know what type the component is. Try to set it to found ${${ARGS_PACKAGE}_${_comp}_FOUND} + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL + RESULT_VARIABLE _temp_flag) + message(DEBUG + "Include result:\n" + "_temp_flag=${_temp_flag}\n" + "${ARGS_PACKAGE}_${_comp}_FOUND = ${${ARGS_PACKAGE}_${_comp}_FOUND}" + ) + + # Check if either it was static/shared or arbitrary component + if ((${ARGS_PACKAGE}_${_comp}_FOUND OR _temp_flag) AND ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp}" + ) + return() + endif () + endif () + endif () + else () + # We do not have shared/static components + message(DEBUG + "Including ${_comp} without shared/static:" + ) + # Check if required component is installed + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_comp}.cmake OPTIONAL + RESULT_VARIABLE ${ARGS_PACKAGE}_${_comp}_FOUND) + # Reformat Comp_FOUND variable to TRUE/FALSE and check if include was successful + if (${ARGS_PACKAGE}_${_comp}_FOUND AND ${ARGS_PACKAGE}_FOUND) + set(${ARGS_PACKAGE}_${_comp}_FOUND TRUE) + else () + set(${ARGS_PACKAGE}_${_comp}_FOUND FALSE) + message(${stdout_type} + "Could not load component ${_comp}" + ) + return() + endif () + endif () + + message(${stdout_type} + "Found component ${_comp} ${${ARGS_PACKAGE}_${_comp}_LIB_TYPE}" + ) endmacro() macro(find_components) - # Include all available components - # - # Requires a target file format equivalent to those generated by `export_component` - # - # Named arguments:: - # COMPONENTS (list): List of supported components (without deprecated components). If empty will just load global target - # DEPRECATED_COMPONENTS (list): List of deprecated components. - # Options - # PRINT: Print results when loading each component - # LOAD_ALL_DEFAULT: Load all supported components if no components are passed - # HAVE_GLOBAL: Whether global targets file is defined (see bellow) - # HAVE_GLOBAL_SHARED_STATIC: Whether global static/shared targets file is defined (see bellow) - # Assumptions :: - # Defined variables in ${PACKAGE}Config.cmake file:: - # ${PACKAGE}__Replacement (string): Replacement components for component . If not defined will ignore. - # ${PACKAGE}__SharedStatic (bool): Whether the component should have static/shared targets. If not defined will try to find target. - # Name format of target files: - # ${PACKAGE}Targets.cmake: Global targets - # ${PACKAGE}Targets-{static/shared}.cmake: Global static/shared library targets - # ${PACKAGE}Targets-.cmake: Component targets - # ${PACKAGE}Targets-{static/shared}-.cmake: Static/Shared component library targets - # - # For a reference to the find_package variables check: - # https://cmake.org/cmake/help/latest/command/find_package.html#package-file-interface-variables - - list(APPEND CMAKE_MESSAGE_CONTEXT find_components) - set(ARGS_Options "") - set(ARGS_OneValue "") - set(ARGS_MultiValue "") - list(APPEND ARGS_Options - PRINT - LOAD_ALL_DEFAULT - HAVE_GLOBAL - HAVE_GLOBAL_SHARED_STATIC - ) - list(APPEND ARGS_MultiValue - COMPONENTS - DEPRECATED_COMPONENTS - ) - - cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) - - ## Basic checks - set(ARGS_PACKAGE ${CMAKE_FIND_PACKAGE_NAME}) - if (NOT DEFINED ARGS_COMPONENTS AND DEFINED ${ARGS_PACKAGE}_Supported_Comps) - set(ARGS_COMPONENTS ${${ARGS_PACKAGE}_Supported_Comps}) - endif () - if (NOT DEFINED ARGS_DEPRECATED_COMPONENTS AND DEFINED ${ARGS_PACKAGE}_Deprecated_Comps) - set(ARGS_DEPRECATED_COMPONENTS ${${ARGS_PACKAGE}_Deprecated_Comps}) - elseif (NOT DEFINED ARGS_DEPRECATED_COMPONENTS) - set(ARGS_DEPRECATED_COMPONENTS "") - endif () - - if (ARGS_PRINT) - set(stdout_type STATUS) - else () - set(stdout_type VERBOSE) - endif () - - - # Setting package found to true by default - # Using `include()` on `Targets.cmake` will set `_FOUND` to false if it errors - set(${ARGS_PACKAGE}_FOUND TRUE) - - message(${stdout_type} - "Looking for package components of ${ARGS_PACKAGE}" - ) - message(DEBUG - "Passed arguments:\n" - "PACKAGE = ${ARGS_PACKAGE}\n" - "COMPONENTS = ${ARGS_COMPONENTS}\n" - "DEPRECATED_COMPONENTS = ${ARGS_DEPRECATED_COMPONENTS}\n" - "LOAD_ALL_DEFAULT = ${ARGS_LOAD_ALL_DEFAULT}\n" - "HAVE_GLOBAL = ${ARGS_HAVE_GLOBAL}\n" - "HAVE_GLOBAL_SHARED_STATIC = ${ARGS_HAVE_GLOBAL_SHARED_STATIC}\n" - "${ARGS_PACKAGE}_FIND_COMPONENTS = ${${ARGS_PACKAGE}_FIND_COMPONENTS}" - ) - file(GLOB _cmake_target_files RELATIVE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*) - message(DEBUG - "CMAKE_CURRENT_LIST_DIR = ${CMAKE_CURRENT_LIST_DIR}\n" - "Files: ${_cmake_target_files}" - ) - - if (NOT DEFINED ARGS_COMPONENTS) - # End early if no component logic is defined - if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) - message(WARNING - "No ${ARGS_PACKAGE}Targets.cmake file bundled. (Report to package distributor of ${ARGS_PACKAGE})" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - else () - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) - message(${stdout_type} - "Found package: ${ARGS_PACKAGE} -> ${${ARGS_PACKAGE}_FOUND}" - ) - endif () - return() - else () - # Check if package support shared/static components - if ("shared" IN_LIST ARGS_COMPONENTS AND "static" IN_LIST ARGS_COMPONENTS) - set(_with_shared_static TRUE) - elseif (NOT "shared" IN_LIST ARGS_COMPONENTS AND NOT "static" IN_LIST ARGS_COMPONENTS) - set(_with_shared_static FALSE) - else () - message(FATAL_ERROR - "COMPONENTS list is incompatible\n" - "Please include both `static` and `shared` components" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - endif () - - # Set subfunction options - set(sub_func_ARGS "") - list(APPEND - PACKAGE ${ARGS_PACKAGE}) - if (ARGS_PRINT) - list(APPEND sub_func_ARGS PRINT) - endif () - - # Initialize components check - set(${ARGS_PACKAGE}_COMPONENTS "") - - # Check for unknown components - # TODO: Not checking for different name used in ${CMAKE_FIND_PACKAGE_NAME} - foreach (comp IN LISTS ${ARGS_PACKAGE}_FIND_COMPONENTS) - if (NOT comp IN_LIST ARGS_COMPONENTS) - if (comp IN_LIST ARGS_DEPRECATED_COMPONENTS) - set(extra_msg "") - if (DEFINED ${ARGS_PACKAGE}_${comp}_Replacement) - list(APPEND ${ARGS_PACKAGE}_FIND_COMPONENTS ${${ARGS_PACKAGE}_${comp}_Replacement}) - set(extra_msg "Replace component: ${comp} -> ${${ARGS_PACKAGE}_${comp}_Replacement}") - else () - set(extra_msg "Importing ${comp} has now no effect") - endif () - message(DEPRECATION - "Trying to import deprecated component of package: ${ARGS_PACKAGE}\n" - "Deprecated component: ${comp}\n" - "${extra_msg}" - ) - list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS ${comp}) - else () - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Trying to import unknown component of package: ${ARGS_PACKAGE}\n" - "Unsupported component: ${comp}" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - endif () - endforeach () - - # Handle shared and static components - if (_with_shared_static) - # Error if both shared and static components are requested - if ("shared" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS AND "static" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Cannot load both `shared` and `static` components at the same time. Select only one of those two" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - - # Get the shared/static targets to be loaded - if ("shared" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) - list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS shared) - set(_libPrefix shared) - elseif ("static" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) - list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS static) - set(_libPrefix static) - elseif (DEFINED ${ARGS_PACKAGE}_SHARED_LIBS) - if (${ARGS_PACKAGE}_SHARED_LIBS) - set(_libPrefix shared) - else () - set(_libPrefix static) - endif () - else () - if (DEFINED BUILD_SHARED_LIBS AND NOT BUILD_SHARED_LIBS) - set(_libPrefix static) - set(_fallbackPrefix shared) - else () - set(_libPrefix shared) - set(_fallbackPrefix static) - endif () - endif () - list(APPEND sub_func_ARGS LIB_PREFIX ${_libPrefix}) - if (DEFINED _fallbackPrefix) - list(APPEND sub_func_ARGS FALLBACK_PREFIX ${_fallbackPrefix}) - endif () - endif () - - message(DEBUG - "_with_shared_static = ${_with_shared_static}\n" - "_libPrefix = ${_libPrefix}\n" - "_fallbackPrefix = ${_fallbackPrefix}\n" - "sub_func_ARGS = ${sub_func_ARGS}" - ) - - # Parse global targets - # Note: These have to be parsed before components in case components depend on it. - # Global targets should not have component dependencies - if (ARGS_HAVE_GLOBAL) - message(VERBOSE - "Trying to include ${ARGS_PACKAGE}Targets.cmake" - ) - if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) - if (NOT ${ARGS_PACKAGE}_FOUND) - # Check if include was successful - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Could not load file: ${ARGS_PACKAGE}Targets.cmake" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - else () - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Missing file: ${ARGS_PACKAGE}Targets.cmake (Report to package distributor of ${ARGS_PACKAGE})" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - endif () - - # Parse global static/shared targets - if (_with_shared_static AND ARGS_HAVE_GLOBAL_SHARED_STATIC) - message(VERBOSE - "Trying to include ${ARGS_PACKAGE}Targets_${_libPrefix}.cmake (or ${_fallbackPrefix})" - ) - if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_libPrefix}.cmake) - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_libPrefix}.cmake) - set(${ARGS_PACKAGE}_LIB_TYPE ${_libPrefix}) - elseif (DEFINED _fallbackPrefix AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_fallbackPrefix}.cmake) - include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_fallbackPrefix}.cmake) - set(${ARGS_PACKAGE}_LIB_TYPE ${_fallbackPrefix}) - else () - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Could not load static/shared component: ${_libPrefix}\n" - "Missing file: ${ARGS_PACKAGE}Targets_${_libPrefix}.cmake" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - if (NOT ${ARGS_PACKAGE}_FOUND) - # Check if include was successful - message(WARNING - "Failed to load package: ${ARGS_PACKAGE}\n" - "Could not load file: ${ARGS_PACKAGE}Targets_${${ARGS_PACKAGE}_LIB_TYPE}.cmake" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - endif () - - # Parse components - if (${ARGS_PACKAGE}_FIND_COMPONENTS) - # If specific components are passed handle only these components - message(VERBOSE - "Trying to search for specific components: ${${ARGS_PACKAGE}_FIND_COMPONENTS}" - ) - foreach (comp IN LISTS ${ARGS_PACKAGE}_FIND_COMPONENTS) - # Should make sure _FOUND is always true to know if component is found or not - set(${ARGS_PACKAGE}_FOUND TRUE) - get_component(${comp} CHECK_REQUIRED ${sub_func_ARGS}) - if (${ARGS_PACKAGE}_FIND_REQUIRED_${comp} AND NOT ${ARGS_PACKAGE}_${comp}_FOUND) - message(DEBUG - "Failed to load package: ${ARGS_PACKAGE}\n" - "Could not load component: ${comp}" - ) - set(${ARGS_PACKAGE}_FOUND FALSE) - return() - endif () - # Append components found - list(APPEND ${ARGS_PACKAGE}_COMPONENTS ${comp}) - endforeach () - elseif (ARGS_LOAD_ALL_DEFAULT) - # If no components are passed and ${_load_all_default} is true, get all supported components - list(REMOVE_ITEM ARGS_COMPONENTS "static" "shared") - message(VERBOSE - "Trying to search for all components: ${ARGS_COMPONENTS}" - ) - foreach (comp IN LISTS ARGS_COMPONENTS) - # Should make sure _FOUND is always true to know if component is found or not - set(${ARGS_PACKAGE}_FOUND TRUE) - get_component(${comp} ${sub_func_ARGS}) - if (${ARGS_PACKAGE}_${comp}_FOUND) - # No need to fail if component not found. Just add the successful ones - list(APPEND ${ARGS_PACKAGE}_COMPONENTS ${comp}) - endif () - endforeach () - # At the end some components might have set _FOUND false. Reset it to true because these are optional - set(${ARGS_PACKAGE}_FOUND TRUE) - endif () - - # Final print status - message(${stdout_type} - "Found package: ${ARGS_PACKAGE}" - ) + # Include all available components + # + # Requires a target file format equivalent to those generated by `export_component` + # + # Named arguments:: + # COMPONENTS (list): List of supported components (without deprecated components). If empty will just load global target + # DEPRECATED_COMPONENTS (list): List of deprecated components. + # Options + # PRINT: Print results when loading each component + # LOAD_ALL_DEFAULT: Load all supported components if no components are passed + # HAVE_GLOBAL: Whether global targets file is defined (see bellow) + # HAVE_GLOBAL_SHARED_STATIC: Whether global static/shared targets file is defined (see bellow) + # Assumptions :: + # Defined variables in ${PACKAGE}Config.cmake file:: + # ${PACKAGE}__Replacement (string): Replacement components for component . If not defined will ignore. + # ${PACKAGE}__SharedStatic (bool): Whether the component should have static/shared targets. If not defined will try to find target. + # Name format of target files: + # ${PACKAGE}Targets.cmake: Global targets + # ${PACKAGE}Targets-{static/shared}.cmake: Global static/shared library targets + # ${PACKAGE}Targets-.cmake: Component targets + # ${PACKAGE}Targets-{static/shared}-.cmake: Static/Shared component library targets + # + # For a reference to the find_package variables check: + # https://cmake.org/cmake/help/latest/command/find_package.html#package-file-interface-variables + + list(APPEND CMAKE_MESSAGE_CONTEXT find_components) + set(ARGS_Options "") + set(ARGS_OneValue "") + set(ARGS_MultiValue "") + list(APPEND ARGS_Options + PRINT + LOAD_ALL_DEFAULT + HAVE_GLOBAL + HAVE_GLOBAL_SHARED_STATIC + ) + list(APPEND ARGS_MultiValue + COMPONENTS + DEPRECATED_COMPONENTS + ) + + cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) + + ## Basic checks + set(ARGS_PACKAGE ${CMAKE_FIND_PACKAGE_NAME}) + if (NOT DEFINED ARGS_COMPONENTS AND DEFINED ${ARGS_PACKAGE}_Supported_Comps) + set(ARGS_COMPONENTS ${${ARGS_PACKAGE}_Supported_Comps}) + endif () + if (NOT DEFINED ARGS_DEPRECATED_COMPONENTS AND DEFINED ${ARGS_PACKAGE}_Deprecated_Comps) + set(ARGS_DEPRECATED_COMPONENTS ${${ARGS_PACKAGE}_Deprecated_Comps}) + elseif (NOT DEFINED ARGS_DEPRECATED_COMPONENTS) + set(ARGS_DEPRECATED_COMPONENTS "") + endif () + + if (ARGS_PRINT) + set(stdout_type STATUS) + else () + set(stdout_type VERBOSE) + endif () + + + # Setting package found to true by default + # Using `include()` on `Targets.cmake` will set `_FOUND` to false if it errors + set(${ARGS_PACKAGE}_FOUND TRUE) + + message(${stdout_type} + "Looking for package components of ${ARGS_PACKAGE}" + ) + message(DEBUG + "Passed arguments:\n" + "PACKAGE = ${ARGS_PACKAGE}\n" + "COMPONENTS = ${ARGS_COMPONENTS}\n" + "DEPRECATED_COMPONENTS = ${ARGS_DEPRECATED_COMPONENTS}\n" + "LOAD_ALL_DEFAULT = ${ARGS_LOAD_ALL_DEFAULT}\n" + "HAVE_GLOBAL = ${ARGS_HAVE_GLOBAL}\n" + "HAVE_GLOBAL_SHARED_STATIC = ${ARGS_HAVE_GLOBAL_SHARED_STATIC}\n" + "${ARGS_PACKAGE}_FIND_COMPONENTS = ${${ARGS_PACKAGE}_FIND_COMPONENTS}" + ) + file(GLOB _cmake_target_files RELATIVE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*) + message(DEBUG + "CMAKE_CURRENT_LIST_DIR = ${CMAKE_CURRENT_LIST_DIR}\n" + "Files: ${_cmake_target_files}" + ) + + if (NOT DEFINED ARGS_COMPONENTS) + # End early if no component logic is defined + if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) + message(WARNING + "No ${ARGS_PACKAGE}Targets.cmake file bundled. (Report to package distributor of ${ARGS_PACKAGE})" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + else () + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) + message(${stdout_type} + "Found package: ${ARGS_PACKAGE} -> ${${ARGS_PACKAGE}_FOUND}" + ) + endif () + return() + else () + # Check if package support shared/static components + if ("shared" IN_LIST ARGS_COMPONENTS AND "static" IN_LIST ARGS_COMPONENTS) + set(_with_shared_static TRUE) + elseif (NOT "shared" IN_LIST ARGS_COMPONENTS AND NOT "static" IN_LIST ARGS_COMPONENTS) + set(_with_shared_static FALSE) + else () + message(FATAL_ERROR + "COMPONENTS list is incompatible\n" + "Please include both `static` and `shared` components" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + endif () + + # Set subfunction options + set(sub_func_ARGS "") + list(APPEND + PACKAGE ${ARGS_PACKAGE}) + if (ARGS_PRINT) + list(APPEND sub_func_ARGS PRINT) + endif () + + # Initialize components check + set(${ARGS_PACKAGE}_COMPONENTS "") + + # Check for unknown components + # TODO: Not checking for different name used in ${CMAKE_FIND_PACKAGE_NAME} + foreach (comp IN LISTS ${ARGS_PACKAGE}_FIND_COMPONENTS) + if (NOT comp IN_LIST ARGS_COMPONENTS) + if (comp IN_LIST ARGS_DEPRECATED_COMPONENTS) + set(extra_msg "") + if (DEFINED ${ARGS_PACKAGE}_${comp}_Replacement) + list(APPEND ${ARGS_PACKAGE}_FIND_COMPONENTS ${${ARGS_PACKAGE}_${comp}_Replacement}) + set(extra_msg "Replace component: ${comp} -> ${${ARGS_PACKAGE}_${comp}_Replacement}") + else () + set(extra_msg "Importing ${comp} has now no effect") + endif () + message(DEPRECATION + "Trying to import deprecated component of package: ${ARGS_PACKAGE}\n" + "Deprecated component: ${comp}\n" + "${extra_msg}" + ) + list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS ${comp}) + else () + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Trying to import unknown component of package: ${ARGS_PACKAGE}\n" + "Unsupported component: ${comp}" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + endif () + endforeach () + + # Handle shared and static components + if (_with_shared_static) + # Error if both shared and static components are requested + if ("shared" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS AND "static" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Cannot load both `shared` and `static` components at the same time. Select only one of those two" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + + # Get the shared/static targets to be loaded + if ("shared" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) + list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS shared) + set(_libPrefix shared) + elseif ("static" IN_LIST ${ARGS_PACKAGE}_FIND_COMPONENTS) + list(REMOVE_ITEM ${ARGS_PACKAGE}_FIND_COMPONENTS static) + set(_libPrefix static) + elseif (DEFINED ${ARGS_PACKAGE}_SHARED_LIBS) + if (${ARGS_PACKAGE}_SHARED_LIBS) + set(_libPrefix shared) + else () + set(_libPrefix static) + endif () + else () + if (DEFINED BUILD_SHARED_LIBS AND NOT BUILD_SHARED_LIBS) + set(_libPrefix static) + set(_fallbackPrefix shared) + else () + set(_libPrefix shared) + set(_fallbackPrefix static) + endif () + endif () + list(APPEND sub_func_ARGS LIB_PREFIX ${_libPrefix}) + if (DEFINED _fallbackPrefix) + list(APPEND sub_func_ARGS FALLBACK_PREFIX ${_fallbackPrefix}) + endif () + endif () + + message(DEBUG + "_with_shared_static = ${_with_shared_static}\n" + "_libPrefix = ${_libPrefix}\n" + "_fallbackPrefix = ${_fallbackPrefix}\n" + "sub_func_ARGS = ${sub_func_ARGS}" + ) + + # Parse global targets + # Note: These have to be parsed before components in case components depend on it. + # Global targets should not have component dependencies + if (ARGS_HAVE_GLOBAL) + message(VERBOSE + "Trying to include ${ARGS_PACKAGE}Targets.cmake" + ) + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets.cmake) + if (NOT ${ARGS_PACKAGE}_FOUND) + # Check if include was successful + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Could not load file: ${ARGS_PACKAGE}Targets.cmake" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + else () + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Missing file: ${ARGS_PACKAGE}Targets.cmake (Report to package distributor of ${ARGS_PACKAGE})" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + endif () + + # Parse global static/shared targets + if (_with_shared_static AND ARGS_HAVE_GLOBAL_SHARED_STATIC) + message(VERBOSE + "Trying to include ${ARGS_PACKAGE}Targets_${_libPrefix}.cmake (or ${_fallbackPrefix})" + ) + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_libPrefix}.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_libPrefix}.cmake) + set(${ARGS_PACKAGE}_LIB_TYPE ${_libPrefix}) + elseif (DEFINED _fallbackPrefix AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_fallbackPrefix}.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/${ARGS_PACKAGE}Targets_${_fallbackPrefix}.cmake) + set(${ARGS_PACKAGE}_LIB_TYPE ${_fallbackPrefix}) + else () + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Could not load static/shared component: ${_libPrefix}\n" + "Missing file: ${ARGS_PACKAGE}Targets_${_libPrefix}.cmake" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + if (NOT ${ARGS_PACKAGE}_FOUND) + # Check if include was successful + message(WARNING + "Failed to load package: ${ARGS_PACKAGE}\n" + "Could not load file: ${ARGS_PACKAGE}Targets_${${ARGS_PACKAGE}_LIB_TYPE}.cmake" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + endif () + + # Parse components + if (${ARGS_PACKAGE}_FIND_COMPONENTS) + # If specific components are passed handle only these components + message(VERBOSE + "Trying to search for specific components: ${${ARGS_PACKAGE}_FIND_COMPONENTS}" + ) + foreach (comp IN LISTS ${ARGS_PACKAGE}_FIND_COMPONENTS) + # Should make sure _FOUND is always true to know if component is found or not + set(${ARGS_PACKAGE}_FOUND TRUE) + get_component(${comp} CHECK_REQUIRED ${sub_func_ARGS}) + if (${ARGS_PACKAGE}_FIND_REQUIRED_${comp} AND NOT ${ARGS_PACKAGE}_${comp}_FOUND) + message(DEBUG + "Failed to load package: ${ARGS_PACKAGE}\n" + "Could not load component: ${comp}" + ) + set(${ARGS_PACKAGE}_FOUND FALSE) + return() + endif () + # Append components found + list(APPEND ${ARGS_PACKAGE}_COMPONENTS ${comp}) + endforeach () + elseif (ARGS_LOAD_ALL_DEFAULT) + # If no components are passed and ${_load_all_default} is true, get all supported components + list(REMOVE_ITEM ARGS_COMPONENTS "static" "shared") + message(VERBOSE + "Trying to search for all components: ${ARGS_COMPONENTS}" + ) + foreach (comp IN LISTS ARGS_COMPONENTS) + # Should make sure _FOUND is always true to know if component is found or not + set(${ARGS_PACKAGE}_FOUND TRUE) + get_component(${comp} ${sub_func_ARGS}) + if (${ARGS_PACKAGE}_${comp}_FOUND) + # No need to fail if component not found. Just add the successful ones + list(APPEND ${ARGS_PACKAGE}_COMPONENTS ${comp}) + endif () + endforeach () + # At the end some components might have set _FOUND false. Reset it to true because these are optional + set(${ARGS_PACKAGE}_FOUND TRUE) + endif () + + # Final print status + message(${stdout_type} + "Found package: ${ARGS_PACKAGE}" + ) endmacro() function(export_component) - # Export package component - # - # Designed to be compatible with `find_components` - # - # Named arguments:: - # PROJECT (string) [${PROJECT_NAME}]: Project name. Also used as prefix - # TARGET (string) [${PROJECT}Targets or ${PROJECT}Targets-${COMPONENT}]: Target export component - # COMPONENT (string): Package component - # LIB_TYPE (string) : Whether the target is shared/static or general - - list(APPEND CMAKE_MESSAGE_CONTEXT export_component) - set(ARGS_Options "") - set(ARGS_OneValue "") - set(ARGS_MultiValue "") - list(APPEND ARGS_Options - PRINT - ) - list(APPEND ARGS_OneValue - PROJECT - TARGET - COMPONENT - LIB_TYPE - ) - set(LIB_TYPE_Choices "") - list(APPEND LIB_TYPE_Choices static shared) - - # Include GNUInstallDirs if not done already - if (NOT DEFINED CMAKE_INSTALL_DATAROOTDIR) - include(GNUInstallDirs) - endif () - - # Choose appropriate target install location - get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) - if (NOT ENABLED_LANGUAGES) - set(install_prefix ${CMAKE_INSTALL_DATAROOTDIR}) - else () - set(install_prefix ${CMAKE_INSTALL_LIBDIR}) - endif () - - cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) - - if (NOT DEFINED ARGS_PROJECT) - set(ARGS_PROJECT "${PROJECT_NAME}") - endif () - if (DEFINED ARGS_LIB_TYPE AND NOT ARGS_LIB_TYPE IN_LIST LIB_TYPE_Choices) - message(FATAL_ERROR - "Unknown LIB_TYPE passed: ${ARGS_LIB_TYPE}\n" - " Valid choices: ${LIB_TYPE_Choices}") - endif () - - if (ARGS_PRINT) - set(stdout_type STATUS) - else () - set(stdout_type VERBOSE) - endif () - - # Configure target and target file - if (ARGS_COMPONENT) - if (NOT DEFINED ARGS_TARGET) - set(ARGS_TARGET "${ARGS_PROJECT}Targets-${ARGS_COMPONENT}") - endif () - if (ARGS_LIB_TYPE) - set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_COMPONENT}_${ARGS_LIB_TYPE}.cmake") - else () - set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_COMPONENT}.cmake") - endif () - else () - if (NOT DEFINED ARGS_TARGET) - set(ARGS_TARGET "${ARGS_PROJECT}Targets") - endif () - if (ARGS_LIB_TYPE) - set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_LIB_TYPE}.cmake") - else () - set(TargetFile "${ARGS_PROJECT}Targets.cmake") - endif () - endif () - - install(EXPORT ${ARGS_TARGET} - FILE ${TargetFile} - NAMESPACE ${ARGS_PROJECT}:: - DESTINATION ${install_prefix}/cmake/${ARGS_PROJECT} - COMPONENT ${ARGS_PROJECT}_Development) - export(EXPORT ${ARGS_TARGET} - FILE ${TargetFile} - NAMESPACE ${ARGS_PROJECT}::) - - message(${stdout_type} - "Configured package component for export\n" - " Target: ${Target}\n" - " TargetFile: ${TargetFile}" - ) + # Export package component + # + # Designed to be compatible with `find_components` + # + # Named arguments:: + # PROJECT (string) [${PROJECT_NAME}]: Project name. Also used as prefix + # TARGET (string) [${PROJECT}Targets or ${PROJECT}Targets-${COMPONENT}]: Target export component + # COMPONENT (string): Package component + # LIB_TYPE (string) : Whether the target is shared/static or general + + list(APPEND CMAKE_MESSAGE_CONTEXT export_component) + set(ARGS_Options "") + set(ARGS_OneValue "") + set(ARGS_MultiValue "") + list(APPEND ARGS_Options + PRINT + ) + list(APPEND ARGS_OneValue + PROJECT + TARGET + COMPONENT + LIB_TYPE + ) + set(LIB_TYPE_Choices "") + list(APPEND LIB_TYPE_Choices static shared) + + # Include GNUInstallDirs if not done already + if (NOT DEFINED CMAKE_INSTALL_DATAROOTDIR) + include(GNUInstallDirs) + endif () + + # Choose appropriate target install location + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + if (NOT ENABLED_LANGUAGES) + set(install_prefix ${CMAKE_INSTALL_DATAROOTDIR}) + else () + set(install_prefix ${CMAKE_INSTALL_LIBDIR}) + endif () + + cmake_parse_arguments(ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}" ${ARGN}) + + if (NOT DEFINED ARGS_PROJECT) + set(ARGS_PROJECT "${PROJECT_NAME}") + endif () + if (DEFINED ARGS_LIB_TYPE AND NOT ARGS_LIB_TYPE IN_LIST LIB_TYPE_Choices) + message(FATAL_ERROR + "Unknown LIB_TYPE passed: ${ARGS_LIB_TYPE}\n" + " Valid choices: ${LIB_TYPE_Choices}") + endif () + + if (ARGS_PRINT) + set(stdout_type STATUS) + else () + set(stdout_type VERBOSE) + endif () + + # Configure target and target file + if (ARGS_COMPONENT) + if (NOT DEFINED ARGS_TARGET) + set(ARGS_TARGET "${ARGS_PROJECT}Targets-${ARGS_COMPONENT}") + endif () + if (ARGS_LIB_TYPE) + set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_COMPONENT}_${ARGS_LIB_TYPE}.cmake") + else () + set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_COMPONENT}.cmake") + endif () + else () + if (NOT DEFINED ARGS_TARGET) + set(ARGS_TARGET "${ARGS_PROJECT}Targets") + endif () + if (ARGS_LIB_TYPE) + set(TargetFile "${ARGS_PROJECT}Targets_${ARGS_LIB_TYPE}.cmake") + else () + set(TargetFile "${ARGS_PROJECT}Targets.cmake") + endif () + endif () + + install(EXPORT ${ARGS_TARGET} + FILE ${TargetFile} + NAMESPACE ${ARGS_PROJECT}:: + DESTINATION ${install_prefix}/cmake/${ARGS_PROJECT} + COMPONENT ${ARGS_PROJECT}_Development) + export(EXPORT ${ARGS_TARGET} + FILE ${TargetFile} + NAMESPACE ${ARGS_PROJECT}::) + + message(${stdout_type} + "Configured package component for export\n" + " Target: ${Target}\n" + " TargetFile: ${TargetFile}" + ) endfunction() list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/docs/README.md b/docs/README.md index c4249db..cf32de5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,5 +35,7 @@ markdown files in [`cmake_modules`](cmake_modules) folder, e.g. [`DynamicVersion Other personal standards applied: - Use markdown file format only -- Use [colon-fence](https://myst-parser.readthedocs.io/en/v1.0.0/syntax/optional.html#code-fences-using-colons) `:::` instead of triple-tick ```` ``` ```` -- Use [yaml](https://myst-parser.readthedocs.io/en/v1.0.0/configuration.html#frontmatter-local-configuration) for directive configurations +- Use [colon-fence](https://myst-parser.readthedocs.io/en/v1.0.0/syntax/optional.html#code-fences-using-colons) `::` + instead of triple-tick \`\`\` +- Use [yaml](https://myst-parser.readthedocs.io/en/v1.0.0/configuration.html#frontmatter-local-configuration) for + directive configurations diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 45be992..7960574 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,93 +1,93 @@ cmake_minimum_required(VERSION 3.20) list(APPEND CMAKE_MESSAGE_CONTEXT Test) project(CMakeExtraUtils_test - LANGUAGES NONE + LANGUAGES NONE ) enable_testing() # Not importing CMakeExtraUtils itself here since these will always be done by internal cmake projects function(CMakeExtraUtils_add_test test) - #[===[.md - # CMakeExtraUtils_add_test + #[===[.md + # CMakeExtraUtils_add_test - Internal helper for adding functional tests specific for the current template project + Internal helper for adding functional tests specific for the current template project - ## Synopsis - ```cmake - CMakeExtraUtils_add_test( - [TEST_NAME ] - [TARGET ] - [LABELS ]) - ``` + ## Synopsis + ```cmake + CMakeExtraUtils_add_test( + [TEST_NAME ] + [TARGET ] + [LABELS ]) + ``` - ## Options + ## Options - `` - Path to the CMake project to be executed relative to `${CMAKE_CURRENT_SOURCE_DIR}` + `` + Path to the CMake project to be executed relative to `${CMAKE_CURRENT_SOURCE_DIR}` - `TEST_NAME` [Default: ``] - Name for the test to be used as the ctest name + `TEST_NAME` [Default: ``] + Name for the test to be used as the ctest name - `LABELS` - Additional labels to be added + `LABELS` + Additional labels to be added - ]===] + ]===] - list(APPEND CMAKE_MESSAGE_CONTEXT "CMakeExtraUtils_add_test") + list(APPEND CMAKE_MESSAGE_CONTEXT "CMakeExtraUtils_add_test") - set(ARGS_Options) - set(ARGS_OneValue - TEST_NAME - ) - set(ARGS_MultiValue - LABELS - ) - cmake_parse_arguments(PARSE_ARGV 1 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") - # Check required/optional arguments - if (ARGC LESS 1) - message(FATAL_ERROR "Missing test name") - endif () - if (NOT DEFINED ARGS_TEST_NAME) - set(ARGS_TEST_NAME ${test}) - endif () - set(extra_args) - if (CMakeExtraUtils_IS_TOP_LEVEL) - # If it's run by main project use the export paths - list(APPEND extra_args - -DFETCHCONTENT_TRY_FIND_PACKAGE_MODE=ALWAYS - # Generated Config file point to binary targets until it is installed - -DCMakeExtraUtils_ROOT=${CMakeExtraUtils_BINARY_DIR} - -DFETCHCONTENT_SOURCE_DIR_CMAKEEXTRAUTILS=${CMakeExtraUtils_SOURCE_DIR} - ) - elseif (DEFINED CMakeExtraUtils_ROOT) - # Alternatively, if it's run by the tmt runner, CMakeExtraUtils is either pre-installed or we have pre-built it - # and exported to `CMakeExtraUtils_ROOT` - list(APPEND extra_args - -DCMakeExtraUtils_ROOT=${CMakeExtraUtils_ROOT} - ) - endif () + set(ARGS_Options) + set(ARGS_OneValue + TEST_NAME + ) + set(ARGS_MultiValue + LABELS + ) + cmake_parse_arguments(PARSE_ARGV 1 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") + # Check required/optional arguments + if (ARGC LESS 1) + message(FATAL_ERROR "Missing test name") + endif () + if (NOT DEFINED ARGS_TEST_NAME) + set(ARGS_TEST_NAME ${test}) + endif () + set(extra_args) + if (CMakeExtraUtils_IS_TOP_LEVEL) + # If it's run by main project use the export paths + list(APPEND extra_args + -DFETCHCONTENT_TRY_FIND_PACKAGE_MODE=ALWAYS + # Generated Config file point to binary targets until it is installed + -DCMakeExtraUtils_ROOT=${CMakeExtraUtils_BINARY_DIR} + -DFETCHCONTENT_SOURCE_DIR_CMAKEEXTRAUTILS=${CMakeExtraUtils_SOURCE_DIR} + ) + elseif (DEFINED CMakeExtraUtils_ROOT) + # Alternatively, if it's run by the tmt runner, CMakeExtraUtils is either pre-installed or we have pre-built it + # and exported to `CMakeExtraUtils_ROOT` + list(APPEND extra_args + -DCMakeExtraUtils_ROOT=${CMakeExtraUtils_ROOT} + ) + endif () - add_test(NAME ${ARGS_TEST_NAME} - COMMAND ${CMAKE_CTEST_COMMAND} --build-and-test ${CMAKE_CURRENT_SOURCE_DIR}/${test} - ${CMAKE_CURRENT_BINARY_DIR}/${test} - # Use the same build environment as the current runner - --build-generator "${CMAKE_GENERATOR}" - --build-options - ${extra_args} - --test-command ${CMAKE_CTEST_COMMAND} - --test-dir ${CMAKE_CURRENT_BINARY_DIR}/${test} - --output-on-failure - # Generally ignore if no tests are bundled - --no-tests=ignore - ) - set_tests_properties(${ARGS_TEST_NAME} PROPERTIES - LABELS "${ARGS_LABELS}" - ) + add_test(NAME ${ARGS_TEST_NAME} + COMMAND ${CMAKE_CTEST_COMMAND} --build-and-test ${CMAKE_CURRENT_SOURCE_DIR}/${test} + ${CMAKE_CURRENT_BINARY_DIR}/${test} + # Use the same build environment as the current runner + --build-generator "${CMAKE_GENERATOR}" + --build-options + ${extra_args} + --test-command ${CMAKE_CTEST_COMMAND} + --test-dir ${CMAKE_CURRENT_BINARY_DIR}/${test} + --output-on-failure + # Generally ignore if no tests are bundled + --no-tests=ignore + ) + set_tests_properties(${ARGS_TEST_NAME} PROPERTIES + LABELS "${ARGS_LABELS}" + ) endfunction() foreach (test_type IN ITEMS - package + package ) - add_subdirectory(${test_type}) + add_subdirectory(${test_type}) endforeach () diff --git a/test/DynamicVersion/src/commit.cpp b/test/DynamicVersion/src/commit.cpp index fa60cf1..6c2d9c3 100644 --- a/test/DynamicVersion/src/commit.cpp +++ b/test/DynamicVersion/src/commit.cpp @@ -3,12 +3,12 @@ #include "commit.h" #include "version.h" -int main(){ - std::cout << "version: " << version << std::endl; - std::cout << "version-full: " << version_full << std::endl; - std::cout << "commit: " << commit << std::endl; - std::cout << "short-hash: " << short_hash << std::endl; - std::cout << "describe: " << describe << std::endl; - std::cout << "distance: " << distance << std::endl; - return 0; +int main() { + std::cout << "version: " << version << std::endl; + std::cout << "version-full: " << version_full << std::endl; + std::cout << "commit: " << commit << std::endl; + std::cout << "short-hash: " << short_hash << std::endl; + std::cout << "describe: " << describe << std::endl; + std::cout << "distance: " << distance << std::endl; + return 0; } diff --git a/test/DynamicVersion/src/version.cpp b/test/DynamicVersion/src/version.cpp index 6de16fd..eb51209 100644 --- a/test/DynamicVersion/src/version.cpp +++ b/test/DynamicVersion/src/version.cpp @@ -2,8 +2,8 @@ #include "version.h" -int main(){ - std::cout << "version: " << version << std::endl; - std::cout << "version-full: " << version_full << std::endl; - return 0; +int main() { + std::cout << "version: " << version << std::endl; + std::cout << "version-full: " << version_full << std::endl; + return 0; } diff --git a/test/PackageComps/simple_provider/CMakeLists.txt b/test/PackageComps/simple_provider/CMakeLists.txt index 6a90550..74235b6 100644 --- a/test/PackageComps/simple_provider/CMakeLists.txt +++ b/test/PackageComps/simple_provider/CMakeLists.txt @@ -9,21 +9,21 @@ add_executable(hello src/hello.cpp) export_component() install(TARGETS hello - EXPORT TestProviderTargets) + EXPORT TestProviderTargets) include(CMakePackageConfigHelpers) write_basic_package_version_file( - TestProviderConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion + TestProviderConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion ) configure_package_config_file( - cmake/TestProviderConfig.cmake.in - TestProviderConfig.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TestProvider + cmake/TestProviderConfig.cmake.in + TestProviderConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TestProvider ) install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/TestProviderConfigVersion.cmake - ${CMAKE_CURRENT_BINARY_DIR}/TestProviderConfig.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TestProvider - ) + ${CMAKE_CURRENT_BINARY_DIR}/TestProviderConfigVersion.cmake + ${CMAKE_CURRENT_BINARY_DIR}/TestProviderConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/TestProvider +) diff --git a/test/PackageComps/simple_provider/src/hello.cpp b/test/PackageComps/simple_provider/src/hello.cpp index ebf8446..0353c18 100644 --- a/test/PackageComps/simple_provider/src/hello.cpp +++ b/test/PackageComps/simple_provider/src/hello.cpp @@ -1,6 +1,6 @@ #include int main(int argc, char *argv[]) { - std::cout << "Hello World!"; - return 0; + std::cout << "Hello World!"; + return 0; } diff --git a/test/package/CMakeLists.txt b/test/package/CMakeLists.txt index f714e1c..5299617 100644 --- a/test/package/CMakeLists.txt +++ b/test/package/CMakeLists.txt @@ -1,10 +1,10 @@ set_property(DIRECTORY APPEND - PROPERTY LABELS package + PROPERTY LABELS package ) foreach (test IN ITEMS - FetchContent - find_package + FetchContent + find_package ) - CMakeExtraUtils_add_test(${test} TEST_NAME test-import-${test}) + CMakeExtraUtils_add_test(${test} TEST_NAME test-import-${test}) endforeach () diff --git a/test/package/FetchContent/CMakeLists.txt b/test/package/FetchContent/CMakeLists.txt index 0a9847e..831e5aa 100644 --- a/test/package/FetchContent/CMakeLists.txt +++ b/test/package/FetchContent/CMakeLists.txt @@ -4,21 +4,21 @@ project(test_import_FetchContent LANGUAGES NONE) include(FetchContent) if (DEFINED ENV{PACKIT_SOURCE_URL}) - set(git_repo $ENV{PACKIT_SOURCE_URL}) + set(git_repo $ENV{PACKIT_SOURCE_URL}) else () - set(git_repo https://github.com/LecrisUT/CmakeExtraUtils) + set(git_repo https://github.com/LecrisUT/CmakeExtraUtils) endif () if (DEFINED ENV{PACKIT_SOURCE_SHA}) - set(git_tag $ENV{PACKIT_SOURCE_SHA}) + set(git_tag $ENV{PACKIT_SOURCE_SHA}) elseif (DEFINED ENV{PACKIT_COMMIT_SHA}) - set(git_tag $ENV{PACKIT_COMMIT_SHA}) + set(git_tag $ENV{PACKIT_COMMIT_SHA}) else () - set(git_tag main) + set(git_tag main) endif () FetchContent_Declare(CMakeExtraUtils - GIT_REPOSITORY ${git_repo} - GIT_TAG ${git_tag} + GIT_REPOSITORY ${git_repo} + GIT_TAG ${git_tag} ) FetchContent_MakeAvailable(CMakeExtraUtils) From a40f4091203903b81b3840bcbad418b903fd49a6 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 11:46:57 +0200 Subject: [PATCH 02/10] Replace dependabot with renovate Signed-off-by: Cristian Le --- .github/dependabot.yaml | 11 ----------- .github/renovate.json | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 .github/dependabot.yaml create mode 100644 .github/renovate.json diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml deleted file mode 100644 index ee04970..0000000 --- a/.github/dependabot.yaml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - groups: - production-dependencies: - dependency-type: "production" - development-dependencies: - dependency-type: "development" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..f079226 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "packageRules": [ + { + "groupName": "CI and devDependencies", + "matchManagers": ["github-actions", "pre-commit"] + } + ], + "separateMajorMinor": false, + "extends": [ + "config:recommended", + ":dependencyDashboard", + "schedule:weekly", + ":enablePreCommit", + ":semanticCommitTypeAll(chore)" + ] +} From f82311a82fa2b10921c7a613c1d5664d41efa29e Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 11:49:25 +0200 Subject: [PATCH 03/10] Remove problematic `ref-names` Signed-off-by: Cristian Le --- .git_archival.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/.git_archival.txt b/.git_archival.txt index 9d376cd..4ed73f5 100644 --- a/.git_archival.txt +++ b/.git_archival.txt @@ -1,4 +1,3 @@ node: $Format:%H$ node-date: $Format:%cI$ describe-name: $Format:%(describe:tags=true,match=?[0-9.]*)$ -ref-names: $Format:%D$ From 6397298b7ee07618c1f8267ad428d0fc456183dc Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 11:52:27 +0200 Subject: [PATCH 04/10] Bump minimum CMake Signed-off-by: Cristian Le --- .github/workflows/step_test.yaml | 8 +++----- CMakeLists.txt | 27 +-------------------------- cmake/DynamicVersion.cmake | 16 +--------------- cmake/PackageComps.cmake | 1 + 4 files changed, 6 insertions(+), 46 deletions(-) diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index e300d26..da9a9b0 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - cmake: [ "3.20", "latest", "latestrc" ] + cmake: [ "3.25", "latest", "latestrc" ] steps: - uses: actions/checkout@v4 with: @@ -34,10 +34,8 @@ jobs: cmakeVersion: ${{ matrix.cmake }} - name: Build and test native CMake run: | - # Not running presets because of minimum CMake version being tested - cmake -B ./build - ctest --test-dir ./build --output-on-failure - echo "CMakeExtraUtils_ROOT=$(pwd)/build" >> $GITHUB_ENV + cmake --workflow --preset default --fresh + echo "CMakeExtraUtils_ROOT=$(pwd)/cmake-build-release" >> $GITHUB_ENV # TODO: This will be migrated to standalone actions - name: Run tmt tests uses: LecrisUT/tmt-actions/run-tmt@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 74eb481..fe2096a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,5 @@ # Minimum version follows the current Ubuntu LTS and RHEL version -cmake_minimum_required(VERSION 3.20) -if (POLICY CMP0140) - # Enable using return(PROPAGATE) - # TODO: Remove when cmake 3.25 is commonly distributed - cmake_policy(SET CMP0140 NEW) -endif () +cmake_minimum_required(VERSION 3.25...3.30) #[==============================================================================================[ # Basic project definition # @@ -25,17 +20,6 @@ project(CMakeExtraUtils HOMEPAGE_URL https://github.com/LecrisUT/CmakeExtraUtils LANGUAGES NONE ) -# Back-porting to PROJECT_IS_TOP_LEVEL to older cmake -# TODO: Remove when requiring cmake >= 3.21 -if (NOT DEFINED CMakeExtraUtils_IS_TOP_LEVEL) - if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(PROJECT_IS_TOP_LEVEL ON) - set(CMakeExtraUtils_IS_TOP_LEVEL ON) - else () - set(PROJECT_IS_TOP_LEVEL OFF) - set(CMakeExtraUtils_IS_TOP_LEVEL_IS_TOP_LEVEL OFF) - endif () -endif () #[==============================================================================================[ @@ -121,15 +105,6 @@ endif () if (NOT PROJECT_IS_TOP_LEVEL) # Propagate variables for FetchContent # All variables have to be consistent with CMakeExtraUtilsConfig.cmake - if (CMAKE_VERSION VERSION_LESS 3.25) - # TODO: Remove when cmake 3.25 is commonly distributed - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION ${CMakeExtraUtils_VERSION} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_MAJOR ${CMakeExtraUtils_VERSION_MAJOR} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_MINOR ${CMakeExtraUtils_VERSION_MINOR} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_PATCH ${CMakeExtraUtils_VERSION_PATCH} PARENT_SCOPE) - set(CMakeExtraUtils_VERSION_TWEAK ${CMakeExtraUtils_VERSION_TWEAK} PARENT_SCOPE) - endif () return(PROPAGATE CMAKE_MODULE_PATH CMakeExtraUtils_VERSION diff --git a/cmake/DynamicVersion.cmake b/cmake/DynamicVersion.cmake index a0fd87f..4d1e900 100644 --- a/cmake/DynamicVersion.cmake +++ b/cmake/DynamicVersion.cmake @@ -10,13 +10,9 @@ Helper module to get the project's version dynamically. Format is compatible wit ]===] +cmake_minimum_required(VERSION 3.25...3.30) include_guard() list(APPEND CMAKE_MESSAGE_CONTEXT DynamicVersion) -if (POLICY CMP0140) - # Enable using return(PROPAGATE) - # TODO: Remove when cmake 3.25 is commonly distributed - cmake_policy(SET CMP0140 NEW) -endif () #[==============================================================================================[ # Preparations # @@ -327,16 +323,6 @@ function(dynamic_version) message(VERBOSE "Calculated version = ${${ARGS_OUTPUT_VERSION}}" ) - - if (CMAKE_VERSION VERSION_LESS 3.25) - # TODO: Remove when cmake 3.25 is commonly distributed - set(${ARGS_OUTPUT_DESCRIBE} ${${ARGS_OUTPUT_DESCRIBE}} PARENT_SCOPE) - set(${ARGS_OUTPUT_VERSION} ${${ARGS_OUTPUT_VERSION}} PARENT_SCOPE) - set(${ARGS_OUTPUT_VERSION_FULL} ${${ARGS_OUTPUT_VERSION_FULL}} PARENT_SCOPE) - set(${ARGS_OUTPUT_COMMIT} ${${ARGS_OUTPUT_COMMIT}} PARENT_SCOPE) - set(${ARGS_OUTPUT_DISTANCE} ${${ARGS_OUTPUT_DISTANCE}} PARENT_SCOPE) - set(${ARGS_OUTPUT_SHORT_HASH} ${${ARGS_OUTPUT_SHORT_HASH}} PARENT_SCOPE) - endif () return(PROPAGATE ${ARGS_OUTPUT_DESCRIBE} ${ARGS_OUTPUT_VERSION} diff --git a/cmake/PackageComps.cmake b/cmake/PackageComps.cmake index ef7ac34..af9ff88 100644 --- a/cmake/PackageComps.cmake +++ b/cmake/PackageComps.cmake @@ -6,6 +6,7 @@ # # +cmake_minimum_required(VERSION 3.25...3.30) list(APPEND CMAKE_MESSAGE_CONTEXT PackageComps) # TODO: Move these to functions with minimal macro that actually does the `include()` From 16017a305becb85225d9b3e00d1a8a39c1238fd5 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 11:58:49 +0200 Subject: [PATCH 05/10] Some documentation cleanup Signed-off-by: Cristian Le --- README.md | 11 +++++++++-- docs/README.md | 18 ------------------ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 1568272..4f7ee4b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # CMakeExtraUtils + + Extra utilities for cmake: -- [`DynamicVersion`](cmake/DynamicVersion.md) -- [`PackageComps`](cmake/PackageComps.md) +- [`DynamicVersion`] +- [`PackageComps`] ## Installation @@ -39,6 +41,8 @@ project(MyProject VERSION ${PROJECT_VERSION}) ``` + + ## TODO for v1.0 - [x] Automation: @@ -47,3 +51,6 @@ project(MyProject - [ ] Test coverage: - [x] `DynamicVersion` - [ ] `PackageComps` + +[`dynamicversion`]: cmake/DynamicVersion.md +[`packagecomps`]: cmake/PackageComps.md diff --git a/docs/README.md b/docs/README.md index cf32de5..388644e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,21 +21,3 @@ For more intensive documentation editing I recommend using `sphinx-autobuild` wh ```console $ sphinx-autobuild . ./build ``` - -## Documentation notes - -We heavily reuse the documentation already found in the source markdown files like the installation instructions in -[`Readme.md`](../README.md#Installation). See an example in [install.md](install.md). Please do not use -sphinx/myst_parser specific directives for these included files. Use the files in this `doc` folder to insert the -sphinx/myst_parser specific directives. - -The main cmake module documentations is found in the [cmake folder](../cmake). Make sure that there is a skeleton -markdown files in [`cmake_modules`](cmake_modules) folder, e.g. [`DynamicVersion.md`](cmake_modules/DynamicVersion.md). - -Other personal standards applied: - -- Use markdown file format only -- Use [colon-fence](https://myst-parser.readthedocs.io/en/v1.0.0/syntax/optional.html#code-fences-using-colons) `::` - instead of triple-tick \`\`\` -- Use [yaml](https://myst-parser.readthedocs.io/en/v1.0.0/configuration.html#frontmatter-local-configuration) for - directive configurations From 57621ec4662a4a9f263cbbcd625f0226f47edff0 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Tue, 23 Jul 2024 12:02:44 +0200 Subject: [PATCH 06/10] Badges! Signed-off-by: Cristian Le --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 4f7ee4b..b91070e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # CMakeExtraUtils +[![CI Status][ci-badge]][ci-link] +[![Documentation Status][rtd-badge]][rtd-link] + +![License Status][license-badge] +![CMake Status][cmake-badge] + Extra utilities for cmake: @@ -52,5 +58,11 @@ project(MyProject - [x] `DynamicVersion` - [ ] `PackageComps` +[ci-badge]: https://github.com/LecrisUT/CmakeExtraUtils/actions/workflows/ci.yaml/badge.svg?branch=main&event=push +[ci-link]: https://github.com/LecrisUT/CmakeExtraUtils/actions/workflows/ci.yaml?query=branch%3Amain+event%3Apush +[cmake-badge]: https://img.shields.io/badge/CMake-3.25-blue?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMiIgdmlld0JveD0iMCAwIDU0NS41IDU0NS45Ij48cGF0aCBkPSJNNTQ2IDUzNCAyODIgOWwzOSA0MzQgMjI1IDkxeiIgZGF0YS1uYW1lPSJyZWQgcmlnaHQiIHN0eWxlPSJmaWxsOiNmMzI3MzU7c3Ryb2tlLXdpZHRoOjAiLz48cGF0aCBkPSJNNTI1IDU0NiAxNzAgNDAzIDEgNTQ2aDUyNHoiIGRhdGEtbmFtZT0iZ3JlZW4gYm90dG9tIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOjA7ZmlsbDojM2VhZTJiIi8+PHBhdGggZD0iTTI2MyAwIDAgNTIybDI4OC0yNDRMMjYzIDB6IiBkYXRhLW5hbWU9ImJsdWUgbGVmdCIgc3R5bGU9ImZpbGw6IzAwNjhjNztzdHJva2Utd2lkdGg6MCIvPjxwYXRoIGQ9Im0yOTEgMjk5LTEwNSA4OSAxMTcgNDgtMTItMTM3eiIgZGF0YS1uYW1lPSJncmF5IGNlbnRlciIgc3R5bGU9ImZpbGw6I2RjZTNlYztzdHJva2Utd2lkdGg6MCIvPjwvc3ZnPg== +[license-badge]: https://img.shields.io/github/license/LecrisUT/CmakeExtraUtils +[rtd-badge]: https://img.shields.io/readthedocs/cmakeextrautils +[rtd-link]: https://cmakeextrautils.readthedocs.io/en/latest/?badge=latest [`dynamicversion`]: cmake/DynamicVersion.md [`packagecomps`]: cmake/PackageComps.md From ac2f2fd35be6c30ce5c937f05c0dcc635930727c Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 24 Jul 2024 10:07:45 +0200 Subject: [PATCH 07/10] Cleanup CI workflows Signed-off-by: Cristian Le --- .github/workflows/ci.yaml | 6 ++++++ .github/workflows/release.yaml | 13 +++---------- .github/workflows/step_docs.yaml | 3 --- .github/workflows/step_pre-commit.yaml | 3 --- .github/workflows/step_test.yaml | 3 --- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ec7f366..955b882 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,4 +1,7 @@ name: CI +run-name: > + CI (${{ github.event_name }}) + ${{ github.event_name == 'pull_request' && format('PR#{0}', github.event.number) || '' }} on: workflow_dispatch: @@ -6,6 +9,8 @@ on: branches: [ main ] push: branches: [ main ] + schedule: + - cron: 0 0 * * 3 permissions: contents: read @@ -27,6 +32,7 @@ jobs: pull-requests: write docs: + name: 📘 docs needs: [ pre-commit ] uses: ./.github/workflows/step_docs.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 41b6857..2ac67d0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,5 +1,5 @@ -name: release -run-name: Release +name: 🚀 Release +run-name: Release ${{ github.ref_name }} on: push: @@ -13,22 +13,15 @@ on: required: true jobs: - # TODO: tests and docs are not aligned when called from workflow_dispatch :/ - pre-commit: - uses: ./.github/workflows/step_pre-commit.yaml tests: - needs: [ pre-commit ] uses: ./.github/workflows/step_test.yaml permissions: contents: read checks: write pull-requests: write - docs: - needs: [ pre-commit ] - uses: ./.github/workflows/step_docs.yaml release: - needs: [ tests, docs ] + needs: [ tests ] name: Create release runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/step_docs.yaml b/.github/workflows/step_docs.yaml index 7d51f4e..009e5ce 100644 --- a/.github/workflows/step_docs.yaml +++ b/.github/workflows/step_docs.yaml @@ -1,6 +1,3 @@ -name: docs -run-name: Run documentation tests - on: workflow_call: diff --git a/.github/workflows/step_pre-commit.yaml b/.github/workflows/step_pre-commit.yaml index 61cbc75..4441611 100644 --- a/.github/workflows/step_pre-commit.yaml +++ b/.github/workflows/step_pre-commit.yaml @@ -1,6 +1,3 @@ -name: pre-commit -run-name: Run pre-commits - on: workflow_call: diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index da9a9b0..7e9582d 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -1,6 +1,3 @@ -name: test -run-name: Run tests - on: workflow_call: From c51273d95a4396cc79726c97c905fb9bc60e49a8 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 24 Jul 2024 10:09:10 +0200 Subject: [PATCH 08/10] Remove workarounds Signed-off-by: Cristian Le --- .github/workflows/step_test.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index 7e9582d..20c39b0 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -18,12 +18,6 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - # Note: Proper solution is: https://github.com/actions/runner/issues/2033#issuecomment-1598547465 - - name: Temporary fix for git permissions - run: | - git config --global --add safe.directory "*" - git config --global user.email "bot@github.com" - git config --global user.name "GitHub Actions Bot" - name: Setup tmt uses: LecrisUT/tmt-actions/setup-tmt@v1 - uses: lukka/get-cmake@latest From bedc0cca9f1dfda577357b5cabce9c6ad0827d02 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 24 Jul 2024 11:13:40 +0200 Subject: [PATCH 09/10] Simplify junit result publish Signed-off-by: Cristian Le --- .github/workflows/ci.yaml | 4 ---- .github/workflows/step_test.yaml | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 955b882..4970834 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,10 +26,6 @@ jobs: tests: needs: [ pre-commit ] uses: ./.github/workflows/step_test.yaml - permissions: - contents: read - checks: write - pull-requests: write docs: name: 📘 docs diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index 20c39b0..e7a472d 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -36,10 +36,6 @@ jobs: report: name: Report JUnit needs: [ tests ] - permissions: - contents: read - checks: write - pull-requests: write runs-on: ubuntu-latest steps: - name: Download test results @@ -51,4 +47,6 @@ jobs: large_files: true report_individual_runs: true report_suite_logs: any + comment_mode: off + check_run: false if: always() From eefe5f2e13e96c12c8e8cc0dc6458f53f5179be7 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 24 Jul 2024 11:35:20 +0200 Subject: [PATCH 10/10] Fix documentation issues Signed-off-by: Cristian Le --- cmake/DynamicVersion.md | 4 ++++ cmake/PackageComps.md | 4 ++++ docs/cmake_modules/DynamicVersion.md | 3 ++- docs/cmake_modules/PackageComps.md | 3 ++- docs/cmake_modules/index.md | 8 +++----- docs/index.md | 9 ++------- docs/install.md | 6 ------ 7 files changed, 17 insertions(+), 20 deletions(-) delete mode 100644 docs/install.md diff --git a/cmake/DynamicVersion.md b/cmake/DynamicVersion.md index 28780e1..085c4d6 100644 --- a/cmake/DynamicVersion.md +++ b/cmake/DynamicVersion.md @@ -1,5 +1,7 @@ # [`DynamicVersion.cmake`](DynamicVersion.cmake) + + Calculate the project version from the git tags or `.git_archival.txt` if the source is not a git repository ## Example @@ -27,3 +29,5 @@ add_dependencies(version_lib My_Project_Version) set_property(SOURCE version.cpp.in APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/.version) ``` + + diff --git a/cmake/PackageComps.md b/cmake/PackageComps.md index 87a5f01..5d654cc 100644 --- a/cmake/PackageComps.md +++ b/cmake/PackageComps.md @@ -1,5 +1,7 @@ # [`PackageComps.cmake`](PackageComps.cmake) + + Export and import targets as individual components. Special components `shared` and `static` ## Example @@ -54,3 +56,5 @@ project(Downstream_Project) find_package(My_Project COMPONENTS my_component) ``` + + diff --git a/docs/cmake_modules/DynamicVersion.md b/docs/cmake_modules/DynamicVersion.md index 03f6764..4b54d7c 100644 --- a/docs/cmake_modules/DynamicVersion.md +++ b/docs/cmake_modules/DynamicVersion.md @@ -1,5 +1,6 @@ # DynamicVersion ```{include} ../../cmake/DynamicVersion.md -: start-after: "# [`DynamicVersion.cmake`](DynamicVersion.cmake)" +:start-after: +:end-before: ``` diff --git a/docs/cmake_modules/PackageComps.md b/docs/cmake_modules/PackageComps.md index 2b8011e..a8b3c94 100644 --- a/docs/cmake_modules/PackageComps.md +++ b/docs/cmake_modules/PackageComps.md @@ -1,5 +1,6 @@ # PackageComps ```{include} ../../cmake/PackageComps.md -: start-after: "# [`PackageComps.cmake`](PackageComps.cmake)" +:start-after: +:end-before: ``` diff --git a/docs/cmake_modules/index.md b/docs/cmake_modules/index.md index eb85c39..e390751 100644 --- a/docs/cmake_modules/index.md +++ b/docs/cmake_modules/index.md @@ -1,10 +1,8 @@ # CMake modules ```{toctree} -: maxdepth: 1 -: titlesonly: true -: caption: Contents -: glob: true +:titlesonly: true -./* +DynamicVersion +PackageComps ``` diff --git a/docs/index.md b/docs/index.md index 19abd82..eb3e44d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,14 +2,9 @@ CMakeExtraUtils is a collection of cmake modules designed to help you manage and export your cmake project. -See the [installation guide](install) for details on how to import this project and -[CMake modules](cmake_modules/index) for the modules available. - ```{toctree} -: maxdepth: 2 -: titlesonly: true -: caption: Contents +:hidden: true -install +self cmake_modules/index ``` diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index 9f10a4d..0000000 --- a/docs/install.md +++ /dev/null @@ -1,6 +0,0 @@ -# Installation guide - -:::{include} ../README.md -: start-after: "## Installation" -: end-before: "## " -:::