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