diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a959cc..c526250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.19) project(test_add_target) -include(add_target.cmake) - macro(get_cmake_test) include(cmake_test/cmake_test OPTIONAL RESULT_VARIABLE cmake_test_found) if(NOT cmake_test_found) @@ -30,4 +28,5 @@ get_cmake_test() include(cmake_test/cmake_test) -ct_add_dir("test") +enable_testing() +ct_add_dir("test" USE_REL_PATH_NAMES) diff --git a/fetch_source_files.cmake b/fetch_source_files.cmake deleted file mode 100644 index c22ceff..0000000 --- a/fetch_source_files.cmake +++ /dev/null @@ -1,62 +0,0 @@ -include(add_target.cmake) -include(unit_test_for_cmake/unit-test.cmake) - -function(test_sources_alone) - fetch_source_files(sources test.cpp) - expect_streq("test.cpp" "${sources}") - - fetch_source_files(sources "test.cpp;foo.txt") - expect_streq("test.cpp;foo.txt" "${sources}") - - fetch_source_files(sources "test.cpp" "foo.txt") - expect_streq("test.cpp;foo.txt" "${sources}") - - fetch_source_files(sources) - expect_empty("${sources}") - - fetch_source_files(out_sources "test.cpp") - expect_streq("test.cpp" "${out_sources}") - - fetch_source_files(out_sources "test.cpp;foo.txt") - expect_streq("test.cpp;foo.txt" "${out_sources}") -endfunction() - -function(test_groups_alone) - fetch_source_files(sources "///") - expect_empty("${sources}") - - fetch_source_files(sources "//") - expect_empty("${sources}") - - fetch_source_files(sources "//" "a//" "/b//" "a/b/c//" "/a/b//") - expect_empty("${sources}") - - fetch_source_files(sources "//;a//;/b//;a/b/c//;/a/b//") - expect_empty("${sources}") -endfunction() - -function(test_options) - fetch_source_files(sources "test.cpp:header" "test.txt:file") - expect_streq("test.cpp;test.txt" "${sources}") - - fetch_source_files(sources "test.cpp:header;test.txt:file") - expect_streq("test.cpp;test.txt" "${sources}") - - fetch_source_files( - sources "test.cpp:header;test.txt:file//") # last one interpreted as group - expect_streq("test.cpp" "${sources}") -endfunction() - -function(test_all_together) - fetch_source_files(sources "test.h" "b//" "test.cpp:header" "/a:c//" - "test.txt") - expect_streq("test.h;test.cpp;test.txt" "${sources}") - - fetch_source_files(sources "test.h;b:c//;test.cpp:header;/a//;test.txt") - expect_streq("test.h;test.cpp;test.txt" "${sources}") -endfunction() - -test_sources_alone() -test_groups_alone() -test_options() -test_all_together() diff --git a/fetch_source_groups.cmake b/fetch_source_groups.cmake deleted file mode 100644 index 5439fc0..0000000 --- a/fetch_source_groups.cmake +++ /dev/null @@ -1,64 +0,0 @@ -include(add_target.cmake) -include(unit_test_for_cmake/unit-test.cmake) - -function(test_no_groups) - fetch_source_groups(sources groups "") - expect_empty("${groups}") - expect_empty("${sources}") - - fetch_source_groups(sources groups "test.cpp") - expect_empty("${groups}") - expect_empty("${sources}") - - fetch_source_groups(out_sources out_groups "") - expect_empty("${out_sources}") - expect_empty("${out_groups}") - - fetch_source_groups(out_sources out_groups "test.cpp") - expect_empty("${out_sources}") - expect_empty("${out_groups}") -endfunction() - -function(test_no_sources) - fetch_source_groups(sources groups "toto//") - expect_empty("${groups}") - expect_empty("${sources}") - - fetch_source_groups(sources groups "/toto//;tata//") - expect_empty("${groups}") - expect_empty("${sources}") - - fetch_source_groups(out_sources out_groups "toto//") - expect_empty("${out_sources}") - expect_empty("${out_groups}") - - fetch_source_groups(out_sources out_groups "/toto//;tata//") - expect_empty("${out_sources}") - expect_empty("${out_groups}") -endfunction() - -function(test_main) - fetch_source_groups( - sources groups - "test.cpp;toto//;test.h;detail/impl.h;tata//;help.txt;/foo/bar//;readme.md") - expect_streq("${groups}" "toto;toto;toto/tata;foo/bar") - expect_streq("${sources}" "test.h;detail/impl.h;help.txt;readme.md") - - fetch_source_groups( - out_sources out_groups - "test.cpp;toto//;test.h;detail/impl.h;tata//;help.txt;/foo/bar//;readme.md") - expect_streq("${out_groups}" "toto;toto;toto/tata;foo/bar") - expect_streq("${out_sources}" "test.h;detail/impl.h;help.txt;readme.md") - - fetch_source_groups(sources groups "") - expect_empty("${groups}") - expect_empty("${sources}") - - fetch_source_groups(out_sources out_groups "") - expect_empty("${out_groups}") - expect_empty("${out_sources}") -endfunction() - -test_no_groups() -test_no_sources() -test_main() diff --git a/add_target.cmake b/io1_add_target.cmake similarity index 82% rename from add_target.cmake rename to io1_add_target.cmake index 27c7f17..18ffe43 100644 --- a/add_target.cmake +++ b/io1_add_target.cmake @@ -163,7 +163,7 @@ function(add_target target_name) endfunction() set(source_group_regex "^(.*)//$") -set(source_file_properties_regex "^(.*):(.*)$") +set(source_file_properties_regex "^(.+):?(.*)$") function(apply_source_groups) fetch_source_groups(sources groups ${ARGN}) @@ -227,9 +227,11 @@ function(fetch_source_files out_sources) PARENT_SCOPE) endfunction() + function(apply_source_files_properties) foreach(str IN LISTS ARGN) - if("${str}" MATCHES "${source_group_regex}") + is_source_group("${str}" out) + if(out) continue() endif() @@ -245,29 +247,63 @@ function(apply_source_files_properties) endforeach() endfunction() +# adds src to target, applying options +function(io1_add_source_file target src) + io1_parse_file_options("${src}" file options) + + get_target_property(type ${target} TYPE) + if (${type} STREQUAL "INTERFACE_LIBRARY") + target_sources(${target} INTERFACE ${file}) + else() + target_sources(${target} PRIVATE ${file}) + endif() + + cmake_parse_arguments(io1 "cpp;header" "" "" ${options}) + if(io1_cpp) + set_source_files_properties("${file}" PROPERTIES LANGUAGE CXX) + endif() + if(io1_header) + set_source_files_properties("${file}" PROPERTIES HEADER_FILE_ONLY ON) + endif() +endfunction() + +# any string that ends with // is a source group +function(io1_is_source_group str res) + if("${str}" MATCHES "^(.*)//$") + set(${res} "TRUE" PARENT_SCOPE) + else() + set(${res} "FALSE" PARENT_SCOPE) + endif() +endfunction() + # expects "file.c[:opt1,opt2,opt3,...]" and parse it into "file.c" and the list # "opt1;opt2;opt3" -function(parse_file_options str out_file out_options) - if("${str}" MATCHES "${source_file_properties_regex}") - set(${out_file} - "${CMAKE_MATCH_1}" - PARENT_SCOPE) - if("${CMAKE_MATCH_1}" STREQUAL "") - set(${out_options} - "" - PARENT_SCOPE) - else() - string(REPLACE "," ";" temp_out_options "${CMAKE_MATCH_2}") - set(${out_options} - "${temp_out_options}" - PARENT_SCOPE) - endif() - else() - set(${out_file} - "${str}" - PARENT_SCOPE) - set(${out_options} - "" - PARENT_SCOPE) - endif() +function(io1_parse_file_options str out_file out_options) + if("${str}" MATCHES "^(.*):(.*)$") + if ("${CMAKE_MATCH_1}" STREQUAL "") + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION}: ignored orphaned source option '${CMAKE_MATCH_2}'.") + else() + set(${out_file} + "${CMAKE_MATCH_1}" + PARENT_SCOPE) + + if("${CMAKE_MATCH_2}" STREQUAL "") + unset(${out_options} + PARENT_SCOPE) + else() + string(REPLACE "," ";" temp_out_options "${CMAKE_MATCH_2}") + set(${out_options} + "${temp_out_options}" + PARENT_SCOPE) + endif() + endif() + else() + set(${out_file} + "${str}" + PARENT_SCOPE + ) + unset(${out_options} + PARENT_SCOPE + ) + endif() endfunction() diff --git a/test/add_source_file.cmake b/test/add_source_file.cmake new file mode 100644 index 0000000..0d068f5 --- /dev/null +++ b/test/add_source_file.cmake @@ -0,0 +1,28 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../io1_add_target.cmake) +file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/foo.cpp" "int main() { return 0; }") + +ct_add_test(NAME io1.add_source_file.normal) +function(${CMAKETEST_TEST}) + add_library(foo STATIC) + set_target_properties(foo PROPERTIES LINKER_LANGUAGE CXX) + + io1_add_source_file(foo "foo.cpp") + get_source_file_property(prop "foo.cpp" LANGUAGE) + ct_assert_equal(prop "NOTFOUND") + + get_source_file_property(prop "foo.cpp" HEADER_FILE_ONLY) + ct_assert_equal(prop "NOTFOUND") +endfunction() + +ct_add_test(NAME io1.add_source_file.header) +function(${CMAKETEST_TEST}) + add_library(foo_header STATIC) + set_target_properties(foo_header PROPERTIES LINKER_LANGUAGE CXX) + + io1_add_source_file(foo_header "foo.cpp:header") + get_source_file_property(prop "foo.cpp" LANGUAGE) + #ct_assert_equal(prop "NOTFOUND") + + get_source_file_property(prop "foo.cpp" HEADER_FILE_ONLY) + ct_assert_equal(prop "ON") +endfunction() diff --git a/test/is_source_group.cmake b/test/is_source_group.cmake new file mode 100644 index 0000000..331f6ae --- /dev/null +++ b/test/is_source_group.cmake @@ -0,0 +1,56 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../io1_add_target.cmake) + +ct_add_test(NAME io1.is_source_group.normal) +function(${CMAKETEST_TEST}) + set(out "foo") + io1_is_source_group("test.cpp" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("test" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("/" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("/foo" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("/foo/" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("/foo/bar" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("/foo/bar/" out) + ct_assert_false(out) + + set(out "foo") + io1_is_source_group("//" out) + ct_assert_true(out) + + set(out "foo") + io1_is_source_group("/foo//" out) + ct_assert_true(out) + + set(out "foo") + io1_is_source_group("foo//" out) + ct_assert_true(out) + + set(out "foo") + io1_is_source_group("bar/foo//" out) + ct_assert_true(out) + + set(out "foo") + io1_is_source_group("/bar/foo//" out) + ct_assert_true(out) +endfunction() diff --git a/test/parse_file_options.cmake b/test/parse_file_options.cmake index 8ff13a1..0724aa9 100644 --- a/test/parse_file_options.cmake +++ b/test/parse_file_options.cmake @@ -1,66 +1,53 @@ -include(cmake_test/cmake_test) +include(${CMAKE_CURRENT_LIST_DIR}/../io1_add_target.cmake) -ct_add_test(NAME parse_file_options.main) +# variable names out_file and out_options are also local names +# of parse_file_options, keep them in sync +ct_add_test(NAME io1.parse_file_options.normal) function(${CMAKETEST_TEST}) - parse_file_options("test.cpp" file options) - ct_assert_equal(file "test.cpp") - ct_assert_not_defined(options) + set(out_file "foo") + set(out_options "bar") + io1_parse_file_options("test.cpp" out_file out_options) - parse_file_options("test.cpp:toto" file options) - ct_assert_equal(file "test.cpp") - ct_assert_equal(options, "toto") - - parse_file_options("test.cpp:toto,tata" file options) - ct_assert_equal(file "test.cpp") - ct_assert_equal(options, "toto;tata") - - parse_file_options("test.cpp" file options) - ct_assert_equal(file "test.cpp") - ct_assert_not_defined(options) - - parse_file_options("" file options) - ct_assert_not_defined(file) - ct_assert_not_defined(options) - - parse_file_options(":" file options) - ct_assert_not_defined(file) - ct_assert_not_defined(options) + ct_assert_equal(out_file "test.cpp") + ct_assert_not_defined(out_options) +endfunction() - parse_file_options("test.cpp:" file options) - ct_assert_equal(file "test.cpp") - ct_assert_not_defined(options) +ct_add_test(NAME io1.parse_file_options.with_one_option) +function(${CMAKETEST_TEST}) + set(out_file "foo") + set(out_options "bar") + io1_parse_file_options("test.cpp:toto" out_file out_options) - parse_file_options(":toto" file options) - ct_assert_not_defined(file) - ct_assert_not_defined(options) + ct_assert_equal(out_file "test.cpp") + ct_assert_equal(out_options "toto") endfunction() - -# Using same variable names as in function definition because some -# implementations may break in this case. -ct_add_test(NAME parse_file_options.same_variable_names) +ct_add_test(NAME io1.parse_file_options.with_two_options) function(${CMAKETEST_TEST}) - parse_file_options("test.cpp" out_file out_options) - ct_assert_equal(out_file "test.cpp") - ct_assert_not_defined(out_options) + set(out_file "foo") + set(out_options "bar") + io1_parse_file_options("test.cpp:toto,tata" out_file out_options) - parse_file_options("test.cpp:toto" out_file out_options) - ct_assert_equal(out_file "test.cpp") - ct_assert_equal(out_options "toto") + ct_assert_equal(out_file "test.cpp") + ct_assert_equal(out_options "toto;tata") +endfunction() - parse_file_options("test.cpp" out_file out_options) - ct_assert_equal(out_file "test.cpp") - ct_assert_not_defined(out_options "toto") +ct_add_test(NAME io1.parse_file_options.with_no_option) +function(${CMAKETEST_TEST}) + set(out_file "foo") + set(out_options "bar") + io1_parse_file_options("test.cpp:" out_file out_options) - parse_file_options(":" out_file out_options) - ct_assert_not_defined(out_file) - ct_assert_not_defined(out_options) + ct_assert_equal(out_file "test.cpp") + ct_assert_not_defined(out_options) +endfunction() - parse_file_options("test.cpp:" out_file out_options) - ct_assert_equal(out_file "test.cpp") - ct_assert_not_defined(out_options) +ct_add_test(NAME io1.parse_file_options.orphaned_option EXPECTFAIL) +function(${CMAKETEST_TEST}) + io1_parse_file_options(":toto" out_file out_options) +endfunction() - parse_file_options(":toto" out_file out_options) - ct_assert_not_defined(out_file) - ct_assert_not_defined(out_options) +ct_add_test(NAME io1.parse_file_options.orphaned_no_option EXPECTFAIL) +function(${CMAKETEST_TEST}) + io1_parse_file_options(":" out_file out_options) endfunction()