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")
25 if(LLVM_LIBC_FULL_BUILD)
26 # Only add -ffreestanding flag in full build mode.
27 list(APPEND compile_options "-ffreestanding")
30 list(APPEND compile_options "-fno-builtin")
31 list(APPEND compile_options "-fno-exceptions")
32 list(APPEND compile_options "-fno-lax-vector-conversions")
33 list(APPEND compile_options "-fno-unwind-tables")
34 list(APPEND compile_options "-fno-asynchronous-unwind-tables")
35 list(APPEND compile_options "-fno-rtti")
36 list(APPEND compile_options "-Wall")
37 list(APPEND compile_options "-Wextra")
38 list(APPEND compile_options "-Wconversion")
39 list(APPEND compile_options "-Wno-sign-conversion")
40 list(APPEND compile_options "-Wimplicit-fallthrough")
41 list(APPEND compile_options "-Wwrite-strings")
42 list(APPEND compile_options "-Wextra-semi")
43 if(NOT CMAKE_COMPILER_IS_GNUCXX)
44 list(APPEND compile_options "-Wnewline-eof")
45 list(APPEND compile_options "-Wnonportable-system-include-path")
46 list(APPEND compile_options "-Wstrict-prototypes")
47 list(APPEND compile_options "-Wthread-safety")
48 list(APPEND compile_options "-Wglobal-constructors")
51 if(LIBC_TARGET_ARCHITECTURE_IS_X86)
52 list(APPEND compile_options "-mavx2")
53 list(APPEND compile_options "-mfma")
54 elseif(LIBC_TARGET_ARCHITECTURE_IS_RISCV64)
55 list(APPEND compile_options "-D__LIBC_RISCV_USE_FMA")
59 list(APPEND compile_options "-msse4.2")
62 list(APPEND compile_options "/EHs-c-")
63 list(APPEND compile_options "/GR-")
65 list(APPEND compile_options "/arch:AVX2")
68 if (LIBC_TARGET_ARCHITECTURE_IS_GPU)
69 list(APPEND compile_options "-nogpulib")
70 list(APPEND compile_options "-fvisibility=hidden")
71 list(APPEND compile_options "-fconvergent-functions")
73 # Manually disable all standard include paths and include the resource
74 # directory to prevent system headers from being included.
75 list(APPEND compile_options "-isystem${COMPILER_RESOURCE_DIR}/include")
76 list(APPEND compile_options "-nostdinc")
78 set(${output_var} ${compile_options} PARENT_SCOPE)
81 # Obtains NVPTX specific arguments for compilation.
82 # The PTX feature is primarily based on the CUDA toolchain version. We want to
83 # be able to target NVPTX without an existing CUDA installation, so we need to
84 # set this manually. This simply sets the PTX feature to the minimum required
85 # for the features we wish to use on that target. The minimum PTX features used
86 # here roughly corresponds to the CUDA 9.0 release.
87 # Adjust as needed for desired PTX features.
88 function(get_nvptx_compile_options output_var gpu_arch)
90 list(APPEND nvptx_options "-march=${gpu_arch}")
91 list(APPEND nvptx_options "-Wno-unknown-cuda-version")
92 if(${gpu_arch} STREQUAL "sm_35")
93 list(APPEND nvptx_options "--cuda-feature=+ptx60")
94 elseif(${gpu_arch} STREQUAL "sm_37")
95 list(APPEND nvptx_options "--cuda-feature=+ptx60")
96 elseif(${gpu_arch} STREQUAL "sm_50")
97 list(APPEND nvptx_options "--cuda-feature=+ptx60")
98 elseif(${gpu_arch} STREQUAL "sm_52")
99 list(APPEND nvptx_options "--cuda-feature=+ptx60")
100 elseif(${gpu_arch} STREQUAL "sm_53")
101 list(APPEND nvptx_options "--cuda-feature=+ptx63")
102 elseif(${gpu_arch} STREQUAL "sm_60")
103 list(APPEND nvptx_options "--cuda-feature=+ptx63")
104 elseif(${gpu_arch} STREQUAL "sm_61")
105 list(APPEND nvptx_options "--cuda-feature=+ptx63")
106 elseif(${gpu_arch} STREQUAL "sm_62")
107 list(APPEND nvptx_options "--cuda-feature=+ptx63")
108 elseif(${gpu_arch} STREQUAL "sm_70")
109 list(APPEND nvptx_options "--cuda-feature=+ptx63")
110 elseif(${gpu_arch} STREQUAL "sm_72")
111 list(APPEND nvptx_options "--cuda-feature=+ptx63")
112 elseif(${gpu_arch} STREQUAL "sm_75")
113 list(APPEND nvptx_options "--cuda-feature=+ptx63")
114 elseif(${gpu_arch} STREQUAL "sm_80")
115 list(APPEND nvptx_options "--cuda-feature=+ptx72")
116 elseif(${gpu_arch} STREQUAL "sm_86")
117 list(APPEND nvptx_options "--cuda-feature=+ptx72")
118 elseif(${gpu_arch} STREQUAL "sm_89")
119 list(APPEND nvptx_options "--cuda-feature=+ptx72")
120 elseif(${gpu_arch} STREQUAL "sm_90")
121 list(APPEND nvptx_options "--cuda-feature=+ptx72")
123 message(FATAL_ERROR "Unknown Nvidia GPU architecture '${gpu_arch}'")
127 list(APPEND nvptx_options "--cuda-path=${LIBC_CUDA_ROOT}")
129 set(${output_var} ${nvptx_options} PARENT_SCOPE)
132 # Builds the object target for the GPU.
133 # This compiles the target for all supported architectures and embeds it into
134 # host binary for installing. The internal target contains the GPU code directly
135 # compiled for a single architecture used internally.
137 # _build_gpu_objects(
139 # <internal_target_name>
140 # SRCS <list of .cpp files>
141 # HDRS <list of .h files>
142 # DEPENDS <list of dependencies>
143 # COMPILE_OPTIONS <optional list of special compile options for this target>
144 # FLAGS <optional list of flags>
146 function(_build_gpu_objects fq_target_name internal_target_name)
147 cmake_parse_arguments(
149 "" # No optional arguments
150 "NAME;CXX_STANDARD" # Single value arguments
151 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
155 set(common_compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
156 if(NOT ADD_GPU_OBJ_CXX_STANDARD)
157 set(ADD_GPU_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
160 foreach(add_gpu_obj_src ${ADD_GPU_OBJ_SRCS})
161 # The packaged version will be built for every target GPU architecture. We do
162 # this so we can support multiple accelerators on the same machine.
163 foreach(gpu_arch ${LIBC_GPU_ARCHITECTURES})
164 get_filename_component(src_name ${add_gpu_obj_src} NAME)
165 set(gpu_target_name ${fq_target_name}.${src_name}.${gpu_arch})
166 set(compile_options ${ADD_GPU_OBJ_COMPILE_OPTIONS})
167 # Derive the triple from the specified architecture.
168 if("${gpu_arch}" IN_LIST all_amdgpu_architectures)
169 set(gpu_target_triple "amdgcn-amd-amdhsa")
170 list(APPEND compile_options "-mcpu=${gpu_arch}")
171 list(APPEND compile_options "SHELL:-Xclang -mcode-object-version=none")
172 elseif("${gpu_arch}" IN_LIST all_nvptx_architectures)
173 set(gpu_target_triple "nvptx64-nvidia-cuda")
174 get_nvptx_compile_options(nvptx_options ${gpu_arch})
175 list(APPEND compile_options "${nvptx_options}")
177 message(FATAL_ERROR "Unknown GPU architecture '${gpu_arch}'")
179 list(APPEND compile_options "--target=${gpu_target_triple}")
180 list(APPEND compile_options "-emit-llvm")
182 # Build the library for this target architecture. We always emit LLVM-IR for
183 # packaged GPU binaries.
184 add_library(${gpu_target_name}
191 target_compile_options(${gpu_target_name} PRIVATE ${compile_options})
192 target_include_directories(${gpu_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
193 target_include_directories(${gpu_target_name} PRIVATE ${LIBC_SOURCE_DIR})
194 target_compile_definitions(${gpu_target_name} PRIVATE LIBC_COPT_PUBLIC_PACKAGING)
195 set_target_properties(${gpu_target_name} PROPERTIES CXX_STANDARD ${ADD_GPU_OBJ_CXX_STANDARD})
196 if(ADD_GPU_OBJ_DEPENDS)
197 add_dependencies(${gpu_target_name} ${ADD_GPU_OBJ_DEPENDS})
200 # Append this target to a list of images to package into a single binary.
201 set(input_file $<TARGET_OBJECTS:${gpu_target_name}>)
202 if("${gpu_arch}" IN_LIST all_nvptx_architectures)
203 string(REGEX MATCH "\\+ptx[0-9]+" nvptx_ptx_feature ${nvptx_options})
204 list(APPEND packager_images
205 --image=file=${input_file},arch=${gpu_arch},triple=${gpu_target_triple},feature=${nvptx_ptx_feature})
207 list(APPEND packager_images
208 --image=file=${input_file},arch=${gpu_arch},triple=${gpu_target_triple})
210 list(APPEND gpu_target_objects ${input_file})
213 # After building the target for the desired GPUs we must package the output
214 # into a fatbinary, see https://clang.llvm.org/docs/OffloadingDesign.html for
216 set(packaged_target_name ${fq_target_name}.${src_name}.__gpu__)
217 set(packaged_output_name ${CMAKE_CURRENT_BINARY_DIR}/${fq_target_name}.${src_name}.gpubin)
219 add_custom_command(OUTPUT ${packaged_output_name}
220 COMMAND ${LIBC_CLANG_OFFLOAD_PACKAGER}
221 ${packager_images} -o ${packaged_output_name}
222 DEPENDS ${gpu_target_objects} ${add_gpu_obj_src} ${ADD_GPU_OBJ_HDRS}
223 COMMENT "Packaging LLVM offloading binary")
224 add_custom_target(${packaged_target_name} DEPENDS ${packaged_output_name})
225 list(APPEND packaged_gpu_names ${packaged_target_name})
226 list(APPEND packaged_gpu_binaries ${packaged_output_name})
229 # We create an empty 'stub' file for the host to contain the embedded device
230 # code. This will be packaged into 'libcgpu.a'.
231 # TODO: In the future we will want to combine every architecture for a target
232 # into a single bitcode file and use that. For now we simply build for
233 # every single one and let the offloading linker handle it.
234 string(FIND ${fq_target_name} "." last_dot_loc REVERSE)
235 math(EXPR name_loc "${last_dot_loc} + 1")
236 string(SUBSTRING ${fq_target_name} ${name_loc} -1 target_name)
237 set(stub_filename "${target_name}.cpp")
239 OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}"
240 COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/stubs/
241 COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}
242 DEPENDS ${gpu_target_objects} ${ADD_GPU_OBJ_SRCS} ${ADD_GPU_OBJ_HDRS}
244 set(stub_target_name ${fq_target_name}.__stub__)
245 add_custom_target(${stub_target_name} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename})
249 # We want an object library as the objects will eventually get packaged into
250 # an archive (like libcgpu.a).
253 ${CMAKE_CURRENT_BINARY_DIR}/stubs/${stub_filename}
255 target_compile_options(${fq_target_name} BEFORE PRIVATE
256 ${common_compile_options} -nostdlib)
257 foreach(packaged_gpu_binary ${packaged_gpu_binaries})
258 target_compile_options(${fq_target_name} PRIVATE
259 "SHELL:-Xclang -fembed-offload-object=${packaged_gpu_binary}")
261 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
262 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
263 add_dependencies(${fq_target_name}
264 ${full_deps_list} ${packaged_gpu_names} ${stub_target_name})
266 # We only build the internal target for a single supported architecture.
267 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU OR
268 LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
270 ${internal_target_name}
276 target_compile_options(${internal_target_name} BEFORE PRIVATE
277 ${common_compile_options} --target=${LIBC_GPU_TARGET_TRIPLE})
278 if(LIBC_GPU_TARGET_ARCHITECTURE_IS_AMDGPU)
279 target_compile_options(${internal_target_name} PRIVATE
280 "SHELL:-Xclang -mcode-object-version=none"
281 -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto)
282 elseif(LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX)
283 get_nvptx_compile_options(nvptx_options ${LIBC_GPU_TARGET_ARCHITECTURE})
284 target_compile_options(${internal_target_name} PRIVATE ${nvptx_options})
286 target_include_directories(${internal_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
287 target_include_directories(${internal_target_name} PRIVATE ${LIBC_SOURCE_DIR})
289 add_dependencies(${internal_target_name} ${full_deps_list})
294 # Rule which is essentially a wrapper over add_library to compile a set of
295 # sources to object files.
297 # add_object_library(
299 # HDRS <list of header files>
300 # SRCS <list of source files>
301 # [ALIAS] <If this object library is an alias for another object library.>
302 # DEPENDS <list of dependencies; Should be a single item for ALIAS libraries>
303 # COMPILE_OPTIONS <optional list of special compile options for this target>
304 # FLAGS <optional list of flags>
305 function(create_object_library fq_target_name)
306 cmake_parse_arguments(
308 "ALIAS;NO_GPU_BUNDLE" # optional arguments
309 "CXX_STANDARD" # Single value arguments
310 "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments
314 get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
317 if(ADD_OBJECT_SRCS OR ADD_OBJECT_HDRS)
319 "${fq_target_name}: object library alias cannot have SRCS and/or HDRS.")
321 list(LENGTH fq_deps_list depends_size)
322 if(NOT ${depends_size} EQUAL 1)
324 "${fq_targe_name}: object library alias should have exactly one DEPENDS.")
334 if(NOT ADD_OBJECT_SRCS)
335 message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
338 # The GPU build uses a separate internal file.
339 if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
340 set(internal_target_name ${fq_target_name}.__internal__)
342 set(internal_target_name ${fq_target_name})
345 _get_common_compile_options(
347 "${ADD_OBJECT_FLAGS}"
348 ${ADD_OBJECT_COMPILE_OPTIONS}
351 # GPU builds require special handling for the objects because we want to
352 # export several different targets at once, e.g. for both Nvidia and AMD.
353 if(LIBC_TARGET_ARCHITECTURE_IS_GPU AND NOT ${ADD_OBJECT_NO_GPU_BUNDLE})
356 ${internal_target_name}
357 SRCS ${ADD_OBJECT_SRCS}
358 HDRS ${ADD_OBJECT_HDRS}
359 DEPENDS ${fq_deps_list}
360 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
361 COMPILE_OPTIONS ${compile_options}
371 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
372 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
373 target_compile_options(${fq_target_name} PRIVATE ${compile_options})
376 if(SHOW_INTERMEDIATE_OBJECTS)
377 message(STATUS "Adding object library ${fq_target_name}")
378 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
379 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
380 message(STATUS " ${fq_target_name} depends on ${dep}")
386 add_dependencies(${fq_target_name} ${fq_deps_list})
387 # Add deps as link libraries to inherit interface compile and link options.
388 target_link_libraries(${fq_target_name} PUBLIC ${fq_deps_list})
391 if(NOT ADD_OBJECT_CXX_STANDARD)
392 set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
394 set_target_properties(
397 TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE}
398 CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
399 DEPS "${fq_deps_list}"
400 FLAGS "${ADD_OBJECT_FLAGS}"
403 if(TARGET ${internal_target_name})
404 set_target_properties(
407 OBJECT_FILES "$<TARGET_OBJECTS:${internal_target_name}>"
410 endfunction(create_object_library)
412 # Internal function, used by `add_object_library`.
413 function(expand_flags_for_object_library target_name flags)
414 cmake_parse_arguments(
416 "IGNORE_MARKER" # Optional arguments
417 "" # Single-value arguments
418 "DEPENDS;FLAGS" # Multi-value arguments
422 list(LENGTH flags nflags)
424 create_object_library(
426 DEPENDS ${EXPAND_FLAGS_DEPENDS}
427 FLAGS ${EXPAND_FLAGS_FLAGS}
428 ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
433 list(GET flags 0 flag)
434 list(REMOVE_AT flags 0)
435 extract_flag_modifier(${flag} real_flag modifier)
437 if(NOT "${modifier}" STREQUAL "NO")
438 expand_flags_for_object_library(
441 DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
442 FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
443 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
447 if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
451 set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
452 list(REMOVE_ITEM NEW_FLAGS ${flag})
453 get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
455 # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
456 # `flag__ONLY` do not.
457 if("${modifier}" STREQUAL "")
458 set(TARGET_NAME "${target_name}.__NO_${flag}")
460 set(TARGET_NAME "${target_name}")
463 expand_flags_for_object_library(
466 DEPENDS "${NEW_DEPS}" IGNORE_MARKER
467 FLAGS "${NEW_FLAGS}" IGNORE_MARKER
468 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
470 endfunction(expand_flags_for_object_library)
472 function(add_object_library target_name)
473 cmake_parse_arguments(
475 "" # Optional arguments
476 "" # Single value arguments
477 "DEPENDS;FLAGS" # Multi-value arguments
481 get_fq_target_name(${target_name} fq_target_name)
483 if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
484 message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
487 get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
488 get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
490 list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
491 remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
494 if(SHOW_INTERMEDIATE_OBJECTS AND flags)
495 message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}")
498 expand_flags_for_object_library(
501 DEPENDS "${fq_deps_list}" IGNORE_MARKER
502 FLAGS "${flags}" IGNORE_MARKER
503 ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
505 endfunction(add_object_library)
507 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
508 set(ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE "ENTRYPOINT_OBJ_VENDOR")
510 # A rule for entrypoint object targets.
512 # add_entrypoint_object(
514 # [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
515 # [NAME] <the C name of the entrypoint if different from target_name>
516 # SRCS <list of .cpp files>
517 # HDRS <list of .h files>
518 # DEPENDS <list of dependencies>
519 # COMPILE_OPTIONS <optional list of special compile options for this target>
520 # SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
521 # FLAGS <optional list of flags>
523 function(create_entrypoint_object fq_target_name)
524 cmake_parse_arguments(
526 "ALIAS;REDIRECTED;VENDOR" # Optional argument
527 "NAME;CXX_STANDARD" # Single value arguments
528 "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments
532 set(entrypoint_target_type ${ENTRYPOINT_OBJ_TARGET_TYPE})
533 if(${ADD_ENTRYPOINT_OBJ_VENDOR})
534 # TODO: We currently rely on external definitions of certain math functions
535 # provided by GPU vendors like AMD or Nvidia. We need to mark these so we
536 # don't end up running tests on these. In the future all of these should be
537 # implemented and this can be removed.
538 set(entrypoint_target_type ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})
540 list(FIND TARGET_ENTRYPOINT_NAME_LIST ${ADD_ENTRYPOINT_OBJ_NAME} entrypoint_name_index)
541 if(${entrypoint_name_index} EQUAL -1)
542 add_custom_target(${fq_target_name})
543 set_target_properties(
546 "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME}
547 "TARGET_TYPE" ${entrypoint_target_type}
553 if(LIBC_CMAKE_VERBOSE_LOGGING)
554 message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
559 set(internal_target_name ${fq_target_name}.__internal__)
561 if(ADD_ENTRYPOINT_OBJ_ALIAS)
562 # Alias targets help one add aliases to other entrypoint object targets.
563 # One can use alias targets setup OS/machine independent entrypoint targets.
564 list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
565 if(NOT (${deps_size} EQUAL "1"))
566 message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
568 list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
569 get_fq_dep_name(fq_dep_name ${dep_target})
571 if(SHOW_INTERMEDIATE_OBJECTS)
572 message(STATUS "Adding entrypoint object ${fq_target_name} as an alias of"
576 if(NOT TARGET ${fq_dep_name})
577 message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
578 "Target ${target_name} will be ignored.")
582 get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
583 if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR
584 ${obj_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})))
585 message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
588 get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
589 get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
591 ${internal_target_name}
596 add_dependencies(${internal_target_name} ${fq_dep_name})
603 add_dependencies(${fq_target_name} ${fq_dep_name} ${internal_target_name})
604 set_target_properties(
607 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
608 TARGET_TYPE ${entrypoint_target_type}
612 DEPS "${fq_dep_name}"
613 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
618 if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
619 message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
621 if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
622 message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
624 if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD)
625 set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
628 _get_common_compile_options(
629 common_compile_options
630 "${ADD_ENTRYPOINT_OBJ_FLAGS}"
631 ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
633 get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
634 set(full_deps_list ${fq_deps_list} libc.src.__support.common)
636 if(SHOW_INTERMEDIATE_OBJECTS)
637 message(STATUS "Adding entrypoint object ${fq_target_name}")
638 if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
639 foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
640 message(STATUS " ${fq_target_name} depends on ${dep}")
645 # GPU builds require special handling for the objects because we want to
646 # export several different targets at once, e.g. for both Nvidia and AMD.
647 if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
650 ${internal_target_name}
651 SRCS ${ADD_ENTRYPOINT_OBJ_SRCS}
652 HDRS ${ADD_ENTRYPOINT_OBJ_HDRS}
653 COMPILE_OPTIONS ${common_compile_options}
654 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
655 DEPENDS ${full_deps_list}
656 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
660 ${internal_target_name}
661 # TODO: We don't need an object library for internal consumption.
662 # A future change should switch this to a normal static library.
665 ${ADD_ENTRYPOINT_OBJ_SRCS}
666 ${ADD_ENTRYPOINT_OBJ_HDRS}
668 target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options})
669 target_include_directories(${internal_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
670 target_include_directories(${internal_target_name} PRIVATE ${LIBC_SOURCE_DIR})
671 add_dependencies(${internal_target_name} ${full_deps_list})
672 target_link_libraries(${internal_target_name} ${full_deps_list})
676 # We want an object library as the objects will eventually get packaged into
677 # an archive (like libc.a).
680 ${ADD_ENTRYPOINT_OBJ_SRCS}
681 ${ADD_ENTRYPOINT_OBJ_HDRS}
683 target_compile_options(${fq_target_name} BEFORE PRIVATE ${common_compile_options} -DLIBC_COPT_PUBLIC_PACKAGING)
684 target_include_directories(${fq_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
685 target_include_directories(${fq_target_name} PRIVATE ${LIBC_SOURCE_DIR})
686 add_dependencies(${fq_target_name} ${full_deps_list})
687 target_link_libraries(${fq_target_name} ${full_deps_list})
690 set_target_properties(
693 ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
694 TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE}
695 OBJECT_FILE "$<TARGET_OBJECTS:${fq_target_name}>"
696 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
697 DEPS "${fq_deps_list}"
698 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
701 if(TARGET ${internal_target_name})
702 set_target_properties(
703 ${internal_target_name}
705 CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
706 FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
708 set_target_properties(
711 # TODO: We don't need to list internal object files if the internal
712 # target is a normal static library.
713 OBJECT_FILE_RAW "$<TARGET_OBJECTS:${internal_target_name}>"
717 if(LLVM_LIBC_ENABLE_LINTING AND TARGET ${internal_target_name})
718 if(NOT LLVM_LIBC_CLANG_TIDY)
719 message(FATAL_ERROR "Something is wrong! LLVM_LIBC_ENABLE_LINTING is "
720 "ON but LLVM_LIBC_CLANG_TIDY is not set.")
723 # We only want a second invocation of clang-tidy to run
724 # restrict-system-libc-headers if the compiler-resource-dir was set in
725 # order to prevent false-positives due to a mismatch between the host
726 # compiler and the compiled clang-tidy.
727 if(COMPILER_RESOURCE_DIR)
728 # We run restrict-system-libc-headers with --system-headers to prevent
729 # transitive inclusion through compler provided headers.
730 set(restrict_system_headers_check_invocation
731 COMMAND ${LLVM_LIBC_CLANG_TIDY} --system-headers
732 --checks="-*,llvmlibc-restrict-system-libc-headers"
733 # We explicitly set the resource dir here to match the
734 # resource dir of the host compiler.
735 "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
737 -p ${PROJECT_BINARY_DIR}
738 ${ADD_ENTRYPOINT_OBJ_SRCS}
741 set(restrict_system_headers_check_invocation
742 COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
746 ${fq_target_name}.__lint__
747 # --quiet is used to surpress warning statistics from clang-tidy like:
748 # Suppressed X warnings (X in non-user code).
749 # There seems to be a bug in clang-tidy where by even with --quiet some
750 # messages from clang's own diagnostics engine leak through:
751 # X warnings generated.
752 # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
754 COMMAND ${LLVM_LIBC_CLANG_TIDY}
755 "--extra-arg=-fno-caret-diagnostics" --quiet
756 # Path to directory containing compile_commands.json
757 -p ${PROJECT_BINARY_DIR}
758 ${ADD_ENTRYPOINT_OBJ_SRCS}
759 # See above: this might be a second invocation of clang-tidy depending on
760 # the conditions above.
761 ${restrict_system_headers_check_invocation}
762 # We have two options for running commands, add_custom_command and
763 # add_custom_target. We don't want to run the linter unless source files
764 # have changed. add_custom_target explicitly runs everytime therefore we
765 # use add_custom_command. This function requires an output file and since
766 # linting doesn't produce a file, we create a dummy file using a
767 # crossplatform touch.
768 COMMENT "Linting... ${fq_target_name}"
769 DEPENDS ${internal_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
770 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
772 add_dependencies(libc-lint ${fq_target_name}.__lint__)
775 endfunction(create_entrypoint_object)
777 # Internal function, used by `add_entrypoint_object`.
778 function(expand_flags_for_entrypoint_object target_name flags)
779 cmake_parse_arguments(
781 "IGNORE_MARKER" # Optional arguments
782 "" # Single-value arguments
783 "DEPENDS;FLAGS" # Multi-value arguments
787 list(LENGTH flags nflags)
789 create_entrypoint_object(
791 DEPENDS ${EXPAND_FLAGS_DEPENDS}
792 FLAGS ${EXPAND_FLAGS_FLAGS}
793 ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
798 list(GET flags 0 flag)
799 list(REMOVE_AT flags 0)
800 extract_flag_modifier(${flag} real_flag modifier)
802 if(NOT "${modifier}" STREQUAL "NO")
803 expand_flags_for_entrypoint_object(
806 DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
807 FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
808 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
812 if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
816 set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
817 list(REMOVE_ITEM NEW_FLAGS ${flag})
818 get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
820 # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
821 # `flag__ONLY` do not.
822 if("${modifier}" STREQUAL "")
823 set(TARGET_NAME "${target_name}.__NO_${flag}")
825 set(TARGET_NAME "${target_name}")
828 expand_flags_for_entrypoint_object(
831 DEPENDS "${NEW_DEPS}" IGNORE_MARKER
832 FLAGS "${NEW_FLAGS}" IGNORE_MARKER
833 "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
835 endfunction(expand_flags_for_entrypoint_object)
837 function(add_entrypoint_object target_name)
838 cmake_parse_arguments(
840 "" # Optional arguments
841 "NAME" # Single value arguments
842 "DEPENDS;FLAGS" # Multi-value arguments
846 get_fq_target_name(${target_name} fq_target_name)
848 if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
849 message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
852 get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
853 get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
855 list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
856 remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
859 if(SHOW_INTERMEDIATE_OBJECTS AND flags)
860 message(STATUS "Entrypoint object ${fq_target_name} has FLAGS: ${flags}")
863 if(NOT ADD_TO_EXPAND_NAME)
864 set(ADD_TO_EXPAND_NAME ${target_name})
867 expand_flags_for_entrypoint_object(
870 NAME ${ADD_TO_EXPAND_NAME} IGNORE_MARKER
871 DEPENDS "${fq_deps_list}" IGNORE_MARKER
872 FLAGS "${flags}" IGNORE_MARKER
873 ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
875 endfunction(add_entrypoint_object)
877 set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT")
879 # A rule for external entrypoint targets.
881 # add_entrypoint_external(
883 # DEPENDS <list of dependencies>
885 function(add_entrypoint_external target_name)
886 cmake_parse_arguments(
888 "" # No optional arguments
889 "" # No single value arguments
890 "DEPENDS" # Multi value arguments
893 get_fq_target_name(${target_name} fq_target_name)
894 set(entrypoint_name ${target_name})
896 add_custom_target(${fq_target_name})
897 set_target_properties(
900 "ENTRYPOINT_NAME" ${entrypoint_name}
901 "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE}
902 "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}"
905 endfunction(add_entrypoint_external)
907 # Rule build a redirector object file.
908 function(add_redirector_object target_name)
909 cmake_parse_arguments(
911 "" # No optional arguments
912 "SRC" # The cpp file in which the redirector is defined.
913 "" # No multivalue arguments
916 if(NOT REDIRECTOR_OBJECT_SRC)
917 message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
924 ${REDIRECTOR_OBJECT_SRC}
926 target_compile_options(
928 BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT}
930 endfunction(add_redirector_object)