1# This is a helper function and not a build rule. It is to be used by the 2# various test rules to generate the full list of object files 3# recursively produced by "add_entrypoint_object" and "add_object_library" 4# targets. 5# Usage: 6# get_object_files_for_test(<result var> 7# <skipped_entrypoints_var> 8# <target0> [<target1> ...]) 9# 10# The list of object files is collected in <result_var>. 11# If skipped entrypoints were found, then <skipped_entrypoints_var> is 12# set to a true value. 13# targetN is either an "add_entrypoint_target" target or an 14# "add_object_library" target. 15function(get_object_files_for_test result skipped_entrypoints_list) 16 set(object_files "") 17 set(skipped_list "") 18 foreach(dep IN LISTS ARGN) 19 get_target_property(dep_type ${dep} "TARGET_TYPE") 20 if(NOT dep_type) 21 # Target for which TARGET_TYPE property is not set do not 22 # provide any object files. 23 continue() 24 endif() 25 26 if(${dep_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE}) 27 get_target_property(dep_object_files ${dep} "OBJECT_FILES") 28 if(dep_object_files) 29 list(APPEND object_files ${dep_object_files}) 30 endif() 31 elseif(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}) 32 get_target_property(is_skipped ${dep} "SKIPPED") 33 if(is_skipped) 34 list(APPEND skipped_list ${dep}) 35 continue() 36 endif() 37 get_target_property(object_file_raw ${dep} "OBJECT_FILE_RAW") 38 if(object_file_raw) 39 list(APPEND object_files ${object_file_raw}) 40 endif() 41 endif() 42 43 get_target_property(indirect_deps ${dep} "DEPS") 44 get_object_files_for_test( 45 indirect_objfiles indirect_skipped_list ${indirect_deps}) 46 list(APPEND object_files ${indirect_objfiles}) 47 if(indirect_skipped_list) 48 list(APPEND skipped_list ${indirect_skipped_list}) 49 endif() 50 endforeach(dep) 51 list(REMOVE_DUPLICATES object_files) 52 set(${result} ${object_files} PARENT_SCOPE) 53 list(REMOVE_DUPLICATES skipped_list) 54 set(${skipped_entrypoints_list} ${skipped_list} PARENT_SCOPE) 55endfunction(get_object_files_for_test) 56 57# Rule to add a libc unittest. 58# Usage 59# add_libc_unittest( 60# <target name> 61# SUITE <name of the suite this test belongs to> 62# SRCS <list of .cpp files for the test> 63# HDRS <list of .h files for the test> 64# DEPENDS <list of dependencies> 65# COMPILE_OPTIONS <list of special compile options for this target> 66# LINK_OPTIONS <list of special linking options for this target> 67# ) 68function(add_libc_unittest target_name) 69 if(NOT LLVM_INCLUDE_TESTS) 70 return() 71 endif() 72 73 cmake_parse_arguments( 74 "LIBC_UNITTEST" 75 "NO_RUN_POSTBUILD" # Optional arguments 76 "SUITE" # Single value arguments 77 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;LINK_OPTIONS" # Multi-value arguments 78 "NO_LIBC_UNITTEST_TEST_MAIN" 79 ${ARGN} 80 ) 81 if(NOT LIBC_UNITTEST_SRCS) 82 message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp " 83 "files.") 84 endif() 85 if(NOT LIBC_UNITTEST_DEPENDS) 86 message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of " 87 "'add_entrypoint_object' targets.") 88 endif() 89 90 get_fq_target_name(${target_name} fq_target_name) 91 get_fq_deps_list(fq_deps_list ${LIBC_UNITTEST_DEPENDS}) 92 get_object_files_for_test( 93 link_object_files skipped_entrypoints_list ${fq_deps_list}) 94 if(skipped_entrypoints_list) 95 # If a test is OS/target machine independent, it has to be skipped if the 96 # OS/target machine combination does not provide any dependent entrypoints. 97 # If a test is OS/target machine specific, then such a test will live is a 98 # OS/target machine specific directory and will be skipped at the directory 99 # level if required. 100 # 101 # There can potentially be a setup like this: A unittest is setup for a 102 # OS/target machine independent object library, which in turn depends on a 103 # machine specific object library. Such a test would be testing internals of 104 # the libc and it is assumed that they will be rare in practice. So, they 105 # can be skipped in the corresponding CMake files using platform specific 106 # logic. This pattern is followed in the loader tests for example. 107 # 108 # Another pattern that is present currently is to detect machine 109 # capabilities and add entrypoints and tests accordingly. That approach is 110 # much lower level approach and is independent of the kind of skipping that 111 # is happening here at the entrypoint level. 112 113 set(msg "Skipping unittest ${fq_target_name} as it has missing deps: " 114 "${skipped_entrypoints_list}.") 115 message(STATUS ${msg}) 116 return() 117 endif() 118 119 add_executable( 120 ${fq_target_name} 121 EXCLUDE_FROM_ALL 122 ${LIBC_UNITTEST_SRCS} 123 ${LIBC_UNITTEST_HDRS} 124 ) 125 target_include_directories( 126 ${fq_target_name} 127 PRIVATE 128 ${LIBC_SOURCE_DIR} 129 ${LIBC_BUILD_DIR} 130 ${LIBC_BUILD_DIR}/include 131 ) 132 target_compile_options( 133 ${fq_target_name} 134 PRIVATE ${LIBC_COMPILE_OPTIONS_DEFAULT} 135 ) 136 if(LIBC_UNITTEST_COMPILE_OPTIONS) 137 target_compile_options( 138 ${fq_target_name} 139 PRIVATE ${LIBC_UNITTEST_COMPILE_OPTIONS} 140 ) 141 endif() 142 143 target_link_libraries(${fq_target_name} PRIVATE ${link_object_files}) 144 if(LIBC_UNITTEST_LINK_OPTIONS) 145 target_link_options( 146 ${fq_target_name} 147 PRIVATE ${LIBC_UNITTEST_LINK_OPTIONS} 148 ) 149 endif() 150 151 set_target_properties(${fq_target_name} 152 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 153 154 add_dependencies( 155 ${fq_target_name} 156 ${fq_deps_list} 157 ) 158 159 if(NO_LIBC_UNITTEST_TEST_MAIN) 160 target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest libc_test_utils) 161 else() 162 target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest LibcUnitTestMain libc_test_utils) 163 endif() 164 165 if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD) 166 add_custom_command( 167 TARGET ${fq_target_name} 168 POST_BUILD 169 COMMAND $<TARGET_FILE:${fq_target_name}> 170 ) 171 endif() 172 173 if(LIBC_UNITTEST_SUITE) 174 add_dependencies( 175 ${LIBC_UNITTEST_SUITE} 176 ${fq_target_name} 177 ) 178 endif() 179endfunction(add_libc_unittest) 180 181function(add_libc_testsuite suite_name) 182 add_custom_target(${suite_name}) 183 add_dependencies(check-llvmlibc ${suite_name}) 184endfunction(add_libc_testsuite) 185 186function(add_libc_exhaustive_testsuite suite_name) 187 add_custom_target(${suite_name}) 188 add_dependencies(exhaustive-check-libc ${suite_name}) 189endfunction(add_libc_exhaustive_testsuite) 190 191function(add_libc_long_running_testsuite suite_name) 192 add_custom_target(${suite_name}) 193 add_dependencies(libc-long-running-tests ${suite_name}) 194endfunction(add_libc_long_running_testsuite) 195 196# Rule to add a fuzzer test. 197# Usage 198# add_libc_fuzzer( 199# <target name> 200# SRCS <list of .cpp files for the test> 201# HDRS <list of .h files for the test> 202# DEPENDS <list of dependencies> 203# ) 204function(add_libc_fuzzer target_name) 205 cmake_parse_arguments( 206 "LIBC_FUZZER" 207 "" # No optional arguments 208 "" # Single value arguments 209 "SRCS;HDRS;DEPENDS" # Multi-value arguments 210 ${ARGN} 211 ) 212 if(NOT LIBC_FUZZER_SRCS) 213 message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp " 214 "files.") 215 endif() 216 if(NOT LIBC_FUZZER_DEPENDS) 217 message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of " 218 "'add_entrypoint_object' targets.") 219 endif() 220 221 get_fq_target_name(${target_name} fq_target_name) 222 get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS}) 223 get_object_files_for_test( 224 link_object_files skipped_entrypoints_list ${fq_deps_list}) 225 if(skipped_entrypoints_list) 226 set(msg "Skipping fuzzer target ${fq_target_name} as it has missing deps: " 227 "${skipped_entrypoints_list}.") 228 message(STATUS ${msg}) 229 add_custom_target(${fq_target_name}) 230 231 # A post build custom command is used to avoid running the command always. 232 add_custom_command( 233 TARGET ${fq_target_name} 234 POST_BUILD 235 COMMAND ${CMAKE_COMMAND} -E echo ${msg} 236 ) 237 return() 238 endif() 239 240 add_executable( 241 ${fq_target_name} 242 EXCLUDE_FROM_ALL 243 ${LIBC_FUZZER_SRCS} 244 ${LIBC_FUZZER_HDRS} 245 ) 246 target_include_directories( 247 ${fq_target_name} 248 PRIVATE 249 ${LIBC_SOURCE_DIR} 250 ${LIBC_BUILD_DIR} 251 ${LIBC_BUILD_DIR}/include 252 ) 253 254 target_link_libraries(${fq_target_name} PRIVATE ${link_object_files}) 255 256 set_target_properties(${fq_target_name} 257 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 258 259 add_dependencies( 260 ${fq_target_name} 261 ${fq_deps_list} 262 ) 263 add_dependencies(libc-fuzzer ${fq_target_name}) 264endfunction(add_libc_fuzzer) 265