1set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY") 2 3function(_get_common_compile_options output_var) 4 set(compile_options ${LLVM_CXX_STD_default} ${LIBC_COMPILE_OPTIONS_DEFAULT} ${ARGN}) 5 if(NOT ${LIBC_TARGET_OS} STREQUAL "windows") 6 set(compile_options ${compile_options} -fpie -ffreestanding) 7 endif() 8 if(LLVM_COMPILER_IS_GCC_COMPATIBLE) 9 list(APPEND compile_options "-fno-exceptions") 10 list(APPEND compile_options "-fno-unwind-tables") 11 list(APPEND compile_options "-fno-asynchronous-unwind-tables") 12 list(APPEND compile_options "-fno-rtti") 13 elseif(MSVC) 14 list(APPEND compile_options "/EHs-c-") 15 list(APPEND compile_options "/GR-") 16 endif() 17 set(${output_var} ${compile_options} PARENT_SCOPE) 18endfunction() 19 20# Rule which is essentially a wrapper over add_library to compile a set of 21# sources to object files. 22# Usage: 23# add_object_library( 24# <target_name> 25# HDRS <list of header files> 26# SRCS <list of source files> 27# DEPENDS <list of dependencies> 28# COMPILE_OPTIONS <optional list of special compile options for this target> 29function(add_object_library target_name) 30 cmake_parse_arguments( 31 "ADD_OBJECT" 32 "" # No optional arguments 33 "CXX_STANDARD" # Single value arguments 34 "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments 35 ${ARGN} 36 ) 37 38 if(NOT ADD_OBJECT_SRCS) 39 message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.") 40 endif() 41 42 get_fq_target_name(${target_name} fq_target_name) 43 add_library( 44 ${fq_target_name} 45 EXCLUDE_FROM_ALL 46 OBJECT 47 ${ADD_OBJECT_SRCS} 48 ${ADD_OBJECT_HDRS} 49 ) 50 target_include_directories( 51 ${fq_target_name} 52 PRIVATE 53 ${LIBC_BUILD_DIR}/include 54 ${LIBC_SOURCE_DIR} 55 ${LIBC_BUILD_DIR} 56 ) 57 _get_common_compile_options(compile_options ${ADD_OBJECT_COMPILE_OPTIONS}) 58 target_compile_options(${fq_target_name} PRIVATE ${compile_options}) 59 60 get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS}) 61 if(fq_deps_list) 62 add_dependencies(${fq_target_name} ${fq_deps_list}) 63 endif() 64 65 if(ADD_OBJECT_CXX_STANDARD) 66 set_target_properties( 67 ${fq_target_name} 68 PROPERTIES 69 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD} 70 ) 71 endif() 72 73 set_target_properties( 74 ${fq_target_name} 75 PROPERTIES 76 "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE} 77 "OBJECT_FILES" "$<TARGET_OBJECTS:${fq_target_name}>" 78 "DEPS" "${fq_deps_list}" 79 ) 80endfunction(add_object_library) 81 82set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ") 83 84# A rule for entrypoint object targets. 85# Usage: 86# add_entrypoint_object( 87# <target_name> 88# [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias. 89# [NAME] <the C name of the entrypoint if different from target_name> 90# SRCS <list of .cpp files> 91# HDRS <list of .h files> 92# DEPENDS <list of dependencies> 93# COMPILE_OPTIONS <optional list of special compile options for this target> 94# SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`> 95# ) 96function(add_entrypoint_object target_name) 97 cmake_parse_arguments( 98 "ADD_ENTRYPOINT_OBJ" 99 "ALIAS;REDIRECTED" # Optional argument 100 "NAME;CXX_STANDARD" # Single value arguments 101 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi value arguments 102 ${ARGN} 103 ) 104 105 get_fq_target_name(${target_name} fq_target_name) 106 set(entrypoint_name ${target_name}) 107 if(ADD_ENTRYPOINT_OBJ_NAME) 108 set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME}) 109 endif() 110 111 list(FIND TARGET_ENTRYPOINT_NAME_LIST ${entrypoint_name} entrypoint_name_index) 112 if(${entrypoint_name_index} EQUAL -1) 113 add_custom_target(${fq_target_name}) 114 set_target_properties( 115 ${fq_target_name} 116 PROPERTIES 117 "ENTRYPOINT_NAME" ${entrypoint_name} 118 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} 119 "OBJECT_FILE" "" 120 "OBJECT_FILE_RAW" "" 121 "DEPS" "" 122 "SKIPPED" "YES" 123 ) 124 message(STATUS "Skipping libc entrypoint ${fq_target_name}.") 125 return() 126 endif() 127 128 if(ADD_ENTRYPOINT_OBJ_ALIAS) 129 # Alias targets help one add aliases to other entrypoint object targets. 130 # One can use alias targets setup OS/machine independent entrypoint targets. 131 list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size) 132 if(NOT (${deps_size} EQUAL "1")) 133 message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.") 134 endif() 135 list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target) 136 get_fq_dep_name(fq_dep_name ${dep_target}) 137 if(NOT TARGET ${fq_dep_name}) 138 message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; " 139 "Target ${target_name} will be ignored.") 140 return() 141 endif() 142 143 get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE") 144 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))) 145 message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.") 146 endif() 147 148 add_custom_target(${fq_target_name}) 149 add_dependencies(${fq_target_name} ${fq_dep_name}) 150 get_target_property(object_file ${fq_dep_name} "OBJECT_FILE") 151 get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW") 152 set_target_properties( 153 ${fq_target_name} 154 PROPERTIES 155 "ENTRYPOINT_NAME" ${entrypoint_name} 156 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} 157 "IS_ALIAS" "YES" 158 "OBJECT_FILE" "" 159 "OBJECT_FILE_RAW" "" 160 "DEPS" "${fq_dep_name}" 161 ) 162 return() 163 endif() 164 165 if(NOT ADD_ENTRYPOINT_OBJ_SRCS) 166 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.") 167 endif() 168 if(NOT ADD_ENTRYPOINT_OBJ_HDRS) 169 message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.") 170 endif() 171 172 _get_common_compile_options(common_compile_options ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}) 173 set(internal_target_name ${fq_target_name}.__internal__) 174 set(include_dirs ${LIBC_BUILD_DIR}/include ${LIBC_SOURCE_DIR} ${LIBC_BUILD_DIR}) 175 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS}) 176 set(full_deps_list ${fq_deps_list} libc.src.__support.common) 177 178 add_library( 179 ${internal_target_name} 180 # TODO: We don't need an object library for internal consumption. 181 # A future change should switch this to a normal static library. 182 EXCLUDE_FROM_ALL 183 OBJECT 184 ${ADD_ENTRYPOINT_OBJ_SRCS} 185 ${ADD_ENTRYPOINT_OBJ_HDRS} 186 ) 187 target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options}) 188 target_include_directories(${internal_target_name} PRIVATE ${include_dirs}) 189 add_dependencies(${internal_target_name} ${full_deps_list}) 190 191 add_library( 192 ${fq_target_name} 193 # We want an object library as the objects will eventually get packaged into 194 # an archive (like libc.a). 195 EXCLUDE_FROM_ALL 196 OBJECT 197 ${ADD_ENTRYPOINT_OBJ_SRCS} 198 ${ADD_ENTRYPOINT_OBJ_HDRS} 199 ) 200 target_compile_options(${fq_target_name} BEFORE PRIVATE ${common_compile_options} -DLLVM_LIBC_PUBLIC_PACKAGING) 201 target_include_directories(${fq_target_name} PRIVATE ${include_dirs}) 202 add_dependencies(${fq_target_name} ${full_deps_list}) 203 204 if(ADD_ENTRYPOINT_OBJ_CXX_STANDARD) 205 set_target_properties( 206 ${fq_target_name} ${internal_target_name} 207 PROPERTIES 208 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD} 209 ) 210 endif() 211 212 set_target_properties( 213 ${fq_target_name} 214 PROPERTIES 215 "ENTRYPOINT_NAME" ${entrypoint_name} 216 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} 217 "OBJECT_FILE" $<TARGET_OBJECTS:${fq_target_name}> 218 # TODO: We don't need to list internal object files if the internal 219 # target is a normal static library. 220 "OBJECT_FILE_RAW" $<TARGET_OBJECTS:${internal_target_name}> 221 "DEPS" "${fq_deps_list}" 222 ) 223 224 if(LLVM_LIBC_ENABLE_LINTING) 225 if(NOT LLVM_LIBC_CLANG_TIDY) 226 message(FATAL_ERROR "Something is wrong! LLVM_LIBC_ENABLE_LINTING is " 227 "ON but LLVM_LIBC_CLANG_TIDY is not set.") 228 endif() 229 230 # We only want a second invocation of clang-tidy to run 231 # restrict-system-libc-headers if the compiler-resource-dir was set in 232 # order to prevent false-positives due to a mismatch between the host 233 # compiler and the compiled clang-tidy. 234 if(COMPILER_RESOURCE_DIR) 235 # We run restrict-system-libc-headers with --system-headers to prevent 236 # transitive inclusion through compler provided headers. 237 set(restrict_system_headers_check_invocation 238 COMMAND ${LLVM_LIBC_CLANG_TIDY} --system-headers 239 --checks="-*,llvmlibc-restrict-system-libc-headers" 240 # We explicitly set the resource dir here to match the 241 # resource dir of the host compiler. 242 "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}" 243 --quiet 244 -p ${PROJECT_BINARY_DIR} 245 ${ADD_ENTRYPOINT_OBJ_SRCS} 246 ) 247 else() 248 set(restrict_system_headers_check_invocation 249 COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped") 250 endif() 251 252 set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__") 253 add_custom_command( 254 OUTPUT ${lint_timestamp} 255 # --quiet is used to surpress warning statistics from clang-tidy like: 256 # Suppressed X warnings (X in non-user code). 257 # There seems to be a bug in clang-tidy where by even with --quiet some 258 # messages from clang's own diagnostics engine leak through: 259 # X warnings generated. 260 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress 261 # these. 262 COMMAND ${LLVM_LIBC_CLANG_TIDY} 263 "--extra-arg=-fno-caret-diagnostics" --quiet 264 # Path to directory containing compile_commands.json 265 -p ${PROJECT_BINARY_DIR} 266 ${ADD_ENTRYPOINT_OBJ_SRCS} 267 # See above: this might be a second invocation of clang-tidy depending on 268 # the conditions above. 269 ${restrict_system_headers_check_invocation} 270 # We have two options for running commands, add_custom_command and 271 # add_custom_target. We don't want to run the linter unless source files 272 # have changed. add_custom_target explicitly runs everytime therefore we 273 # use add_custom_command. This function requires an output file and since 274 # linting doesn't produce a file, we create a dummy file using a 275 # crossplatform touch. 276 COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp} 277 COMMENT "Linting... ${target_name}" 278 DEPENDS clang-tidy ${internal_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} 279 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 280 ) 281 endif() 282 283endfunction(add_entrypoint_object) 284 285set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT") 286 287# A rule for external entrypoint targets. 288# Usage: 289# add_entrypoint_external( 290# <target_name> 291# DEPENDS <list of dependencies> 292# ) 293function(add_entrypoint_external target_name) 294 cmake_parse_arguments( 295 "ADD_ENTRYPOINT_EXT" 296 "" # No optional arguments 297 "" # No single value arguments 298 "DEPENDS" # Multi value arguments 299 ${ARGN} 300 ) 301 get_fq_target_name(${target_name} fq_target_name) 302 set(entrypoint_name ${target_name}) 303 304 add_custom_target(${fq_target_name}) 305 set_target_properties( 306 ${fq_target_name} 307 PROPERTIES 308 "ENTRYPOINT_NAME" ${entrypoint_name} 309 "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE} 310 "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}" 311 ) 312 313endfunction(add_entrypoint_external) 314 315# Rule build a redirector object file. 316function(add_redirector_object target_name) 317 cmake_parse_arguments( 318 "REDIRECTOR_OBJECT" 319 "" # No optional arguments 320 "SRC" # The cpp file in which the redirector is defined. 321 "" # No multivalue arguments 322 ${ARGN} 323 ) 324 if(NOT REDIRECTOR_OBJECT_SRC) 325 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.") 326 endif() 327 328 add_library( 329 ${target_name} 330 EXCLUDE_FROM_ALL 331 OBJECT 332 ${REDIRECTOR_OBJECT_SRC} 333 ) 334 target_compile_options( 335 ${target_name} 336 BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT} 337 ) 338endfunction(add_redirector_object) 339