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