From ff365305068cc9b6c6e3662ae12fa8021076af56 Mon Sep 17 00:00:00 2001 From: Steffen Olszewski Date: Wed, 10 May 2023 21:43:55 +0200 Subject: [PATCH] Add utility function to add source groups for files of a target This function uses default groups like Visual Studio and additional groups for files commonly used by CMake builds. This increases the required CMake version to 3.20. --- cmake/project.cmake | 118 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 cmake/project.cmake diff --git a/cmake/project.cmake b/cmake/project.cmake new file mode 100644 index 00000000..7bd25c49 --- /dev/null +++ b/cmake/project.cmake @@ -0,0 +1,118 @@ +cmake_minimum_required(VERSION 3.20) + +#[[ +Set default source groups. + +set_target_source_groups( + [STRIP_PREFIX ] + [STRIP_SOURCE_PREFIX ] + [STRIP_BINARY_PREFIX ] + [EXTRA_BINARY_DIRECTORY ]) + +Create source groups "Header Files", "Header Templates", "Source Files", "Source Templates", +"Generated Files" for the source files of the target . Only files inside the directory +trees rooted at SOURCE_DIR and BINARY_DIR of are grouped. + +If specified, the common path prefix of the files inside SOURCE_DIR and +the common path prefix of the files inside BINARY_DIR gets removed, +it is an error if not all paths start with that prefix. Use if the same prefix +should be used for SOURCE_DIR and BINARY_DIR, the other two parameters must not be specified in that case. + +If is specified, source files of inside that directory will also get added +to the group "Generated Files", no prefix stripping will be applied to these files. If +is not absolute it is interpreted relative to ${CMAKE_CURRENT_BINARY_DIR}. The may +contain BINARY_DIR of , the contents of BINARY_DIR will get excluded when processing . +]] +function(set_target_source_groups arg_TARGET) + set(options "") + set(singleValues STRIP_PREFIX STRIP_SOURCE_PREFIX STRIP_BINARY_PREFIX EXTRA_BINARY_DIRECTORY) + set(multiValues "") + cmake_parse_arguments(arg "${options}" "${singleValues}" "${multiValues}" ${ARGN}) + + get_target_property(sourceDir ${arg_TARGET} SOURCE_DIR) + get_target_property(binaryDir ${arg_TARGET} BINARY_DIR) + get_target_property(sources ${arg_TARGET} SOURCES) + + if(DEFINED arg_STRIP_PREFIX) + if(DEFINED arg_STRIP_SOURCE_PREFIX OR DEFINED arg_STRIP_BINARY_PREFIX) + message(FATAL_ERROR "STRIP_PREFIX must not be used together with STRIP_SOURCE_PREFIX or STRIP_BINARY_PREFIX") + endif() + set(arg_STRIP_SOURCE_PREFIX "${arg_STRIP_PREFIX}") + set(arg_STRIP_BINARY_PREFIX "${arg_STRIP_PREFIX}") + endif() + if(DEFINED arg_STRIP_SOURCE_PREFIX) + cmake_path(SET sourceTreeDir NORMALIZE "${sourceDir}/${arg_STRIP_SOURCE_PREFIX}") + else() + set(sourceTreeDir "${sourceDir}") + endif() + if(DEFINED arg_STRIP_BINARY_PREFIX) + cmake_path(SET binaryTreeDir NORMALIZE "${binaryDir}/${arg_STRIP_BINARY_PREFIX}") + else() + set(binaryTreeDir "${binaryDir}") + endif() + if(DEFINED arg_EXTRA_BINARY_DIRECTORY) + cmake_path(ABSOLUTE_PATH arg_EXTRA_BINARY_DIRECTORY BASE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" NORMALIZE) + endif() + + set(fileSources "") + foreach(source IN LISTS sources) + cmake_path(ABSOLUTE_PATH source BASE_DIRECTORY "${sourceDir}" NORMALIZE OUTPUT_VARIABLE file) + list(APPEND fileSources "${file}") + endforeach() + # Normally, the build tree is a subdirectory of the source tree. For the root directory the prefix match + # will also match the binary tree, so create separate file lists by filtering the binary prefix explicit. + # This will fail when doing an in-tree build, in that case everything will be classified as binary. + set(sourceFiles ${fileSources}) + list(FILTER sourceFiles EXCLUDE REGEX "^${binaryDir}/") + set(binaryFiles ${fileSources}) + list(FILTER binaryFiles INCLUDE REGEX "^${binaryDir}/") + + set(filterSources ${sourceFiles}) + list(FILTER filterSources INCLUDE REGEX "^${sourceDir}/.+\\.h(h|pp)?$") + source_group( + TREE "${sourceTreeDir}" + PREFIX "Header Files" + FILES ${filterSources} + ) + set(filterSources ${sourceFiles}) + list(FILTER filterSources INCLUDE REGEX "^${sourceDir}/.+\\.h(h|pp)?\\.in$") + source_group( + TREE "${sourceTreeDir}" + PREFIX "Header Templates" + FILES ${filterSources} + ) + set(filterSources ${sourceFiles}) + list(FILTER filterSources INCLUDE REGEX "^${sourceDir}/.+\\.c(c|xx|pp)?$") + source_group( + TREE "${sourceTreeDir}" + PREFIX "Source Files" + FILES ${filterSources} + ) + set(filterSources ${sourceFiles}) + list(FILTER filterSources INCLUDE REGEX "^${sourceDir}/.+\\.c(c|xx|pp)?\\.in$") + source_group( + TREE "${sourceTreeDir}" + PREFIX "Source Templates" + FILES ${filterSources} + ) + + set(filterSources ${binaryFiles}) + list(FILTER filterSources INCLUDE REGEX "^${binaryDir}/") + source_group( + TREE "${binaryTreeDir}" + PREFIX "Generated Files" + FILES ${filterSources} + ) + if(DEFINED arg_EXTRA_BINARY_DIRECTORY) + # If the specified directory contains the binary dir of the target, the files will get added + # twice with a different path, so exclude that directory. + set(filterSources ${fileSources}) + list(FILTER filterSources INCLUDE REGEX "^${arg_EXTRA_BINARY_DIRECTORY}/") + list(FILTER filterSources EXCLUDE REGEX "^${binaryDir}/") + source_group( + TREE "${arg_EXTRA_BINARY_DIRECTORY}" + PREFIX "Generated Files" + FILES ${filterSources} + ) + endif() +endfunction()