From 6ba68d4f8a176e1b8c0583fc49c871bc64b13149 Mon Sep 17 00:00:00 2001 From: msclock Date: Mon, 15 Jul 2024 11:15:38 +0800 Subject: [PATCH] perf: reorganize modules and add the first project module (#115) Signed-off-by: msclock --- cmake/ProjectDefault.cmake | 19 +++ cmake/build/Default.cmake | 3 + cmake/configure/Default.cmake | 4 + cmake/install/Common.cmake | 229 ------------------------- cmake/install/Default.cmake | 6 + cmake/install/InstallCopyright.cmake | 4 + cmake/install/InstallDependency.cmake | 2 +- cmake/install/InstallTarget.cmake | 235 ++++++++++++++++++++++++++ cmake/test/Default.cmake | 2 + 9 files changed, 274 insertions(+), 230 deletions(-) create mode 100644 cmake/ProjectDefault.cmake create mode 100644 cmake/install/InstallTarget.cmake diff --git a/cmake/ProjectDefault.cmake b/cmake/ProjectDefault.cmake new file mode 100644 index 0000000..2e02563 --- /dev/null +++ b/cmake/ProjectDefault.cmake @@ -0,0 +1,19 @@ +#[[ +This module contains default modules and settings that can be used by all projects. +]] + +include_guard(GLOBAL) + +# Prevent the module from being used in the wrong location +if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + message(FATAL_ERROR "This module should be in the project root directory") +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/configure/Default.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/build/Default.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/test/Default.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/install/Default.cmake) + +add_debug_macro() + +create_uninstall_target() diff --git a/cmake/build/Default.cmake b/cmake/build/Default.cmake index 84fcd1a..d384079 100644 --- a/cmake/build/Default.cmake +++ b/cmake/build/Default.cmake @@ -18,3 +18,6 @@ set(BUILD_SHARED_LIBS "This will cause all libraries to be built shared unless the library was explicitly added as a static library. This variable is often added to projects as an ``option()`` so that each user of a project can decide if they want to build the project using shared or static libraries.") + +include(${CMAKE_CURRENT_LIST_DIR}/Ccache.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/LinkOptimization.cmake) diff --git a/cmake/configure/Default.cmake b/cmake/configure/Default.cmake index 7c4701b..4535b5a 100644 --- a/cmake/configure/Default.cmake +++ b/cmake/configure/Default.cmake @@ -13,3 +13,7 @@ set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE set(FETCHCONTENT_QUIET ON CACHE BOOL "Don't print messages about fetch operations.") + +include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CheckBuildDir.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/UniqueOutputBinaryDir.cmake) diff --git a/cmake/install/Common.cmake b/cmake/install/Common.cmake index fe15a98..198f39b 100644 --- a/cmake/install/Common.cmake +++ b/cmake/install/Common.cmake @@ -3,7 +3,6 @@ This module provides some common tools. ]] include_guard(GLOBAL) -include(${CMAKE_CURRENT_LIST_DIR}/InstallCopyright.cmake) #[[ Show installation directories @@ -16,234 +15,6 @@ macro(show_installation) endforeach() endmacro() -#[[ -A function to add install config rules to target - -Arguments: - NAME - A name as the installation export name. (required) - VERSION - The target version. Default to "0.0.0". (optional) - COMPATIBILITY - Compatibility on version. Default to SameMajorVersion. (optional) - CONFIGURE_PACKAGE_CONFIG_FILE - The file to generate config file. (optional) - INCLUDES - The include directories to install. (optional) - INCLUDE_FILES - The include files to install. (optional) - TARGETS - The targets to pack. (required) - DEPENDENCIES - The dependencies to check in config file. (required) - -Note: - - Includes from sources can be installed by PUBLIC_HEADER using set_target_properties - which flattens the hierarchy and puts the header files into the same directory. So - the recommended way it to use INCLUDES or INCLUDE_FILES. - see https://stackoverflow.com/questions/54271925/how-to-configure-cmakelists-txt-to-install-public-headers-of-a-shared-library - -Example: - - add_library(header INTERFACE) - target_include_interface_directories(header ${CMAKE_CURRENT_SOURCE_DIR}/include) - target_link_libraries(header INTERFACE absl::log) - set_target_properties(header PROPERTIES PUBLIC_HEADER "${public_headers}") - install_target( - NAME - header - VERSION - ${CMAKE_PROJECT_VERSION} - INCLUDES - ${CMAKE_CURRENT_SOURCE_DIR}/include/ # install subdirectories with / - TARGETS - header - DEPENDENCIES - "absl:log") - -]] -function(install_target) - set(_opts) - set(_single_opts NAME VERSION COMPATIBILITY CONFIGURE_PACKAGE_CONFIG_FILE) - set(_multi_opts TARGETS INCLUDES INCLUDE_FILES DEPENDENCIES LICENSE_FILE_LIST) - cmake_parse_arguments(PARSE_ARGV 0 arg "${_opts}" "${_single_opts}" - "${_multi_opts}") - - include(GNUInstallDirs) - # Specify rules at install time - install( - TARGETS ${arg_TARGETS} - EXPORT ${arg_NAME}-targets - LIBRARY DESTINATION $<$:debug/>${CMAKE_INSTALL_LIBDIR} - COMPONENT ${arg_NAME}_runtime - ARCHIVE DESTINATION $<$:debug/>${CMAKE_INSTALL_LIBDIR} - COMPONENT ${arg_NAME}_runtime - RUNTIME DESTINATION $<$:debug/>${CMAKE_INSTALL_BINDIR} - COMPONENT ${arg_NAME}_runtime - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME} - COMPONENT ${arg_NAME}_development) - - if(arg_INCLUDES) - install(DIRECTORY ${arg_INCLUDES} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME}) - endif() - - if(arg_INCLUDE_FILES) - install(FILES ${arg_INCLUDE_FILES} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME}) - endif() - - if(arg_LICENSE_FILE_LIST) - install_copyright(FILE_LIST ${arg_LICENSE_FILE_LIST} DESTINATION - share/${arg_NAME}) - endif() - - install( - EXPORT ${arg_NAME}-targets - FILE ${arg_NAME}-targets.cmake - NAMESPACE ${arg_NAME}:: - DESTINATION share/${arg_NAME} - COMPONENT ${arg_NAME}_development) - - set(_cache_dir - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CURRENT_FUNCTION}/${arg_NAME}) - - if(NOT arg_CONFIGURE_PACKAGE_CONFIG_FILE) - - set(_configure_package_config_file_content - "#[=======================================================================[.rst: -${arg_NAME}-config.cmake -------------------- - -${arg_NAME} cmake module. -This module sets the following variables in your project: - -:: - - ${arg_NAME}_FOUND - true if ${arg_NAME} found on the system - ${arg_NAME}_VERSION - ${arg_NAME} version in format Major.Minor.Release -") - string( - APPEND - _configure_package_config_file_content - " - -Exported targets: - -:: - -If ${arg_NAME} is found, this module defines the following :prop_tgt:`IMPORTED` -targets. :: -") - foreach(_tgt ${arg_TARGETS}) - get_target_property(_target_type "${_tgt}" TYPE) - string( - APPEND - _configure_package_config_file_content - " - ${arg_NAME}::${_tgt} - the main ${arg_NAME} ${_target_type} with header & defs attached." - ) - endforeach() - - string( - APPEND - _configure_package_config_file_content - " - - -Suggested usage: - -:: - - find_package(${arg_NAME}) - find_package(${arg_NAME} CONFIG REQUIRED) - - -The following variables can be set to guide the search for this package: - -:: - - ${arg_NAME}_DIR - CMake variable, set to directory containing this Config file - CMAKE_PREFIX_PATH - CMake variable, set to root directory of this package - PATH - environment variable, set to bin directory of this package - CMAKE_DISABLE_FIND_PACKAGE_${arg_NAME} - CMake variable, disables find_package(${arg_NAME}) - perhaps to force internal build - -#]=======================================================================] -") - - string( - APPEND - _configure_package_config_file_content - "@PACKAGE_INIT@ - -include(CMakeFindDependencyMacro) -") - string(APPEND _configure_package_config_file_content " -# Dependency check here") - foreach(_dep ${arg_DEPENDENCIES}) - string(APPEND _configure_package_config_file_content " -find_dependency(${_dep} REQUIRED)") - endforeach() - - string(REPLACE ";" " " _tgts "${arg_TARGETS}") - string( - APPEND - _configure_package_config_file_content - " - -include(\"\${CMAKE_CURRENT_LIST_DIR}/${arg_NAME}-targets.cmake\") -check_required_components(${_tgts}) -") - - file(WRITE ${_cache_dir}/${arg_NAME}-config.cmake.in - ${_configure_package_config_file_content}) - set(arg_CONFIGURE_PACKAGE_CONFIG_FILE - ${_cache_dir}/${arg_NAME}-config.cmake.in) - endif() - - include(CMakePackageConfigHelpers) - - configure_package_config_file( - ${arg_CONFIGURE_PACKAGE_CONFIG_FILE} ${_cache_dir}/${arg_NAME}-config.cmake - INSTALL_DESTINATION share/${arg_NAME}) - - if(NOT arg_COMPATIBILITY) - set(arg_COMPATIBILITY SameMajorVersion) - endif() - - if(NOT arg_VERSION) - set(arg_VERSION "0.0.0") - endif() - - write_basic_package_version_file( - ${_cache_dir}/${arg_NAME}-config-version.cmake - VERSION ${arg_VERSION} - COMPATIBILITY ${arg_COMPATIBILITY}) - - install(FILES ${_cache_dir}/${arg_NAME}-config.cmake - ${_cache_dir}/${arg_NAME}-config-version.cmake - DESTINATION share/${arg_NAME}) - - # Export from build tree - export( - EXPORT ${arg_NAME}-targets - FILE ${_cache_dir}/${arg_NAME}-targets.cmake - NAMESPACE ${arg_NAME}::) - - export(PACKAGE ${arg_NAME}) - - # Generate the usage file - set(_usage_targets) - foreach(_target ${arg_TARGETS}) - string(APPEND _usage_targets "${arg_NAME}::${_target} ") - endforeach() - string(STRIP ${_usage_targets} _usage_targets) - set(USAGE_FILE_CONTENT - "# The package ${arg_NAME} provides the following CMake targets: - - find_package(${arg_NAME} CONFIG REQUIRED) - target_link_libraries(main PRIVATE ${_usage_targets}) -") - file(WRITE ${_cache_dir}/usage ${USAGE_FILE_CONTENT}) - install(FILES ${_cache_dir}/usage DESTINATION share/${arg_NAME}) - install(CODE "MESSAGE(STATUS \"${USAGE_FILE_CONTENT}\")") - -endfunction() - #[[ A function to provide a target to uninstall things from the command `cmake install`. diff --git a/cmake/install/Default.cmake b/cmake/install/Default.cmake index a2de3f3..7e50e61 100644 --- a/cmake/install/Default.cmake +++ b/cmake/install/Default.cmake @@ -2,3 +2,9 @@ Default to installation. ]] include_guard(GLOBAL) + +include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/InstallCopyright.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/InstallTarget.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/InstallDependency.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/Runpath.cmake) diff --git a/cmake/install/InstallCopyright.cmake b/cmake/install/InstallCopyright.cmake index 54405d4..f89b585 100644 --- a/cmake/install/InstallCopyright.cmake +++ b/cmake/install/InstallCopyright.cmake @@ -1,3 +1,7 @@ +#[[ +This module provides tools to handle cmake copyright installations painlessly. +]] + include_guard(GLOBAL) #[[.md diff --git a/cmake/install/InstallDependency.cmake b/cmake/install/InstallDependency.cmake index e5245a3..e81db83 100644 --- a/cmake/install/InstallDependency.cmake +++ b/cmake/install/InstallDependency.cmake @@ -1,5 +1,5 @@ #[[ -This module provides tools to handle cmake installations painlessly. +This module provides tools to handle cmake dependency installations painlessly. ]] include_guard(GLOBAL) diff --git a/cmake/install/InstallTarget.cmake b/cmake/install/InstallTarget.cmake new file mode 100644 index 0000000..0feee0f --- /dev/null +++ b/cmake/install/InstallTarget.cmake @@ -0,0 +1,235 @@ +#[[ +This module provides tools to handle cmake target installations painlessly. +]] + +include_guard(GLOBAL) + +include(${CMAKE_CURRENT_LIST_DIR}/InstallCopyright.cmake) + +#[[ +A function to add install config rules to target + +Arguments: + NAME - A name as the installation export name. (required) + VERSION - The target version. Default to "0.0.0". (optional) + COMPATIBILITY - Compatibility on version. Default to SameMajorVersion. (optional) + CONFIGURE_PACKAGE_CONFIG_FILE - The file to generate config file. (optional) + INCLUDES - The include directories to install. (optional) + INCLUDE_FILES - The include files to install. (optional) + TARGETS - The targets to pack. (required) + DEPENDENCIES - The dependencies to check in config file. (required) + +Note: + + Includes from sources can be installed by PUBLIC_HEADER using set_target_properties + which flattens the hierarchy and puts the header files into the same directory. So + the recommended way it to use INCLUDES or INCLUDE_FILES. + see https://stackoverflow.com/questions/54271925/how-to-configure-cmakelists-txt-to-install-public-headers-of-a-shared-library + +Example: + + add_library(header INTERFACE) + target_include_interface_directories(header ${CMAKE_CURRENT_SOURCE_DIR}/include) + target_link_libraries(header INTERFACE absl::log) + set_target_properties(header PROPERTIES PUBLIC_HEADER "${public_headers}") + install_target( + NAME + header + VERSION + ${CMAKE_PROJECT_VERSION} + INCLUDES + ${CMAKE_CURRENT_SOURCE_DIR}/include/ # install subdirectories with / + TARGETS + header + DEPENDENCIES + "absl:log") + +]] +function(install_target) + set(_opts) + set(_single_opts NAME VERSION COMPATIBILITY CONFIGURE_PACKAGE_CONFIG_FILE) + set(_multi_opts TARGETS INCLUDES INCLUDE_FILES DEPENDENCIES LICENSE_FILE_LIST) + cmake_parse_arguments(PARSE_ARGV 0 arg "${_opts}" "${_single_opts}" + "${_multi_opts}") + + include(GNUInstallDirs) + # Specify rules at install time + install( + TARGETS ${arg_TARGETS} + EXPORT ${arg_NAME}-targets + LIBRARY DESTINATION $<$:debug/>${CMAKE_INSTALL_LIBDIR} + COMPONENT ${arg_NAME}_runtime + ARCHIVE DESTINATION $<$:debug/>${CMAKE_INSTALL_LIBDIR} + COMPONENT ${arg_NAME}_runtime + RUNTIME DESTINATION $<$:debug/>${CMAKE_INSTALL_BINDIR} + COMPONENT ${arg_NAME}_runtime + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME} + COMPONENT ${arg_NAME}_development) + + if(arg_INCLUDES) + install(DIRECTORY ${arg_INCLUDES} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME}) + endif() + + if(arg_INCLUDE_FILES) + install(FILES ${arg_INCLUDE_FILES} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_NAME}) + endif() + + if(arg_LICENSE_FILE_LIST) + install_copyright(FILE_LIST ${arg_LICENSE_FILE_LIST} DESTINATION + share/${arg_NAME}) + endif() + + install( + EXPORT ${arg_NAME}-targets + FILE ${arg_NAME}-targets.cmake + NAMESPACE ${arg_NAME}:: + DESTINATION share/${arg_NAME} + COMPONENT ${arg_NAME}_development) + + set(_cache_dir + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CURRENT_FUNCTION}/${arg_NAME}) + + if(NOT arg_CONFIGURE_PACKAGE_CONFIG_FILE) + + set(_configure_package_config_file_content + "#[=======================================================================[.rst: +${arg_NAME}-config.cmake +------------------- + +${arg_NAME} cmake module. +This module sets the following variables in your project: + +:: + + ${arg_NAME}_FOUND - true if ${arg_NAME} found on the system + ${arg_NAME}_VERSION - ${arg_NAME} version in format Major.Minor.Release +") + string( + APPEND + _configure_package_config_file_content + " + +Exported targets: + +:: + +If ${arg_NAME} is found, this module defines the following :prop_tgt:`IMPORTED` +targets. :: +") + foreach(_tgt ${arg_TARGETS}) + get_target_property(_target_type "${_tgt}" TYPE) + string( + APPEND + _configure_package_config_file_content + " + ${arg_NAME}::${_tgt} - the main ${arg_NAME} ${_target_type} with header & defs attached." + ) + endforeach() + + string( + APPEND + _configure_package_config_file_content + " + + +Suggested usage: + +:: + + find_package(${arg_NAME}) + find_package(${arg_NAME} CONFIG REQUIRED) + + +The following variables can be set to guide the search for this package: + +:: + + ${arg_NAME}_DIR - CMake variable, set to directory containing this Config file + CMAKE_PREFIX_PATH - CMake variable, set to root directory of this package + PATH - environment variable, set to bin directory of this package + CMAKE_DISABLE_FIND_PACKAGE_${arg_NAME} - CMake variable, disables find_package(${arg_NAME}) + perhaps to force internal build + +#]=======================================================================] +") + + string( + APPEND + _configure_package_config_file_content + "@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +") + string(APPEND _configure_package_config_file_content " +# Dependency check here") + foreach(_dep ${arg_DEPENDENCIES}) + string(APPEND _configure_package_config_file_content " +find_dependency(${_dep} REQUIRED)") + endforeach() + + string(REPLACE ";" " " _tgts "${arg_TARGETS}") + string( + APPEND + _configure_package_config_file_content + " + +include(\"\${CMAKE_CURRENT_LIST_DIR}/${arg_NAME}-targets.cmake\") +check_required_components(${_tgts}) +") + + file(WRITE ${_cache_dir}/${arg_NAME}-config.cmake.in + ${_configure_package_config_file_content}) + set(arg_CONFIGURE_PACKAGE_CONFIG_FILE + ${_cache_dir}/${arg_NAME}-config.cmake.in) + endif() + + include(CMakePackageConfigHelpers) + + configure_package_config_file( + ${arg_CONFIGURE_PACKAGE_CONFIG_FILE} ${_cache_dir}/${arg_NAME}-config.cmake + INSTALL_DESTINATION share/${arg_NAME}) + + if(NOT arg_COMPATIBILITY) + set(arg_COMPATIBILITY SameMajorVersion) + endif() + + if(NOT arg_VERSION) + set(arg_VERSION "0.0.0") + endif() + + write_basic_package_version_file( + ${_cache_dir}/${arg_NAME}-config-version.cmake + VERSION ${arg_VERSION} + COMPATIBILITY ${arg_COMPATIBILITY}) + + install(FILES ${_cache_dir}/${arg_NAME}-config.cmake + ${_cache_dir}/${arg_NAME}-config-version.cmake + DESTINATION share/${arg_NAME}) + + # Export from build tree + export( + EXPORT ${arg_NAME}-targets + FILE ${_cache_dir}/${arg_NAME}-targets.cmake + NAMESPACE ${arg_NAME}::) + + export(PACKAGE ${arg_NAME}) + + # Generate the usage file + set(_usage_targets) + foreach(_target ${arg_TARGETS}) + string(APPEND _usage_targets "${arg_NAME}::${_target} ") + endforeach() + string(STRIP ${_usage_targets} _usage_targets) + set(USAGE_FILE_CONTENT + "# The package ${arg_NAME} provides the following CMake targets: + + find_package(${arg_NAME} CONFIG REQUIRED) + target_link_libraries(main PRIVATE ${_usage_targets}) +") + file(WRITE ${_cache_dir}/usage ${USAGE_FILE_CONTENT}) + install(FILES ${_cache_dir}/usage DESTINATION share/${arg_NAME}) + install(CODE "MESSAGE(STATUS \"${USAGE_FILE_CONTENT}\")") + +endfunction() diff --git a/cmake/test/Default.cmake b/cmake/test/Default.cmake index 8cab7b7..2ef62b7 100644 --- a/cmake/test/Default.cmake +++ b/cmake/test/Default.cmake @@ -25,3 +25,5 @@ if(WIN32 AND NOT ${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") ) endif() endif() + +include(${CMAKE_CURRENT_LIST_DIR}/Test.cmake)