From c509dd267e8f79e8c20980deede6f0c138d86548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yohann=20B=C3=A9n=C3=A9dic?= Date: Sat, 12 Oct 2024 18:25:19 +0200 Subject: [PATCH] more tests and final layout --- io1_add_target.cmake | 386 +++++++++++++++------------------ test/update_source_group.cmake | 54 +++++ 2 files changed, 225 insertions(+), 215 deletions(-) create mode 100644 test/update_source_group.cmake diff --git a/io1_add_target.cmake b/io1_add_target.cmake index 1212a9f..b9e537e 100644 --- a/io1_add_target.cmake +++ b/io1_add_target.cmake @@ -1,230 +1,186 @@ include_guard() -if(COMMAND add_target) - message( - WARNING - "add_target function already exists, breaking early instead of overriding." - ) - return() +if(COMMAND io1_add_target) + message( + WARNING + "io1_add_target function already exists, breaking early instead of overriding." + ) + return() endif() -function(add_target target_name) - if(TARGET ${target_name}) - message( - FATAL_ERROR - "${CMAKE_CURRENT_FUNCTION}: Cannot add target ${target_name} because it already exists." - ) - endif() - - set(options "STATIC;SHARED;EXECUTALBE;WIN32_EXECUTABLE;HEADER_ONLY") - set(multivalue_keywords - "INCLUDES;DEPENDENCIES;OPTIONS;DEFINITIONS;FEATURES;BOOST_TEST;GOOGLE_TEST" - ) - - cmake_parse_arguments(PARSE_ARGV 1 io1 "${options}" "" - "${multivalue_keywords}") - - # options are mutually exclusive the found_options list must have length one - # at the end of this loop - foreach(option IN LISTS options) - if(io1_${option}) - list(APPEND found_option ${option}) - endif() - endforeach() - list(LENGTH found_option found_option_count) - if(NOT found_option_count LESS_EQUAL 1) - message( - FATAL_ERROR - "${CMAKE_CURRENT_FUNCTION}: cannot define multiple target types.") - endif() - - # target sources are the leftover values - fetch_source_files(sources ${io1_UNPARSED_ARGUMENTS}) - - # create the target with the type detected by found_option - if(io1_STATIC) - add_library(${target_name} STATIC ${sources}) - elseif(io1_SHARED) - add_library(${target_name} SHARED ${sources}) - elseif(io1_EXECUTABLE) - add_executable(${target_name} ${sources}) - elseif(io1_HEADER_ONLY) - add_library(${target_name} INTERFACE ${sources}) - elseif (io1_WIN32_EXECUTABLE) - add_executable(${target_name} WIN32 ${sources}) - else() - add_library(${target_name} ${sources}) - endif() - - # apply source files properties and groups - apply_source_groups(${io1_UNPARSED_ARGUMENTS}) - apply_source_files_properties(${io1_UNPARSED_ARGUMENTS}) - - message( - STATUS - "${CMAKE_CURRENT_FUNCTION}: created ${found_option} target ${target_name}." - ) - - # configure the target from the multi-value keywords - if(DEFINED io1_INCLUDES) - target_include_directories(${target_name} ${io1_INCLUDES}) - endif() - if(DEFINED io1_DEPENDENCIES) - target_link_libraries(${target_name} ${io1_DEPENDENCIES}) - endif() - if(DEFINED io1_OPTIONS) - target_compile_options(${target_name} ${io1_OPTIONS}) - endif() - if(DEFINED io1_DEFINITIONS) - target_compile_definitions(${target_name} ${io1_DEFINITIONS}) - endif() - if(DEFINED io1_FEATURES) - target_compile_features(${target_name} ${io1_FEATURES}) - endif() - if(DEFINED io1_BOOST_TEST) - set(test_name "boost-test-${target_name}") - if(TARGET ${test_name}) - message( - FATAL_ERROR - "${CMAKE_CURRENT_FUNCTION}: cannot create boost test target ${test_name} because it already exists." - ) - endif() - - find_package( - Boost REQUIRED - COMPONENTS unit_test_framework - QUIET) - - fetch_source_files(test_sources ${io1_BOOST_TEST}) - - add_executable(${test_name} ${test_sources}) - - apply_source_groups(${io1_BOOST_TEST}) - apply_source_files_properties(${io1_BOOST_TEST}) - - target_link_libraries(${test_name} PRIVATE ${target_name} - Boost::unit_test_framework) - - message( - STATUS - "${CMAKE_CURRENT_FUNCTION}: created boost test target ${test_name}.") - - if(BUILD_TESTING) - add_test( - NAME ${test_name} - COMMAND ${test_name} --catch_system_error=yes --detect_memory_leaks - --logger=JUNIT,all,junit_${test_name}.xml - WORKING_DIRECTORY $) - else() - message( - STATUS - "${CMAKE_CURRENT_FUNCTION}: skipped declaring ${test_name} to CTest because BUILD_TESTING is false." - ) - endif() - endif() - if(DEFINED io1_GOOGLE_TEST) - if(NOT COMMAND gtest_discover_tests) - include(GoogleTest) - endif() - - set(test_name "google-test-${target_name}") - if(TARGET ${test_name}) - message( - FATAL_ERROR - "${CMAKE_CURRENT_FUNCTION}: cannot create google test target ${test_name} because it already exists." - ) - endif() - - find_package(GTest REQUIRED QUIET) - - fetch_source_files(test_sources ${io1_GOOGLE_TEST}) - - add_executable(${test_name} ${test_sources}) - - apply_source_groups(${io1_GOOGLE_TEST}) - apply_source_files_properties(${io1_GOOGLE_TEST}) - - target_link_libraries(${test_name} PRIVATE ${target_name} GTest::Main) - message( - STATUS - "${CMAKE_CURRENT_FUNCTION}: created google test target ${test_name}.") - - if(BUILD_TESTING) - gtest_discover_tests(${test_name} - WORKING_DIRECTORY $) - else() - message( - STATUS - "${CMAKE_CURRENT_FUNCTION}: skipped declaring ${test_name} to CTest because BUILD_TESTING is false." - ) - endif() - endif() +function(io1_add_target target_name) + if(TARGET ${target_name}) + message( + FATAL_ERROR + "${CMAKE_CURRENT_FUNCTION}: Cannot add target ${target_name} because it already exists." + ) + endif() -endfunction() + set(options "STATIC;SHARED;EXECUTALBE;WIN32_EXECUTABLE;HEADER_ONLY") + set(multivalue_keywords + "INCLUDES;DEPENDS;OPTIONS;DEFINITIONS;FEATURES;BOOST_TEST;GOOGLE_TEST" + ) + + cmake_parse_arguments(PARSE_ARGV 1 io1 "${options}" "" + "${multivalue_keywords}") + + # options are mutually exclusive the found_options list must have length one + # at the end of this loop + foreach(option IN LISTS options) + if(io1_${option}) + list(APPEND found_option ${option}) + endif() + endforeach() + + list(LENGTH found_option found_option_count) + if(NOT found_option_count LESS_EQUAL 1) + message( + FATAL_ERROR + "${CMAKE_CURRENT_FUNCTION}: cannot define multiple target types.") + endif() + + # target sources are the leftover values + fetch_source_files(sources ${io1_UNPARSED_ARGUMENTS}) + + # create the target with the type detected by found_option + if(io1_STATIC) + add_library(${target_name} STATIC) + elseif(io1_SHARED) + add_library(${target_name} SHARED) + elseif(io1_EXECUTABLE) + add_executable(${target_name}) + elseif(io1_HEADER_ONLY) + add_library(${target_name} INTERFACE) + elseif (io1_WIN32_EXECUTABLE) + add_executable(${target_name} WIN32) + else() + add_library(${target_name}) + endif() + + # adding sources + io1_target_add_sources(${target_name} ${io1_UNPARSED_ARGUMENTS}) + + message( + STATUS + "${CMAKE_CURRENT_FUNCTION}: created ${found_option} target ${target_name}." + ) + + # configure the target from the multi-value keywords + if(DEFINED io1_INCLUDES) + target_include_directories(${target_name} ${io1_INCLUDES}) + endif() + if(DEFINED io1_DEPENDENCIES) + target_link_libraries(${target_name} ${io1_DEPENDENCIES}) + endif() + if(DEFINED io1_OPTIONS) + target_compile_options(${target_name} ${io1_OPTIONS}) + endif() + if(DEFINED io1_DEFINITIONS) + target_compile_definitions(${target_name} ${io1_DEFINITIONS}) + endif() + if(DEFINED io1_FEATURES) + target_compile_features(${target_name} ${io1_FEATURES}) + endif() + + if(DEFINED io1_BOOST_TEST) + set(test_name "boost-test-${target_name}") + if(TARGET ${test_name}) + message( + FATAL_ERROR + "${CMAKE_CURRENT_FUNCTION}: cannot create boost test target ${test_name} because it already exists." + ) + endif() + + find_package( + Boost REQUIRED + COMPONENTS unit_test_framework + QUIET) -set(source_group_regex "^(.*)//$") -set(source_file_properties_regex "^(.+):?(.*)$") -function(apply_source_groups) - fetch_source_groups(sources groups ${ARGN}) + add_executable(${test_name}) + io1_target_add_sources(${test_name} ${io1_BOOST_TEST}) + + target_link_libraries(${test_name} PRIVATE ${target_name} + Boost::unit_test_framework) + + message( + STATUS + "${CMAKE_CURRENT_FUNCTION}: created boost test target ${test_name}.") + + if(BUILD_TESTING) + add_test( + NAME ${test_name} + COMMAND ${test_name} --catch_system_error=yes --detect_memory_leaks + --logger=JUNIT,all,junit_${test_name}.xml + WORKING_DIRECTORY $) + else() + message( + STATUS + "${CMAKE_CURRENT_FUNCTION}: skipped declaring ${test_name} to CTest because BUILD_TESTING is false." + ) + endif() + endif() + if(DEFINED io1_GOOGLE_TEST) + if(NOT COMMAND gtest_discover_tests) + include(GoogleTest) + endif() + + set(test_name "google-test-${target_name}") + if(TARGET ${test_name}) + message( + FATAL_ERROR + "${CMAKE_CURRENT_FUNCTION}: cannot create google test target ${test_name} because it already exists." + ) + endif() + + find_package(GTest REQUIRED QUIET) + + add_executable(${test_name}) + io1_target_add_sources(${test_name} ${io1_GOOGLE_TEST}) + + target_link_libraries(${test_name} PRIVATE ${target_name} GTest::Main) + message( + STATUS + "${CMAKE_CURRENT_FUNCTION}: created google test target ${test_name}.") + + if(BUILD_TESTING) + gtest_discover_tests(${test_name} + WORKING_DIRECTORY $) + else() + message( + STATUS + "${CMAKE_CURRENT_FUNCTION}: skipped declaring ${test_name} to CTest because BUILD_TESTING is false." + ) + endif() + endif() - foreach(source group IN ZIP_LISTS sources groups) - source_group(NAME "${group}" FILES "${source}") - endforeach() endfunction() -function(fetch_source_groups out_sources out_groups) - set(current_group_name ".") - set(current_group_path "/.") - - foreach(file IN LISTS ARGN) - if("${file}" MATCHES "${source_group_regex}") - set(new_group_path "${CMAKE_MATCH_1}") - - if(IS_ABSOLUTE "${new_group_path}") - set(current_group_path "${new_group_path}") - else() - get_filename_component(current_group_path "${new_group_path}" ABSOLUTE - BASE_DIR "${current_group_path}") - endif() - - string(SUBSTRING "${current_group_path}" 1 -1 current_group_name) - - elseif(NOT "${current_group_name}" STREQUAL ".") - list(APPEND temp_out_groups "${current_group_name}") - if("${file}" MATCHES "${source_file_properties_regex}") - list(APPEND temp_out_sources "${CMAKE_MATCH_1}") - else() - list(APPEND temp_out_sources "${file}") - endif() - endif() - endforeach() - - set(${out_sources} - "${temp_out_sources}" - PARENT_SCOPE) - set(${out_groups} - "${temp_out_groups}" - PARENT_SCOPE) +function(io1_target_add_sources target_name) + set(current_group "/") + foreach(str IN LISTS ${ARGN}) + io1_is_source_group("${str}" res) + if(DEFINED res) + io1_update_source_group("${current_group}" "${res}" current_group) + else() + io1_parse_file_options("${str}" filename options) + io1_add_source_file(${target_name} "${filename}" ${options} "${current_group}") + endif() + endforeach() endfunction() -# strip out groups strings and source file properties -function(fetch_source_files out_sources) - foreach(str IN LISTS ARGN) - if("${str}" MATCHES "${source_group_regex}") - continue() - endif() - - if("${str}" MATCHES "${source_file_properties_regex}") - list(APPEND temp_out_sources "${CMAKE_MATCH_1}") - else() - list(APPEND temp_out_sources "${str}") - endif() - endforeach() - - set(${out_sources} - "${temp_out_sources}" - PARENT_SCOPE) +# update a given source group +function(io1_update_source_group current_group str updated_group) + if(IS_ABSOLUTE "${str}") + message("${str} is absolute") + set(${updated_group} "${str}" PARENT_SCOPE) + else() + message("${str} is not absolute") + get_filename_component(temp "${str}" ABSOLUTE BASE_DIR "${current_group}") + message("${temp} is ${str} relative to ${current_group}") + set(${updated_group} "${temp}" PARENT_SCOPE) + endif() + endfunction() # adds src to target, applying options and source group diff --git a/test/update_source_group.cmake b/test/update_source_group.cmake new file mode 100644 index 0000000..2d45921 --- /dev/null +++ b/test/update_source_group.cmake @@ -0,0 +1,54 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../io1_add_target.cmake) + +ct_add_test(NAME io1.update_source_group.normal) +function(${CMAKETEST_TEST}) + set(current_group "foo") + set(updated_group "meow") + io1_update_source_group("${current_group}" "bar" updated_group) + ct_assert_equal(updated_group "foo/bar") + + set(current_group "foo") + set(updated_group "meow") + io1_update_source_group("${current_group}" "bar/meow" updated_group) + ct_assert_equal(updated_group "foo/bar/meow") + + set(current_group "foo") + set(updated_group "meow") + io1_update_source_group("${current_group}" "/bar" updated_group) + ct_assert_equal(updated_group "/bar") + + set(current_group "foo") + set(updated_group "meow") + io1_update_source_group("${current_group}" "./" updated_group) + ct_assert_equal(updated_group "foo") + + set(current_group "foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "../" updated_group) + ct_assert_equal(updated_group "foo") + + set(current_group "foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "../meow" updated_group) + ct_assert_equal(updated_group "foo/meow") + + set(current_group "/foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "../meow" updated_group) + ct_assert_equal(updated_group "/foo/meow") + + set(current_group "/foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "/" updated_group) + ct_assert_equal(updated_group "/") + + set(current_group "/foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "../../../" updated_group) + ct_assert_equal(updated_group "/") + + set(current_group "/foo/bar") + set(updated_group "meow") + io1_update_source_group("${current_group}" "../../../meow" updated_group) + ct_assert_equal(updated_group "/meow") +endfunction()