1 set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
3 # Rule which is essentially a wrapper over add_library to compile a set of
4 # sources to object files.
8 # HDRS <list of header files>
9 # SRCS <list of source files>
10 # [ALIAS] <If this object library is an alias for another object library.>
11 # DEPENDS <list of dependencies; Should be a single item for ALIAS libraries>
12 # COMPILE_OPTIONS <optional list of special compile options for this target>
13 # FLAGS <optional list of flags>
14 function(create_object_library fq_target_name)
15 cmake_parse_arguments(
17 "ALIAS;NO_GPU_BUNDLE" # optional arguments
18 "CXX_STANDARD" # Single value arguments
19 "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments
23 get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
26 if(ADD_OBJECT_SRCS OR ADD_OBJECT_HDRS)
28 "${fq_target_name}: object library alias cannot have SRCS and/or HDRS.")
30 list(LENGTH fq_deps_list depends_size)
31 if(NOT ${depends_size} EQUAL 1)
33 "${fq_targe_name}: object library alias should have exactly one DEPENDS.")
43 if(NOT ADD_OBJECT_SRCS)
44 message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
47 if(NOT ADD_OBJECT_CXX_STANDARD)
48 set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
51 set(internal_target_name ${fq_target_name}.__internal__)
52 set(public_packaging_for_internal "-DLIBC_COPT_PUBLIC_PACKAGING")
54 _get_common_compile_options(compile_options "${ADD_OBJECT_FLAGS}")
55 list(APPEND compile_options ${ADD_OBJECT_COMPILE_OPTIONS})
64 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
65 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
66 target_compile_options(${fq_target_name} PRIVATE ${compile_options})
68 if(SHOW_INTERMEDIATE_OBJECTS)
69 message(STATUS "Adding object library ${fq_target_name}")
70 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
71 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
72 message(STATUS " ${fq_target_name} depends on ${dep}")
77 list(APPEND fq_deps_list libc.src.__support.macros.config)
78 list(REMOVE_DUPLICATES fq_deps_list)
79 add_dependencies(${fq_target_name} ${fq_deps_list})
80 # Add deps as link libraries to inherit interface compile and link options.
81 target_link_libraries(${fq_target_name} PUBLIC ${fq_deps_list})
83 set_target_properties(
86 TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE}
87 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
88 DEPS "${fq_deps_list}"
89 FLAGS "${ADD_OBJECT_FLAGS}"
92 # If we built a separate internal target we want to use those target objects
93 # for testing instead of the exported target.
94 set(target_objects ${fq_target_name})
95 if(TARGET ${internal_target_name})
96 set(target_objects ${internal_target_name})
99 set_target_properties(
102 OBJECT_FILES "$<TARGET_OBJECTS:${target_objects}>"
104 endfunction(create_object_library)
106 function(add_object_library target_name)
107 add_target_with_flags(
109 CREATE_TARGET create_object_library
111 endfunction(add_object_library)
113 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
114 set(ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE "ENTRYPOINT_OBJ_VENDOR")
116 # A rule for entrypoint object targets.
118 # add_entrypoint_object(
120 # [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
121 # [NAME] <the C name of the entrypoint if different from target_name>
122 # SRCS <list of .cpp files>
123 # HDRS <list of .h files>
124 # DEPENDS <list of dependencies>
125 # COMPILE_OPTIONS <optional list of special compile options for this target>
126 # SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
127 # FLAGS <optional list of flags>
129 function(create_entrypoint_object fq_target_name)
130 cmake_parse_arguments(
132 "ALIAS;REDIRECTED;VENDOR" # Optional argument
133 "NAME;CXX_STANDARD" # Single value arguments
134 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
138 set(entrypoint_target_type ${ENTRYPOINT_OBJ_TARGET_TYPE})
139 if(${ADD_ENTRYPOINT_OBJ_VENDOR})
140 # TODO: We currently rely on external definitions of certain math functions
141 # provided by GPU vendors like AMD or Nvidia. We need to mark these so we
142 # don't end up running tests on these. In the future all of these should be
143 # implemented and this can be removed.
144 set(entrypoint_target_type ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})
146 list(FIND TARGET_ENTRYPOINT_NAME_LIST ${ADD_ENTRYPOINT_OBJ_NAME} entrypoint_name_index)
147 if(${entrypoint_name_index} EQUAL -1)
148 add_custom_target(${fq_target_name})
149 set_target_properties(
152 "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME}
153 "TARGET_TYPE" ${entrypoint_target_type}
159 if(LIBC_CMAKE_VERBOSE_LOGGING)
160 message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
165 set(internal_target_name ${fq_target_name}.__internal__)
167 if(ADD_ENTRYPOINT_OBJ_ALIAS)
168 # Alias targets help one add aliases to other entrypoint object targets.
169 # One can use alias targets setup OS/machine independent entrypoint targets.
170 list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
171 if(NOT (${deps_size} EQUAL "1"))
172 message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
174 list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
175 get_fq_dep_name(fq_dep_name ${dep_target})
177 if(SHOW_INTERMEDIATE_OBJECTS)
178 message(STATUS "Adding entrypoint object ${fq_target_name} as an alias of"
182 if(NOT TARGET ${fq_dep_name})
183 message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
184 "Target ${target_name} will be ignored.")
188 get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
189 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR
190 ${obj_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})))
191 message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
194 get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
195 get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
197 # If the system cannot build the GPU tests we simply make a dummy target.
198 if(LIBC_TARGET_OS_IS_GPU AND LIBC_GPU_TESTS_DISABLED)
199 add_custom_target(${internal_target_name})
202 ${internal_target_name}
209 add_dependencies(${internal_target_name} ${fq_dep_name})
216 add_dependencies(${fq_target_name} ${fq_dep_name} ${internal_target_name})
217 set_target_properties(
220 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
221 TARGET_TYPE ${entrypoint_target_type}
225 DEPS "${fq_dep_name}"
226 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
231 if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
232 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
234 if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD)
235 set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
238 _get_common_compile_options(common_compile_options "${ADD_ENTRYPOINT_OBJ_FLAGS}")
239 list(APPEND common_compile_options ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS})
240 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
241 set(full_deps_list ${fq_deps_list} libc.src.__support.common)
243 if(SHOW_INTERMEDIATE_OBJECTS)
244 message(STATUS "Adding entrypoint object ${fq_target_name}")
245 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
246 foreach(dep IN LISTS ADD_ENTRYPOINT_OBJ_DEPENDS)
247 message(STATUS " ${fq_target_name} depends on ${dep}")
253 ${internal_target_name}
254 # TODO: We don't need an object library for internal consumption.
255 # A future change should switch this to a normal static library.
258 ${ADD_ENTRYPOINT_OBJ_SRCS}
259 ${ADD_ENTRYPOINT_OBJ_HDRS}
261 target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options})
262 target_include_directories(${internal_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
263 target_include_directories(${internal_target_name} PRIVATE ${LIBC_SOURCE_DIR})
264 add_dependencies(${internal_target_name} ${full_deps_list})
265 target_link_libraries(${internal_target_name} ${full_deps_list})
269 # We want an object library as the objects will eventually get packaged into
270 # an archive (like libc.a).
273 ${ADD_ENTRYPOINT_OBJ_SRCS}
274 ${ADD_ENTRYPOINT_OBJ_HDRS}
276 target_compile_options(${fq_target_name} BEFORE PRIVATE ${common_compile_options} -DLIBC_COPT_PUBLIC_PACKAGING)
277 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
278 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
279 add_dependencies(${fq_target_name} ${full_deps_list})
280 target_link_libraries(${fq_target_name} ${full_deps_list})
282 # Builtin recognition causes issues when trying to implement the builtin
283 # functions themselves. The GPU backends do not use libcalls so we disable the
284 # known problematic ones on the entrypoints that implement them.
285 if(LIBC_TARGET_OS_IS_GPU)
286 set(libc_builtins bcmp strlen memmem bzero memcmp memcpy memmem memmove
287 memset strcmp strstr)
288 if(${ADD_ENTRYPOINT_OBJ_NAME} IN_LIST libc_builtins)
289 target_compile_options(${fq_target_name} PRIVATE -fno-builtin-${ADD_ENTRYPOINT_OBJ_NAME})
293 set_target_properties(
296 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
297 TARGET_TYPE ${entrypoint_target_type}
298 OBJECT_FILE "$<TARGET_OBJECTS:${fq_target_name}>"
299 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
300 DEPS "${fq_deps_list}"
301 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
304 if(TARGET ${internal_target_name})
305 set_target_properties(
306 ${internal_target_name}
308 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
309 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
311 set_target_properties(
314 # TODO: We don't need to list internal object files if the internal
315 # target is a normal static library.
316 OBJECT_FILE_RAW "$<TARGET_OBJECTS:${internal_target_name}>"
320 if(LLVM_LIBC_ENABLE_LINTING AND TARGET ${internal_target_name})
321 if(NOT LLVM_LIBC_CLANG_TIDY)
322 message(FATAL_ERROR "Something is wrong! LLVM_LIBC_ENABLE_LINTING is "
323 "ON but LLVM_LIBC_CLANG_TIDY is not set.")
326 # We only want a second invocation of clang-tidy to run
327 # restrict-system-libc-headers if the compiler-resource-dir was set in
328 # order to prevent false-positives due to a mismatch between the host
329 # compiler and the compiled clang-tidy.
330 if(COMPILER_RESOURCE_DIR)
331 # We run restrict-system-libc-headers with --system-headers to prevent
332 # transitive inclusion through compler provided headers.
333 set(restrict_system_headers_check_invocation
334 COMMAND ${LLVM_LIBC_CLANG_TIDY} --system-headers
335 --checks="-*,llvmlibc-restrict-system-libc-headers"
336 # We explicitly set the resource dir here to match the
337 # resource dir of the host compiler.
338 "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
340 -p ${PROJECT_BINARY_DIR}
341 ${ADD_ENTRYPOINT_OBJ_SRCS}
344 set(restrict_system_headers_check_invocation
345 COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
349 ${fq_target_name}.__lint__
350 # --quiet is used to surpress warning statistics from clang-tidy like:
351 # Suppressed X warnings (X in non-user code).
352 # There seems to be a bug in clang-tidy where by even with --quiet some
353 # messages from clang's own diagnostics engine leak through:
354 # X warnings generated.
355 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
357 COMMAND ${LLVM_LIBC_CLANG_TIDY}
358 "--extra-arg=-fno-caret-diagnostics" --quiet
359 # Path to directory containing compile_commands.json
360 -p ${PROJECT_BINARY_DIR}
361 ${ADD_ENTRYPOINT_OBJ_SRCS}
362 # See above: this might be a second invocation of clang-tidy depending on
363 # the conditions above.
364 ${restrict_system_headers_check_invocation}
365 # We have two options for running commands, add_custom_command and
366 # add_custom_target. We don't want to run the linter unless source files
367 # have changed. add_custom_target explicitly runs everytime therefore we
368 # use add_custom_command. This function requires an output file and since
369 # linting doesn't produce a file, we create a dummy file using a
370 # crossplatform touch.
371 COMMENT "Linting... ${fq_target_name}"
372 DEPENDS ${internal_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
373 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
375 add_dependencies(libc-lint ${fq_target_name}.__lint__)
378 endfunction(create_entrypoint_object)
380 function(add_entrypoint_object target_name)
381 cmake_parse_arguments(
383 "" # Optional arguments
384 "NAME" # Single value arguments
385 "" # Multi-value arguments
389 if(NOT ADD_ENTRYPOINT_OBJ_NAME)
390 set(ADD_ENTRYPOINT_OBJ_NAME ${target_name})
393 add_target_with_flags(
395 NAME ${ADD_ENTRYPOINT_OBJ_NAME}
396 CREATE_TARGET create_entrypoint_object
397 ${ADD_ENTRYPOINT_OBJ_UNPARSED_ARGUMENTS}
399 endfunction(add_entrypoint_object)
401 set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT")
403 # A rule for external entrypoint targets.
405 # add_entrypoint_external(
407 # DEPENDS <list of dependencies>
409 function(add_entrypoint_external target_name)
410 cmake_parse_arguments(
412 "" # No optional arguments
413 "" # No single value arguments
414 "DEPENDS" # Multi value arguments
417 get_fq_target_name(${target_name} fq_target_name)
418 set(entrypoint_name ${target_name})
420 add_custom_target(${fq_target_name})
421 set_target_properties(
424 "ENTRYPOINT_NAME" ${entrypoint_name}
425 "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE}
426 "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}"
429 endfunction(add_entrypoint_external)
431 # Rule build a redirector object file.
432 function(add_redirector_object target_name)
433 cmake_parse_arguments(
435 "" # No optional arguments
436 "SRC" # The cpp file in which the redirector is defined.
437 "" # No multivalue arguments
440 if(NOT REDIRECTOR_OBJECT_SRC)
441 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
448 ${REDIRECTOR_OBJECT_SRC}
450 target_compile_options(
452 BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT}
454 endfunction(add_redirector_object)