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