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;CXX_STANDARD" # 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 if(LIBC_UNITTEST_CXX_STANDARD) 143 set_target_properties( 144 ${fq_target_name} 145 PROPERTIES 146 CXX_STANDARD ${LIBC_UNITTEST_CXX_STANDARD} 147 ) 148 endif() 149 150 target_link_libraries(${fq_target_name} PRIVATE ${link_object_files}) 151 if(LIBC_UNITTEST_LINK_OPTIONS) 152 target_link_options( 153 ${fq_target_name} 154 PRIVATE ${LIBC_UNITTEST_LINK_OPTIONS} 155 ) 156 endif() 157 158 set_target_properties(${fq_target_name} 159 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 160 161 add_dependencies( 162 ${fq_target_name} 163 ${fq_deps_list} 164 ) 165 166 if(NO_LIBC_UNITTEST_TEST_MAIN) 167 target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest libc_test_utils) 168 else() 169 target_link_libraries(${fq_target_name} PRIVATE LibcUnitTest LibcUnitTestMain libc_test_utils) 170 endif() 171 172 if(NOT LIBC_UNITTEST_NO_RUN_POSTBUILD) 173 add_custom_command( 174 TARGET ${fq_target_name} 175 POST_BUILD 176 COMMAND $<TARGET_FILE:${fq_target_name}> 177 ) 178 endif() 179 180 if(LIBC_UNITTEST_SUITE) 181 add_dependencies( 182 ${LIBC_UNITTEST_SUITE} 183 ${fq_target_name} 184 ) 185 endif() 186endfunction(add_libc_unittest) 187 188function(add_libc_testsuite suite_name) 189 add_custom_target(${suite_name}) 190 add_dependencies(check-llvmlibc ${suite_name}) 191endfunction(add_libc_testsuite) 192 193function(add_libc_exhaustive_testsuite suite_name) 194 add_custom_target(${suite_name}) 195 add_dependencies(exhaustive-check-libc ${suite_name}) 196endfunction(add_libc_exhaustive_testsuite) 197 198function(add_libc_long_running_testsuite suite_name) 199 add_custom_target(${suite_name}) 200 add_dependencies(libc-long-running-tests ${suite_name}) 201endfunction(add_libc_long_running_testsuite) 202 203# Rule to add a fuzzer test. 204# Usage 205# add_libc_fuzzer( 206# <target name> 207# SRCS <list of .cpp files for the test> 208# HDRS <list of .h files for the test> 209# DEPENDS <list of dependencies> 210# ) 211function(add_libc_fuzzer target_name) 212 cmake_parse_arguments( 213 "LIBC_FUZZER" 214 "" # No optional arguments 215 "" # Single value arguments 216 "SRCS;HDRS;DEPENDS" # Multi-value arguments 217 ${ARGN} 218 ) 219 if(NOT LIBC_FUZZER_SRCS) 220 message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp " 221 "files.") 222 endif() 223 if(NOT LIBC_FUZZER_DEPENDS) 224 message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of " 225 "'add_entrypoint_object' targets.") 226 endif() 227 228 get_fq_target_name(${target_name} fq_target_name) 229 get_fq_deps_list(fq_deps_list ${LIBC_FUZZER_DEPENDS}) 230 get_object_files_for_test( 231 link_object_files skipped_entrypoints_list ${fq_deps_list}) 232 if(skipped_entrypoints_list) 233 set(msg "Skipping fuzzer target ${fq_target_name} as it has missing deps: " 234 "${skipped_entrypoints_list}.") 235 message(STATUS ${msg}) 236 add_custom_target(${fq_target_name}) 237 238 # A post build custom command is used to avoid running the command always. 239 add_custom_command( 240 TARGET ${fq_target_name} 241 POST_BUILD 242 COMMAND ${CMAKE_COMMAND} -E echo ${msg} 243 ) 244 return() 245 endif() 246 247 add_executable( 248 ${fq_target_name} 249 EXCLUDE_FROM_ALL 250 ${LIBC_FUZZER_SRCS} 251 ${LIBC_FUZZER_HDRS} 252 ) 253 target_include_directories( 254 ${fq_target_name} 255 PRIVATE 256 ${LIBC_SOURCE_DIR} 257 ${LIBC_BUILD_DIR} 258 ${LIBC_BUILD_DIR}/include 259 ) 260 261 target_link_libraries(${fq_target_name} PRIVATE ${link_object_files}) 262 263 set_target_properties(${fq_target_name} 264 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 265 266 add_dependencies( 267 ${fq_target_name} 268 ${fq_deps_list} 269 ) 270 add_dependencies(libc-fuzzer ${fq_target_name}) 271endfunction(add_libc_fuzzer) 272