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} 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 set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__") 210 211 add_custom_command( 212 OUTPUT ${lint_timestamp} 213 # --quiet is used to surpress warning statistics from clang-tidy like: 214 # Suppressed X warnings (X in non-user code). 215 # There seems to be a bug in clang-tidy where by even with --quiet some 216 # messages from clang's own diagnostics engine leak through: 217 # X warnings generated. 218 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress 219 # these. 220 COMMAND $<TARGET_FILE:clang-tidy> "--extra-arg=-fno-caret-diagnostics" --quiet 221 # Path to directory containing compile_commands.json 222 -p ${PROJECT_BINARY_DIR} 223 ${ADD_ENTRYPOINT_OBJ_SRCS} 224 # We have two options for running commands, add_custom_command and 225 # add_custom_target. We don't want to run the linter unless source files 226 # have changed. add_custom_target explicitly runs everytime therefore we 227 # use add_custom_command. This function requires an output file and since 228 # linting doesn't produce a file, we create a dummy file using a 229 # crossplatform touch. 230 COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp} 231 COMMENT "Linting... ${target_name}" 232 DEPENDS ${clang-tidy} ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS} 233 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 234 ) 235 236 add_custom_target(${fq_target_name}.__lint__ 237 DEPENDS ${lint_timestamp}) 238 add_dependencies(lint-libc ${fq_target_name}.__lint__) 239 add_dependencies(${fq_target_name} ${fq_target_name}.__lint__) 240 endif() 241 242endfunction(add_entrypoint_object) 243 244# Rule build a redirector object file. 245function(add_redirector_object target_name) 246 cmake_parse_arguments( 247 "REDIRECTOR_OBJECT" 248 "" # No optional arguments 249 "SRC" # The cpp file in which the redirector is defined. 250 "" # No multivalue arguments 251 ${ARGN} 252 ) 253 if(NOT REDIRECTOR_OBJECT_SRC) 254 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.") 255 endif() 256 257 add_library( 258 ${target_name} 259 OBJECT 260 ${REDIRECTOR_OBJECT_SRC} 261 ) 262 target_compile_options( 263 ${target_name} 264 BEFORE PRIVATE -fPIC 265 ) 266endfunction(add_redirector_object) 267