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 85 if(ADD_ENTRYPOINT_OBJ_ALIAS) 86 # Alias targets help one add aliases to other entrypoint object targets. 87 # One can use alias targets setup OS/machine independent entrypoint targets. 88 list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size) 89 if(NOT (${deps_size} EQUAL "1")) 90 message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.") 91 endif() 92 list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target) 93 get_fq_dep_name(fq_dep_name ${dep_target}) 94 if(NOT TARGET ${fq_dep_name}) 95 message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; " 96 "Target ${target_name} will be ignored.") 97 return() 98 endif() 99 100 get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE") 101 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}))) 102 message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.") 103 endif() 104 105 add_custom_target(${fq_target_name}) 106 add_dependencies(${fq_target_name} ${fq_dep_name}) 107 get_target_property(object_file ${fq_dep_name} "OBJECT_FILE") 108 get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW") 109 set_target_properties( 110 ${fq_target_name} 111 PROPERTIES 112 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} 113 "IS_ALIAS" "YES" 114 "OBJECT_FILE" "" 115 "OBJECT_FILE_RAW" "" 116 "DEPS" "${fq_dep_name}" 117 ) 118 return() 119 endif() 120 121 if(NOT ADD_ENTRYPOINT_OBJ_SRCS) 122 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.") 123 endif() 124 if(NOT ADD_ENTRYPOINT_OBJ_HDRS) 125 message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.") 126 endif() 127 128 set(entrypoint_name ${target_name}) 129 if(ADD_ENTRYPOINT_OBJ_NAME) 130 set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME}) 131 endif() 132 133 set(objects_target_name "${fq_target_name}_objects") 134 135 add_library( 136 ${objects_target_name} 137 # We want an object library as the objects will eventually get packaged into 138 # an archive (like libc.a). 139 OBJECT 140 ${ADD_ENTRYPOINT_OBJ_SRCS} 141 ${ADD_ENTRYPOINT_OBJ_HDRS} 142 ) 143 target_compile_options( 144 ${objects_target_name} 145 BEFORE 146 PRIVATE 147 -fpie ${LLVM_CXX_STD_default} -ffreestanding 148 ) 149 target_include_directories( 150 ${objects_target_name} 151 PRIVATE 152 ${LIBC_BUILD_DIR}/include 153 ${LIBC_SOURCE_DIR} 154 ${LIBC_BUILD_DIR} 155 ) 156 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS}) 157 add_dependencies( 158 ${objects_target_name} 159 libc.src.__support.common 160 ${fq_deps_list} 161 ) 162 163 if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS) 164 target_compile_options( 165 ${objects_target_name} 166 PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS} 167 ) 168 endif() 169 170 set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o") 171 set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o") 172 173 set(input_objects $<TARGET_OBJECTS:${objects_target_name}>) 174 add_custom_command( 175 OUTPUT ${object_file_raw} 176 DEPENDS ${input_objects} 177 COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw} 178 ) 179 180 set(alias_attributes "0,function,global") 181 if(ADD_ENTRYPOINT_OBJ_REDIRECTED) 182 set(alias_attributes "${alias_attributes},hidden") 183 endif() 184 185 add_custom_command( 186 OUTPUT ${object_file} 187 # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag. 188 DEPENDS ${object_file_raw} ${llvm-objcopy} 189 COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol 190 "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}" 191 ${object_file_raw} ${object_file} 192 ) 193 194 add_custom_target( 195 ${fq_target_name} 196 ALL 197 DEPENDS ${object_file} 198 ) 199 set_target_properties( 200 ${fq_target_name} 201 PROPERTIES 202 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} 203 "OBJECT_FILE" "${object_file}" 204 "OBJECT_FILE_RAW" "${object_file_raw}" 205 "DEPS" "${fq_deps_list}" 206 ) 207 208 if(LLVM_LIBC_ENABLE_LINTING) 209 210 # We only want a second invocation of clang-tidy to run 211 # restrict-system-libc-headers if the compiler-resource-dir was set in 212 # order to prevent false-positives due to a mismatch between the host 213 # compiler and the compiled clang-tidy. 214 if(COMPILER_RESOURCE_DIR) 215 # We run restrict-system-libc-headers with --system-headers to prevent 216 # transitive inclusion through compler provided headers. 217 set(restrict_system_headers_check_invocation 218 COMMAND $<TARGET_FILE:clang-tidy> --system-headers 219 --checks="-*,llvmlibc-restrict-system-libc-headers" 220 # We explicitly set the resource dir here to match the 221 # resource dir of the host compiler. 222 "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}" 223 --quiet 224 -p ${PROJECT_BINARY_DIR} 225 ${ADD_ENTRYPOINT_OBJ_SRCS} 226 ) 227 else() 228 set(restrict_system_headers_check_invocation 229 COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped") 230 endif() 231 232 set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__") 233 add_custom_command( 234 OUTPUT ${lint_timestamp} 235 # --quiet is used to surpress warning statistics from clang-tidy like: 236 # Suppressed X warnings (X in non-user code). 237 # There seems to be a bug in clang-tidy where by even with --quiet some 238 # messages from clang's own diagnostics engine leak through: 239 # X warnings generated. 240 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress 241 # these. 242 COMMAND $<TARGET_FILE:clang-tidy> 243 "--extra-arg=-fno-caret-diagnostics" --quiet 244 # Path to directory containing compile_commands.json 245 -p ${PROJECT_BINARY_DIR} 246 ${ADD_ENTRYPOINT_OBJ_SRCS} 247 # See above: this might be a second invocation of clang-tidy depending on 248 # the conditions above. 249 ${restrict_system_headers_check_invocation} 250 # We have two options for running commands, add_custom_command and 251 # add_custom_target. We don't want to run the linter unless source files 252 # have changed. add_custom_target explicitly runs everytime therefore we 253 # use add_custom_command. This function requires an output file and since 254 # linting doesn't produce a file, we create a dummy file using a 255 # crossplatform touch. 256 COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp} 257 COMMENT "Linting... ${target_name}" 258 DEPENDS ${clang-tidy} ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} 259 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 260 ) 261 262 add_custom_target(${fq_target_name}.__lint__ 263 DEPENDS ${lint_timestamp}) 264 add_dependencies(lint-libc ${fq_target_name}.__lint__) 265 add_dependencies(${fq_target_name} ${fq_target_name}.__lint__) 266 endif() 267 268endfunction(add_entrypoint_object) 269 270# Rule build a redirector object file. 271function(add_redirector_object target_name) 272 cmake_parse_arguments( 273 "REDIRECTOR_OBJECT" 274 "" # No optional arguments 275 "SRC" # The cpp file in which the redirector is defined. 276 "" # No multivalue arguments 277 ${ARGN} 278 ) 279 if(NOT REDIRECTOR_OBJECT_SRC) 280 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.") 281 endif() 282 283 add_library( 284 ${target_name} 285 OBJECT 286 ${REDIRECTOR_OBJECT_SRC} 287 ) 288 target_compile_options( 289 ${target_name} 290 BEFORE PRIVATE -fPIC 291 ) 292endfunction(add_redirector_object) 293