diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a5cd69..66beb42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,77 @@ cmake_minimum_required(VERSION 3.2...3.27) -project(cmake_git_version_tracking - LANGUAGES C) + +set(PROJECT_NAME ${CMAKE_GIT_PROJECT_PREFIX}cmake_git_version_tracking) +project(${PROJECT_NAME} LANGUAGES C VERSION 1.0) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +# Standard paths +include(install_paths) # Define the two required variables before including # the source code for watching a git repository. set(PRE_CONFIGURE_FILE "git.c.in") set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/git.c") include(git_watcher.cmake) +include(CMakePackageConfigHelpers) +set(CMAKE_CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in" CACHE INTERNAL "Package config file" ) + +option(SAVE_GIT_STATE_TO_PY "Creates a .py file containg to be used for python bindings versioning" ON) +if(SAVE_GIT_STATE_TO_PY) + set(GIT_STATE_PY_PATH ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_GIT_PROJECT_PREFIX}git_state.py CACHE INTERNAL "Path to py git state") +endif() # Create a library out of the compiled post-configure file. -# -# Note that the include is a system include. This was done # so downstream projects don't suffer from warnings on a # 3rdparty library. add_library(${PROJECT_NAME} STATIC ${POST_CONFIGURE_FILE}) -target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -add_dependencies(${PROJECT_NAME} check_git) + +target_include_directories(${PROJECT_NAME} + SYSTEM PUBLIC + $ +) + +add_dependencies(${PROJECT_NAME} ${CMAKE_GIT_PROJECT_PREFIX}check_git) # The C99 standard is only required because we're using . # This could be removed if it's a problem for users, but would require the # cmake configure() commands to translate true/false literals to 1/0. set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) + +set(PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake") +set(PROJECT_CONFIG_VERSION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake") + +configure_package_config_file( + ${CMAKE_CONFIG_FILE} + ${PROJECT_CONFIG_FILE} + INSTALL_DESTINATION ${INSTALL_CONFIG_DIR}) + +# This auto-generates a version file. +write_basic_package_version_file( + ${PROJECT_CONFIG_VERSION_FILE} + COMPATIBILITY SameMajorVersion) + +install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} + LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR} + ARCHIVE DESTINATION ${INSTALL_ARCHIVE_DIR}) + +install(FILES ${HEADER_FILES} + DESTINATION ${INSTALL_INCLUDE_DIR}) + + +install(FILES + ${PROJECT_CONFIG_VERSION_FILE} + ${PROJECT_CONFIG_FILE} + DESTINATION ${INSTALL_CONFIG_DIR}) + +install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${INSTALL_CONFIG_DIR}) + +export(EXPORT ${PROJECT_NAME}-targets + FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}::) + +export(PACKAGE ${PROJECT_NAME}) diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 0000000..f96bedd --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1,21 @@ +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) + +get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE) +get_filename_component(@PROJECT_NAME@_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + +if(TARGET @PROJECT_NAME@::@PROJECT_NAME@) + set(@PROJECT_NAME@_DIR "${@PROJECT_NAME@_BINARY_DIR}") + message(STATUS "Target @PROJECT_NAME@::@PROJECT_NAME@ Configured with ${@PROJECT_NAME@_DIR}") +elseif(TARGET @PROJECT_NAME@::@PROJECT_NAME@-static) + set(@PROJECT_NAME@_DIR "${CMAKE_CURRENT_BINARY_DIR}") + message(STATUS "Target @PROJECT_NAME@::@PROJECT_NAME@-static Configured with ${@PROJECT_NAME@_DIR}") +else() + include("${@PROJECT_NAME@_CMAKE_DIR}/@PROJECT_NAME@-targets.cmake") + set(@PROJECT_NAME@_DIR "${_prefix}/share/cmake/@PROJECT_NAME@") + set(@PROJECT_NAME@_INCLUDE_DIRS "${_prefix}/include/@PROJECT_NAME@") + message(STATUS "Target <@PROJECT_NAME@> without aliases configured with ${@PROJECT_NAME@_DIR}") +endif() + +check_required_components("@PROJECT_NAME@") diff --git a/cmake/install_paths.cmake b/cmake/install_paths.cmake new file mode 100644 index 0000000..a4bf465 --- /dev/null +++ b/cmake/install_paths.cmake @@ -0,0 +1,45 @@ +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +find_package(PkgConfig REQUIRED) +find_package (Python3 COMPONENTS Interpreter Development REQUIRED) +pkg_get_variable(SYSTEMD_UNIT_DIR systemd systemdsystemunitdir) +# If no build type was specified, set it to Release. +if(NOT SYSTEMD_UNIT_DIR) + set(SYSTEMD_UNIT_DIR ${CMAKE_INSTALL_PREFIX}/etc/systemd/system CACHE STRING + "Default install path for services" FORCE) +endif(NOT SYSTEMD_UNIT_DIR) + +# If no build type was specified, set it to Release. +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING + "Choose the type of build, options are: None Debug Release." + FORCE) +endif(NOT CMAKE_BUILD_TYPE) + +# If no installation prefix is given manually, install locally. +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING + "The install location" + FORCE) +endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + +# Projectwise paths +set(PROJECT_PREFIX ${PROJECT_NAME}) +set(INSTALL_RUNTIME_DIR ${CMAKE_INSTALL_BINDIR}) +set(INSTALL_CONFIG_DIR ${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}) +set(INSTALL_SERVICES_CFG_DIR ${CMAKE_INSTALL_DATAROOTDIR}/service_cfg) +set(INSTALL_SYSCONFIG_DIR ${CMAKE_INSTALL_SYSCONFDIR}) +set(INSTALL_LIBRARY_DIR ${CMAKE_INSTALL_LIBDIR}) +set(INSTALL_ARCHIVE_DIR ${CMAKE_INSTALL_LIBDIR}) +set(INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +set(INSTALL_SRC_DIR src/${PROJECT_NAME}) +cmake_path (GET Python3_SITELIB FILENAME THIRD_PARTY_DIR_NAME) +cmake_path (GET Python3_STDLIB FILENAME PYTHON3_DIR) +set(INSTALL_PYTHON_DIR ${INSTALL_LIBRARY_DIR}/${PYTHON3_DIR}/${THIRD_PARTY_DIR_NAME}) + +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(INSTALL_SYSTEMD_SERVICE ${CMAKE_INSTALL_PREFIX}/${SYSTEMD_UNIT_DIR}) +else(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(INSTALL_SYSTEMD_SERVICE ${SYSTEMD_UNIT_DIR}) +endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) diff --git a/git_watcher.cmake b/git_watcher.cmake index 32313a3..adae619 100644 --- a/git_watcher.cmake +++ b/git_watcher.cmake @@ -250,7 +250,39 @@ function(GetGitState _working_dir) endfunction() +function(SaveGitStateToPy) + GetGitState("${GIT_WORKING_DIR}") + # Format git state to .py file + if("$ENV{GIT_IS_DIRTY}" STREQUAL "true") + set(PY_GIT_IS_DIRTY True) + else() + set(PY_GIT_IS_DIRTY False) + endif() + + set(GIT_STATE + PY_GIT_HEAD_SHA = \"$ENV{GIT_HEAD_SHA1}\"\n + PY_GIT_IS_DIRTY = ${ES_GIT_IS_DIRTY}\n + PY_GIT_AUTHOR_NAME = \"$ENV{GIT_AUTHOR_NAME}\"\n + PY_GIT_AUTHOR_EMAIL = \"$ENV{GIT_AUTHOR_EMAIL}\"\n + PY_GIT_COMMIT_DATE = \"$ENV{GIT_COMMIT_DATE_ISO8601}\"\n + PY_GIT_COMMIT_SUBJECT = \"$ENV{GIT_COMMIT_SUBJECT}\"\n + PY_GIT_COMMIT_BODY = \"$ENV{GIT_COMMIT_BODY}\"\n + PY_GIT_DESCRIBE = \"$ENV{GIT_DESCRIBE}\"\n + PY_GIT_BRANCH = \"$ENV{GIT_BRANCH}\"\n) + string(REGEX REPLACE ";" "" GIT_STATE "${GIT_STATE}") + + if(EXISTS ${GIT_STATE_PY_PATH}) + file(READ ${GIT_STATE_PY_PATH} GIT_STATE_) + else() + set(GIT_STATE_ "") + endif() + + if (NOT "${GIT_STATE}" STREQUAL "${GIT_STATE_}") + file(WRITE ${GIT_STATE_PY_PATH} "${GIT_STATE}") + endif() + +endfunction() # Function: GitStateChangedAction # Description: this function is executed when the state of the git @@ -263,7 +295,6 @@ function(GitStateChangedAction) endfunction() - # Function: HashGitState # Description: loop through the git state variables and compute a unique hash. # Args: @@ -324,7 +355,7 @@ endfunction() # check the state of git before every build. If the state has # changed, then a file is configured. function(SetupGitMonitoring) - add_custom_target(check_git + add_custom_target(${CMAKE_GIT_PROJECT_PREFIX}check_git ALL DEPENDS ${PRE_CONFIGURE_FILE} BYPRODUCTS @@ -360,6 +391,10 @@ function(Main) else() # >> Executes at configure time. SetupGitMonitoring() + # Save the git state in py file + if(SAVE_GIT_STATE_TO_PY) + SaveGitStateToPy() + endif() endif() endfunction()