1 set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
3 function(_get_common_compile_options output_var flags)
4 list(FIND flags ${FMA_OPT_FLAG} fma)
6 list(FIND flags "${FMA_OPT_FLAG}__ONLY" fma)
8 if((${fma} GREATER -1) AND (LIBC_TARGET_ARCHITECTURE_IS_RISCV64 OR
9 (LIBC_CPU_FEATURES MATCHES "FMA")))
10 set(ADD_FMA_FLAG TRUE)
13 list(FIND flags ${ROUND_OPT_FLAG} round)
15 list(FIND flags "${ROUND_OPT_FLAG}__ONLY" round)
17 if((${round} GREATER -1) AND (LIBC_CPU_FEATURES MATCHES "SSE4_2"))
18 set(ADD_SSE4_2_FLAG TRUE)
21 set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT} ${ARGN})
22 if(LLVM_COMPILER_IS_GCC_COMPATIBLE)
23 list(APPEND compile_options "-fpie")
24 list(APPEND compile_options "-ffreestanding")
25 list(APPEND compile_options "-fno-builtin")
26 list(APPEND compile_options "-fno-exceptions")
27 list(APPEND compile_options "-fno-lax-vector-conversions")
28 list(APPEND compile_options "-fno-unwind-tables")
29 list(APPEND compile_options "-fno-asynchronous-unwind-tables")
30 list(APPEND compile_options "-fno-rtti")
31 list(APPEND compile_options "-Wall")
32 list(APPEND compile_options "-Wextra")
33 list(APPEND compile_options "-Wimplicit-fallthrough")
34 list(APPEND compile_options "-Wwrite-strings")
35 list(APPEND compile_options "-Wextra-semi")
36 if(NOT CMAKE_COMPILER_IS_GNUCXX)
37 list(APPEND compile_options "-Wnewline-eof")
38 list(APPEND compile_options "-Wnonportable-system-include-path")
39 list(APPEND compile_options "-Wstrict-prototypes")
40 list(APPEND compile_options "-Wthread-safety")
43 if(LIBC_TARGET_ARCHITECTURE_IS_X86)
44 list(APPEND compile_options "-mavx2")
45 list(APPEND compile_options "-mfma")
46 elseif(LIBC_TARGET_ARCHITECTURE_IS_RISCV64)
47 list(APPEND compile_options "-D__LIBC_RISCV_USE_FMA")
51 list(APPEND compile_options "-msse4.2")
54 list(APPEND compile_options "/EHs-c-")
55 list(APPEND compile_options "/GR-")
57 list(APPEND compile_options "/arch:AVX2")
60 if (LIBC_TARGET_ARCHITECTURE_IS_GPU)
61 list(APPEND compile_options "-nogpulib")
62 list(APPEND compile_options "-fvisibility=hidden")
64 set(${output_var} ${compile_options} PARENT_SCOPE)
67 # Obtains NVPTX specific arguments for compilation.
68 # The PTX feature is primarily based on the CUDA toolchain version. We want to
69 # be able to target NVPTX without an existing CUDA installation, so we need to
70 # set this manually. This simply sets the PTX feature to the minimum required
71 # for the features we wish to use on that target. The minimum PTX features used
72 # here roughly corresponds to the CUDA 9.0 release.
73 # Adjust as needed for desired PTX features.
74 function(get_nvptx_compile_options output_var gpu_arch)
76 list(APPEND nvptx_options "-march=${gpu_arch}")
77 list(APPEND nvptx_options "-Wno-unknown-cuda-version")
78 if(${gpu_arch} STREQUAL "sm_35")
79 list(APPEND nvptx_options "--cuda-feature=+ptx60")
80 elseif(${gpu_arch} STREQUAL "sm_37")
81 list(APPEND nvptx_options "--cuda-feature=+ptx60")
82 elseif(${gpu_arch} STREQUAL "sm_50")
83 list(APPEND nvptx_options "--cuda-feature=+ptx60")
84 elseif(${gpu_arch} STREQUAL "sm_52")
85 list(APPEND nvptx_options "--cuda-feature=+ptx60")
86 elseif(${gpu_arch} STREQUAL "sm_53")
87 list(APPEND nvptx_options "--cuda-feature=+ptx63")
88 elseif(${gpu_arch} STREQUAL "sm_60")
89 list(APPEND nvptx_options "--cuda-feature=+ptx63")
90 elseif(${gpu_arch} STREQUAL "sm_61")
91 list(APPEND nvptx_options "--cuda-feature=+ptx63")
92 elseif(${gpu_arch} STREQUAL "sm_62")
93 list(APPEND nvptx_options "--cuda-feature=+ptx63")
94 elseif(${gpu_arch} STREQUAL "sm_70")
95 list(APPEND nvptx_options "--cuda-feature=+ptx63")
96 elseif(${gpu_arch} STREQUAL "sm_72")
97 list(APPEND nvptx_options "--cuda-feature=+ptx63")
98 elseif(${gpu_arch} STREQUAL "sm_75")
99 list(APPEND nvptx_options "--cuda-feature=+ptx63")
100 elseif(${gpu_arch} STREQUAL "sm_80")
101 list(APPEND nvptx_options "--cuda-feature=+ptx72")
102 elseif(${gpu_arch} STREQUAL "sm_86")
103 list(APPEND nvptx_options "--cuda-feature=+ptx72")
105 message(FATAL_ERROR "Unknown Nvidia GPU architecture '${gpu_arch}'")
109 list(APPEND nvptx_options "--cuda-path=${LIBC_CUDA_ROOT}")
111 set(${output_var} ${nvptx_options} PARENT_SCOPE)
114 # Builds the object target for the GPU.
115 # This compiles the target for all supported architectures and embeds it into
116 # host binary for installing. The internal target contains the GPU code directly
117 # compiled for a single architecture used internally.
119 # _build_gpu_objects(
121 # <internal_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 # FLAGS <optional list of flags>
128 function(_build_gpu_objects fq_target_name internal_target_name)
129 cmake_parse_arguments(
131 "" # No optional arguments
132 "NAME;CXX_STANDARD" # Single value arguments
133 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
137 set(include_dirs ${LIBC_BUILD_DIR}/include ${LIBC_SOURCE_DIR} ${LIBC_BUILD_DIR})
138 set(common_compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
139 if(NOT ADD_GPU_OBJ_CXX_STANDARD)
140 set(ADD_GPU_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
143 foreach(add_gpu_obj_src ${ADD_GPU_OBJ_SRCS})
144 # The packaged version will be built for every target GPU architecture. We do
145 # this so we can support multiple accelerators on the same machine.
146 foreach(gpu_arch ${LIBC_GPU_ARCHITECTURES})
147 get_filename_component(src_name ${add_gpu_obj_src} NAME)
148 set(gpu_target_name ${fq_target_name}.${src_name}.${gpu_arch})
149 set(compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
150 # Derive the triple from the specified architecture.
151 if("${gpu_arch}" IN_LIST all_amdgpu_architectures)
152 set(gpu_target_triple "amdgcn-amd-amdhsa")
153 list(APPEND compile_options "-mcpu=${gpu_arch}")
154 elseif("${gpu_arch}" IN_LIST all_nvptx_architectures)
155 set(gpu_target_triple "nvptx64-nvidia-cuda")
156 get_nvptx_compile_options(nvptx_options ${gpu_arch})
157 list(APPEND compile_options "${nvptx_options}")
159 message(FATAL_ERROR "Unknown GPU architecture '${gpu_arch}'")
161 list(APPEND compile_options "--target=${gpu_target_triple}")
162 list(APPEND compile_options "-emit-llvm")
164 # Build the library for this target architecture. We always emit LLVM-IR for
165 # packaged GPU binaries.
166 add_library(${gpu_target_name}
173 target_compile_options(${gpu_target_name} PRIVATE ${compile_options})
174 target_include_directories(${gpu_target_name} PRIVATE ${include_dirs})
175 target_compile_definitions(${gpu_target_name} PRIVATE LIBC_COPT_PUBLIC_PACKAGING)
176 set_target_properties(
179 CXX_STANDARD ${ADD_GPU_OBJ_CXX_STANDARD}
181 if(ADD_GPU_OBJ_DEPENDS)
182 add_dependencies(${gpu_target_name} ${ADD_GPU_OBJ_DEPENDS})
185 # Append this target to a list of images to package into a single binary.
186 set(input_file $<TARGET_OBJECTS:${gpu_target_name}>)
187 list(APPEND packager_images
188 --image=file=${input_file},arch=${gpu_arch},triple=${gpu_target_triple})
189 list(APPEND gpu_target_names ${gpu_target_name})
192 # After building the target for the desired GPUs we must package the output
193 # into a fatbinary, see https://clang.llvm.org/docs/OffloadingDesign.html for
195 set(packaged_target_name ${fq_target_name}.${src_name}.__gpu__)
196 set(packaged_output_name ${CMAKE_CURRENT_BINARY_DIR}/${fq_target_name}.${src_name}.gpubin)
198 add_custom_command(OUTPUT ${packaged_output_name}
199 COMMAND ${LIBC_CLANG_OFFLOAD_PACKAGER}
200 ${packager_images} -o ${packaged_output_name}
201 DEPENDS ${gpu_target_names} ${add_gpu_obj_src} ${ADD_GPU_OBJ_HDRS}
202 COMMENT "Packaging LLVM offloading binary")
203 add_custom_target(${packaged_target_name} DEPENDS ${packaged_output_name})
204 list(APPEND packaged_gpu_names ${packaged_target_name})
205 list(APPEND packaged_gpu_binaries ${packaged_output_name})
208 # We create an empty 'stub' file for the host to contain the embedded device
209 # code. This will be packaged into 'libcgpu.a'.
210 # TODO: In the future we will want to combine every architecture for a target
211 # into a single bitcode file and use that. For now we simply build for
212 # every single one and let the offloading linker handle it.
213 string(FIND ${fq_target_name} "." last_dot_loc REVERSE)
214 math(EXPR name_loc "${last_dot_loc} + 1")
215 string(SUBSTRING ${fq_target_name} ${name_loc} -1 target_name)
216 set(stub_filename "${target_name}.cpp")
218 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}"
219 COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/stubs/
220 COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}
221 DEPENDS ${gpu_target_names} ${ADD_GPU_OBJ_SRCS} ${ADD_GPU_OBJ_HDRS}
223 set(stub_target_name ${fq_target_name}.__stub__)
224 add_custom_target(${stub_target_name} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename})
228 # We want an object library as the objects will eventually get packaged into
229 # an archive (like libcgpu.a).
232 ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}
234 target_compile_options(${fq_target_name} BEFORE PRIVATE
235 ${common_compile_options} -nostdlib)
236 foreach(packaged_gpu_binary ${packaged_gpu_binaries})
237 target_compile_options(${fq_target_name} PRIVATE
238 "SHELL:-Xclang -fembed-offload-object=${packaged_gpu_binary}")
240 target_include_directories(${fq_target_name} PRIVATE ${include_dirs})
241 add_dependencies(${fq_target_name}
242 ${full_deps_list} ${packaged_gpu_names} ${stub_target_name})
244 # We only build the internal target for a single supported architecture.
245 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU OR
246 LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
248 ${internal_target_name}
254 target_compile_options(${internal_target_name} BEFORE PRIVATE
255 ${common_compile_options} --target=${LIBC_GPU_TARGET_TRIPLE})
256 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
257 target_compile_options(${internal_target_name} PRIVATE -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto)
258 elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
259 get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
260 target_compile_options(${internal_target_name} PRIVATE ${nvptx_options})
262 target_include_directories(${internal_target_name} PRIVATE ${include_dirs})
264 add_dependencies(${internal_target_name} ${full_deps_list})
269 # Rule which is essentially a wrapper over add_library to compile a set of
270 # sources to object files.
272 # add_object_library(
274 # HDRS <list of header files>
275 # SRCS <list of source files>
276 # [ALIAS] <If this object library is an alias for another object library.>
277 # DEPENDS <list of dependencies; Should be a single item for ALIAS libraries>
278 # COMPILE_OPTIONS <optional list of special compile options for this target>
279 # FLAGS <optional list of flags>
280 function(create_object_library fq_target_name)
281 cmake_parse_arguments(
283 "ALIAS;NO_GPU_BUNDLE" # optional arguments
284 "CXX_STANDARD" # Single value arguments
285 "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments
289 get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
292 if(ADD_OBJECT_SRCS OR ADD_OBJECT_HDRS)
294 "${fq_target_name}: object library alias cannot have SRCS and/or HDRS.")
296 list(LENGTH fq_deps_list depends_size)
297 if(NOT ${depends_size} EQUAL 1)
299 "${fq_targe_name}: object library alias should have exactly one DEPENDS.")
309 if(NOT ADD_OBJECT_SRCS)
310 message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
313 # The GPU build uses a separate internal file.
314 if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
315 set(internal_target_name ${fq_target_name}.__internal__)
317 set(internal_target_name ${fq_target_name})
320 _get_common_compile_options(
322 "${ADD_OBJECT_FLAGS}"
323 ${ADD_OBJECT_COMPILE_OPTIONS}
326 # GPU builds require special handling for the objects because we want to
327 # export several different targets at once, e.g. for both Nvidia and AMD.
328 if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
331 ${internal_target_name}
332 SRCS ${ADD_OBJECT_SRCS}
333 HDRS ${ADD_OBJECT_HDRS}
334 DEPENDS ${fq_deps_list}
335 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
336 COMPILE_OPTIONS ${compile_options}
346 target_include_directories(
349 ${LIBC_BUILD_DIR}/include
353 target_compile_options(${fq_target_name} PRIVATE ${compile_options})
356 if(SHOW_INTERMEDIATE_OBJECTS)
357 message(STATUS "Adding object library ${fq_target_name}")
358 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
359 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
360 message(STATUS " ${fq_target_name} depends on ${dep}")
366 add_dependencies(${fq_target_name} ${fq_deps_list})
369 if(NOT ADD_OBJECT_CXX_STANDARD)
370 set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
372 set_target_properties(
375 TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE}
376 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
377 DEPS "${fq_deps_list}"
378 FLAGS "${ADD_OBJECT_FLAGS}"
381 if(TARGET ${internal_target_name})
382 set_target_properties(
385 OBJECT_FILES "$<TARGET_OBJECTS:${internal_target_name}>"
388 endfunction(create_object_library)
390 # Internal function, used by `add_object_library`.
391 function(expand_flags_for_object_library target_name flags)
392 cmake_parse_arguments(
394 "IGNORE_MARKER" # Optional arguments
395 "" # Single-value arguments
396 "DEPENDS;FLAGS" # Multi-value arguments
400 list(LENGTH flags nflags)
402 create_object_library(
404 DEPENDS ${EXPAND_FLAGS_DEPENDS}
405 FLAGS ${EXPAND_FLAGS_FLAGS}
406 ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
411 list(GET flags 0 flag)
412 list(REMOVE_AT flags 0)
413 extract_flag_modifier(${flag} real_flag modifier)
415 if(NOT "${modifier}" STREQUAL "NO")
416 expand_flags_for_object_library(
419 DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
420 FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
421 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
425 if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
429 set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
430 list(REMOVE_ITEM NEW_FLAGS ${flag})
431 get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
433 # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
434 # `flag__ONLY` do not.
435 if("${modifier}" STREQUAL "")
436 set(TARGET_NAME "${target_name}.__NO_${flag}")
438 set(TARGET_NAME "${target_name}")
441 expand_flags_for_object_library(
444 DEPENDS "${NEW_DEPS}" IGNORE_MARKER
445 FLAGS "${NEW_FLAGS}" IGNORE_MARKER
446 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
448 endfunction(expand_flags_for_object_library)
450 function(add_object_library target_name)
451 cmake_parse_arguments(
453 "" # Optional arguments
454 "" # Single value arguments
455 "DEPENDS;FLAGS" # Multi-value arguments
459 get_fq_target_name(${target_name} fq_target_name)
461 if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
462 message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
465 get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
466 get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
468 list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
469 remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
472 if(SHOW_INTERMEDIATE_OBJECTS AND flags)
473 message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}")
476 expand_flags_for_object_library(
479 DEPENDS "${fq_deps_list}" IGNORE_MARKER
480 FLAGS "${flags}" IGNORE_MARKER
481 ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
483 endfunction(add_object_library)
485 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
487 # A rule for entrypoint object targets.
489 # add_entrypoint_object(
491 # [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
492 # [NAME] <the C name of the entrypoint if different from target_name>
493 # SRCS <list of .cpp files>
494 # HDRS <list of .h files>
495 # DEPENDS <list of dependencies>
496 # COMPILE_OPTIONS <optional list of special compile options for this target>
497 # SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
498 # FLAGS <optional list of flags>
500 function(create_entrypoint_object fq_target_name)
501 cmake_parse_arguments(
503 "ALIAS;REDIRECTED" # Optional argument
504 "NAME;CXX_STANDARD" # Single value arguments
505 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
509 list(FIND TARGET_ENTRYPOINT_NAME_LIST ${ADD_ENTRYPOINT_OBJ_NAME} entrypoint_name_index)
510 if(${entrypoint_name_index} EQUAL -1)
511 add_custom_target(${fq_target_name})
512 set_target_properties(
515 "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME}
516 "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
522 if(LIBC_CMAKE_VERBOSE_LOGGING)
523 message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
528 if(ADD_ENTRYPOINT_OBJ_ALIAS)
529 # Alias targets help one add aliases to other entrypoint object targets.
530 # One can use alias targets setup OS/machine independent entrypoint targets.
531 list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
532 if(NOT (${deps_size} EQUAL "1"))
533 message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
535 list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
536 get_fq_dep_name(fq_dep_name ${dep_target})
538 if(SHOW_INTERMEDIATE_OBJECTS)
539 message(STATUS "Adding entrypoint object ${fq_target_name} as an alias of"
543 if(NOT TARGET ${fq_dep_name})
544 message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
545 "Target ${target_name} will be ignored.")
549 get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
550 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})))
551 message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
554 add_custom_target(${fq_target_name})
555 add_dependencies(${fq_target_name} ${fq_dep_name})
556 get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
557 get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
558 set_target_properties(
561 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
562 TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE}
566 DEPS "${fq_dep_name}"
567 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
572 if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
573 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
575 if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
576 message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
578 if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD)
579 set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
582 _get_common_compile_options(
583 common_compile_options
584 "${ADD_ENTRYPOINT_OBJ_FLAGS}"
585 ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
587 set(internal_target_name ${fq_target_name}.__internal__)
588 set(include_dirs ${LIBC_BUILD_DIR}/include ${LIBC_SOURCE_DIR} ${LIBC_BUILD_DIR})
589 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
590 set(full_deps_list ${fq_deps_list} libc.src.__support.common)
592 if(SHOW_INTERMEDIATE_OBJECTS)
593 message(STATUS "Adding entrypoint object ${fq_target_name}")
594 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
595 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
596 message(STATUS " ${fq_target_name} depends on ${dep}")
601 # GPU builds require special handling for the objects because we want to
602 # export several different targets at once, e.g. for both Nvidia and AMD.
603 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
606 ${internal_target_name}
607 SRCS ${ADD_ENTRYPOINT_OBJ_SRCS}
608 HDRS ${ADD_ENTRYPOINT_OBJ_HDRS}
609 COMPILE_OPTIONS ${common_compile_options}
610 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
611 DEPENDS ${full_deps_list}
612 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
616 ${internal_target_name}
617 # TODO: We don't need an object library for internal consumption.
618 # A future change should switch this to a normal static library.
621 ${ADD_ENTRYPOINT_OBJ_SRCS}
622 ${ADD_ENTRYPOINT_OBJ_HDRS}
624 target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options})
625 target_include_directories(${internal_target_name} PRIVATE ${include_dirs})
626 add_dependencies(${internal_target_name} ${full_deps_list})
630 # We want an object library as the objects will eventually get packaged into
631 # an archive (like libc.a).
634 ${ADD_ENTRYPOINT_OBJ_SRCS}
635 ${ADD_ENTRYPOINT_OBJ_HDRS}
637 target_compile_options(${fq_target_name} BEFORE PRIVATE ${common_compile_options} -DLIBC_COPT_PUBLIC_PACKAGING)
638 target_include_directories(${fq_target_name} PRIVATE ${include_dirs})
639 add_dependencies(${fq_target_name} ${full_deps_list})
642 set_target_properties(
645 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
646 TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE}
647 OBJECT_FILE "$<TARGET_OBJECTS:${fq_target_name}>"
648 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
649 DEPS "${fq_deps_list}"
650 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
653 if(TARGET ${internal_target_name})
654 set_target_properties(
655 ${internal_target_name}
657 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
658 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
660 set_target_properties(
663 # TODO: We don't need to list internal object files if the internal
664 # target is a normal static library.
665 OBJECT_FILE_RAW "$<TARGET_OBJECTS:${internal_target_name}>"
669 if(LLVM_LIBC_ENABLE_LINTING AND TARGET ${internal_target_name})
670 if(NOT LLVM_LIBC_CLANG_TIDY)
671 message(FATAL_ERROR "Something is wrong! LLVM_LIBC_ENABLE_LINTING is "
672 "ON but LLVM_LIBC_CLANG_TIDY is not set.")
675 # We only want a second invocation of clang-tidy to run
676 # restrict-system-libc-headers if the compiler-resource-dir was set in
677 # order to prevent false-positives due to a mismatch between the host
678 # compiler and the compiled clang-tidy.
679 if(COMPILER_RESOURCE_DIR)
680 # We run restrict-system-libc-headers with --system-headers to prevent
681 # transitive inclusion through compler provided headers.
682 set(restrict_system_headers_check_invocation
683 COMMAND ${LLVM_LIBC_CLANG_TIDY} --system-headers
684 --checks="-*,llvmlibc-restrict-system-libc-headers"
685 # We explicitly set the resource dir here to match the
686 # resource dir of the host compiler.
687 "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
689 -p ${PROJECT_BINARY_DIR}
690 ${ADD_ENTRYPOINT_OBJ_SRCS}
693 set(restrict_system_headers_check_invocation
694 COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
698 ${fq_target_name}.__lint__
699 # --quiet is used to surpress warning statistics from clang-tidy like:
700 # Suppressed X warnings (X in non-user code).
701 # There seems to be a bug in clang-tidy where by even with --quiet some
702 # messages from clang's own diagnostics engine leak through:
703 # X warnings generated.
704 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
706 COMMAND ${LLVM_LIBC_CLANG_TIDY}
707 "--extra-arg=-fno-caret-diagnostics" --quiet
708 # Path to directory containing compile_commands.json
709 -p ${PROJECT_BINARY_DIR}
710 ${ADD_ENTRYPOINT_OBJ_SRCS}
711 # See above: this might be a second invocation of clang-tidy depending on
712 # the conditions above.
713 ${restrict_system_headers_check_invocation}
714 # We have two options for running commands, add_custom_command and
715 # add_custom_target. We don't want to run the linter unless source files
716 # have changed. add_custom_target explicitly runs everytime therefore we
717 # use add_custom_command. This function requires an output file and since
718 # linting doesn't produce a file, we create a dummy file using a
719 # crossplatform touch.
720 COMMENT "Linting... ${fq_target_name}"
721 DEPENDS ${internal_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
722 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
724 add_dependencies(libc-lint ${fq_target_name}.__lint__)
727 endfunction(create_entrypoint_object)
729 # Internal function, used by `add_entrypoint_object`.
730 function(expand_flags_for_entrypoint_object target_name flags)
731 cmake_parse_arguments(
733 "IGNORE_MARKER" # Optional arguments
734 "" # Single-value arguments
735 "DEPENDS;FLAGS" # Multi-value arguments
739 list(LENGTH flags nflags)
741 create_entrypoint_object(
743 DEPENDS ${EXPAND_FLAGS_DEPENDS}
744 FLAGS ${EXPAND_FLAGS_FLAGS}
745 ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
750 list(GET flags 0 flag)
751 list(REMOVE_AT flags 0)
752 extract_flag_modifier(${flag} real_flag modifier)
754 if(NOT "${modifier}" STREQUAL "NO")
755 expand_flags_for_entrypoint_object(
758 DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
759 FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
760 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
764 if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
768 set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
769 list(REMOVE_ITEM NEW_FLAGS ${flag})
770 get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
772 # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
773 # `flag__ONLY` do not.
774 if("${modifier}" STREQUAL "")
775 set(TARGET_NAME "${target_name}.__NO_${flag}")
777 set(TARGET_NAME "${target_name}")
780 expand_flags_for_entrypoint_object(
783 DEPENDS "${NEW_DEPS}" IGNORE_MARKER
784 FLAGS "${NEW_FLAGS}" IGNORE_MARKER
785 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
787 endfunction(expand_flags_for_entrypoint_object)
789 function(add_entrypoint_object target_name)
790 cmake_parse_arguments(
792 "" # Optional arguments
793 "NAME" # Single value arguments
794 "DEPENDS;FLAGS" # Multi-value arguments
798 get_fq_target_name(${target_name} fq_target_name)
800 if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
801 message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
804 get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
805 get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
807 list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
808 remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
811 if(SHOW_INTERMEDIATE_OBJECTS AND flags)
812 message(STATUS "Entrypoint object ${fq_target_name} has FLAGS: ${flags}")
815 if(NOT ADD_TO_EXPAND_NAME)
816 set(ADD_TO_EXPAND_NAME ${target_name})
819 expand_flags_for_entrypoint_object(
822 NAME ${ADD_TO_EXPAND_NAME} IGNORE_MARKER
823 DEPENDS "${fq_deps_list}" IGNORE_MARKER
824 FLAGS "${flags}" IGNORE_MARKER
825 ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
827 endfunction(add_entrypoint_object)
829 set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT")
831 # A rule for external entrypoint targets.
833 # add_entrypoint_external(
835 # DEPENDS <list of dependencies>
837 function(add_entrypoint_external target_name)
838 cmake_parse_arguments(
840 "" # No optional arguments
841 "" # No single value arguments
842 "DEPENDS" # Multi value arguments
845 get_fq_target_name(${target_name} fq_target_name)
846 set(entrypoint_name ${target_name})
848 add_custom_target(${fq_target_name})
849 set_target_properties(
852 "ENTRYPOINT_NAME" ${entrypoint_name}
853 "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE}
854 "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}"
857 endfunction(add_entrypoint_external)
859 # Rule build a redirector object file.
860 function(add_redirector_object target_name)
861 cmake_parse_arguments(
863 "" # No optional arguments
864 "SRC" # The cpp file in which the redirector is defined.
865 "" # No multivalue arguments
868 if(NOT REDIRECTOR_OBJECT_SRC)
869 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
876 ${REDIRECTOR_OBJECT_SRC}
878 target_compile_options(
880 BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT}
882 endfunction(add_redirector_object)