Bump version to 19.1.0 (final)
[llvm-project.git] / libc / cmake / modules / LLVMLibCObjectRules.cmake
blob68b5ed1ed51c042b16f65eb3d689a0bde2766120
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.
5 # Usage:
6 #     add_object_library(
7 #       <target_name>
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(
16     "ADD_OBJECT"
17     "ALIAS;NO_GPU_BUNDLE" # optional arguments
18     "CXX_STANDARD" # Single value arguments
19     "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments
20     ${ARGN}
21   )
23   get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
25   if(ADD_OBJECT_ALIAS)
26     if(ADD_OBJECT_SRCS OR ADD_OBJECT_HDRS)
27       message(FATAL_ERROR
28               "${fq_target_name}: object library alias cannot have SRCS and/or HDRS.")
29     endif()
30     list(LENGTH fq_deps_list depends_size)
31     if(NOT ${depends_size} EQUAL 1)
32       message(FATAL_ERROR
33               "${fq_targe_name}: object library alias should have exactly one DEPENDS.")
34     endif()
35     add_library(
36       ${fq_target_name}
37       ALIAS
38       ${fq_deps_list}
39     )
40     return()
41   endif()
43   if(NOT ADD_OBJECT_SRCS)
44     message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
45   endif()
47   if(NOT ADD_OBJECT_CXX_STANDARD)
48     set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
49   endif()
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})
57   add_library(
58     ${fq_target_name}
59     EXCLUDE_FROM_ALL
60     OBJECT
61     ${ADD_OBJECT_SRCS}
62     ${ADD_OBJECT_HDRS}
63   )
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}")
73       endforeach()
74     endif()
75   endif()
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(
84     ${fq_target_name}
85     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}"
90   )
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})
97   endif()
99   set_target_properties(
100     ${fq_target_name}
101     PROPERTIES
102       OBJECT_FILES "$<TARGET_OBJECTS:${target_objects}>"
103   )
104 endfunction(create_object_library)
106 function(add_object_library target_name)
107   add_target_with_flags(
108     ${target_name}
109     CREATE_TARGET create_object_library
110     ${ARGN})
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.
117 # Usage:
118 #     add_entrypoint_object(
119 #       <target_name>
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>
128 #     )
129 function(create_entrypoint_object fq_target_name)
130   cmake_parse_arguments(
131     "ADD_ENTRYPOINT_OBJ"
132     "ALIAS;REDIRECTED;VENDOR" # Optional argument
133     "NAME;CXX_STANDARD" # Single value arguments
134     "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS"  # Multi value arguments
135     ${ARGN}
136   )
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})
145   endif()
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(
150       ${fq_target_name}
151       PROPERTIES
152         "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME}
153         "TARGET_TYPE" ${entrypoint_target_type}
154         "OBJECT_FILE" ""
155         "OBJECT_FILE_RAW" ""
156         "DEPS" ""
157         "SKIPPED" "YES"
158     )
159     if(LIBC_CMAKE_VERBOSE_LOGGING)
160       message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
161     endif()
162     return()
163   endif()
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.")
173     endif()
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"
179               " ${fq_dep_name}")
180     endif()
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.")
185       return()
186     endif()
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.")
192     endif()
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})
200     else()
201       add_library(
202         ${internal_target_name}
203         EXCLUDE_FROM_ALL
204         OBJECT
205         ${object_file_raw}
206       )
207     endif()
209     add_dependencies(${internal_target_name} ${fq_dep_name})
210     add_library(
211       ${fq_target_name}
212       EXCLUDE_FROM_ALL
213       OBJECT
214       ${object_file}
215     )
216     add_dependencies(${fq_target_name} ${fq_dep_name} ${internal_target_name})
217     set_target_properties(
218       ${fq_target_name}
219       PROPERTIES
220         ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
221         TARGET_TYPE ${entrypoint_target_type}
222         IS_ALIAS "YES"
223         OBJECT_FILE ""
224         OBJECT_FILE_RAW ""
225         DEPS "${fq_dep_name}"
226         FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
227     )
228     return()
229   endif()
231   if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
232     message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
233   endif()
234   if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD)
235     set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
236   endif()
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}")
248       endforeach()
249     endif()
250   endif()
252   add_library(
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.
256     EXCLUDE_FROM_ALL
257     OBJECT
258     ${ADD_ENTRYPOINT_OBJ_SRCS}
259     ${ADD_ENTRYPOINT_OBJ_HDRS}
260   )
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})
267   add_library(
268     ${fq_target_name}
269     # We want an object library as the objects will eventually get packaged into
270     # an archive (like libc.a).
271     EXCLUDE_FROM_ALL
272     OBJECT
273     ${ADD_ENTRYPOINT_OBJ_SRCS}
274     ${ADD_ENTRYPOINT_OBJ_HDRS}
275   )
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})
290     endif()
291   endif()
293   set_target_properties(
294     ${fq_target_name}
295     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}"
302   )
304   if(TARGET ${internal_target_name})
305     set_target_properties(
306       ${internal_target_name}
307       PROPERTIES
308         CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
309         FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
310     )
311     set_target_properties(
312       ${fq_target_name}
313       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}>"
317     )
318   endif()
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.")
324     endif()
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}"
339         --quiet
340         -p ${PROJECT_BINARY_DIR}
341         ${ADD_ENTRYPOINT_OBJ_SRCS}
342       )
343     else()
344       set(restrict_system_headers_check_invocation
345         COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
346     endif()
348     add_custom_target(
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
356       # these.
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}
374     )
375     add_dependencies(libc-lint ${fq_target_name}.__lint__)
376   endif()
378 endfunction(create_entrypoint_object)
380 function(add_entrypoint_object target_name)
381   cmake_parse_arguments(
382     "ADD_ENTRYPOINT_OBJ"
383     "" # Optional arguments
384     "NAME" # Single value arguments
385     "" # Multi-value arguments
386     ${ARGN}
387   )
389   if(NOT ADD_ENTRYPOINT_OBJ_NAME)
390     set(ADD_ENTRYPOINT_OBJ_NAME ${target_name})
391   endif()
393   add_target_with_flags(
394     ${target_name}
395     NAME ${ADD_ENTRYPOINT_OBJ_NAME}
396     CREATE_TARGET create_entrypoint_object
397     ${ADD_ENTRYPOINT_OBJ_UNPARSED_ARGUMENTS}
398   )
399 endfunction(add_entrypoint_object)
401 set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT")
403 # A rule for external entrypoint targets.
404 # Usage:
405 #     add_entrypoint_external(
406 #       <target_name>
407 #       DEPENDS <list of dependencies>
408 #     )
409 function(add_entrypoint_external target_name)
410   cmake_parse_arguments(
411     "ADD_ENTRYPOINT_EXT"
412     "" # No optional arguments
413     "" # No single value arguments
414     "DEPENDS"  # Multi value arguments
415     ${ARGN}
416   )
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(
422     ${fq_target_name}
423     PROPERTIES
424       "ENTRYPOINT_NAME" ${entrypoint_name}
425       "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE}
426       "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}"
427   )
429 endfunction(add_entrypoint_external)
431 # Rule build a redirector object file.
432 function(add_redirector_object target_name)
433   cmake_parse_arguments(
434     "REDIRECTOR_OBJECT"
435     "" # No optional arguments
436     "SRC" # The cpp file in which the redirector is defined.
437     "" # No multivalue arguments
438     ${ARGN}
439   )
440   if(NOT REDIRECTOR_OBJECT_SRC)
441     message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
442   endif()
444   add_library(
445     ${target_name}
446     EXCLUDE_FROM_ALL
447     OBJECT
448     ${REDIRECTOR_OBJECT_SRC}
449   )
450   target_compile_options(
451     ${target_name}
452     BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT}
453   )
454 endfunction(add_redirector_object)