Bump version to 19.1.0 (final)
[llvm-project.git] / libc / cmake / modules / LLVMLibCLibraryRules.cmake
blob75bc81e2aee8e9a95215c164756372286ad31a33
1 function(collect_object_file_deps target result)
2   # NOTE: This function does add entrypoint targets to |result|.
3   # It is expected that the caller adds them separately.
4   set(all_deps "")
5   get_target_property(target_type ${target} "TARGET_TYPE")
6   if(NOT target_type)
7     return()
8   endif()
10   if(${target_type} STREQUAL ${OBJECT_LIBRARY_TARGET_TYPE})
11     list(APPEND all_deps ${target})
12     get_target_property(deps ${target} "DEPS")
13     foreach(dep IN LISTS deps)
14       collect_object_file_deps(${dep} dep_targets)
15       list(APPEND all_deps ${dep_targets})
16     endforeach(dep)
17     list(REMOVE_DUPLICATES all_deps)
18     set(${result} ${all_deps} PARENT_SCOPE)
19     return()
20   endif()
22   if(${target_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR
23      ${target_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})
24     set(entrypoint_target ${target})
25     get_target_property(is_alias ${entrypoint_target} "IS_ALIAS")
26     if(is_alias)
27       get_target_property(aliasee ${entrypoint_target} "DEPS")
28       if(NOT aliasee)
29         message(FATAL_ERROR
30                 "Entrypoint alias ${entrypoint_target} does not have an aliasee.")
31       endif()
32       set(entrypoint_target ${aliasee})
33     endif()
34     get_target_property(deps ${target} "DEPS")
35     foreach(dep IN LISTS deps)
36       collect_object_file_deps(${dep} dep_targets)
37       list(APPEND all_deps ${dep_targets})
38     endforeach(dep)
39     list(REMOVE_DUPLICATES all_deps)
40     set(${result} ${all_deps} PARENT_SCOPE)
41     return()
42   endif()
44   if(${target_type} STREQUAL ${ENTRYPOINT_EXT_TARGET_TYPE})
45     # It is not possible to recursively extract deps of external dependencies.
46     # So, we just accumulate the direct dep and return.
47     get_target_property(deps ${target} "DEPS")
48     set(${result} ${deps} PARENT_SCOPE)
49     return()
50   endif()
51 endfunction(collect_object_file_deps)
53 function(get_all_object_file_deps result fq_deps_list)
54   set(all_deps "")
55   foreach(dep ${fq_deps_list})
56     get_target_property(dep_type ${dep} "TARGET_TYPE")
57     if(NOT ((${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE}) OR
58             (${dep_type} STREQUAL ${ENTRYPOINT_EXT_TARGET_TYPE}) OR
59             (${dep_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})))
60       message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is "
61                           "not an 'add_entrypoint_object' or 'add_entrypoint_external' target.")
62     endif()
63     collect_object_file_deps(${dep} recursive_deps)
64     list(APPEND all_deps ${recursive_deps})
65     # Add the entrypoint object target explicitly as collect_object_file_deps
66     # only collects object files from non-entrypoint targets.
67     if(${dep_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE} OR
68        ${dep_type} STREQUAL ${ENTRYPOINT_OBJ_VENDOR_TARGET_TYPE})
69       set(entrypoint_target ${dep})
70       get_target_property(is_alias ${entrypoint_target} "IS_ALIAS")
71       if(is_alias)
72         get_target_property(aliasee ${entrypoint_target} "DEPS")
73         if(NOT aliasee)
74           message(FATAL_ERROR
75                   "Entrypoint alias ${entrypoint_target} does not have an aliasee.")
76         endif()
77         set(entrypoint_target ${aliasee})
78       endif()
79     endif()
80     list(APPEND all_deps ${entrypoint_target})
81   endforeach(dep)
82   list(REMOVE_DUPLICATES all_deps)
83   set(${result} ${all_deps} PARENT_SCOPE)
84 endfunction()
86 # A rule to build a library from a collection of entrypoint objects and bundle
87 # it into a GPU fatbinary. Usage is the same as 'add_entrypoint_library'.
88 # Usage:
89 #     add_gpu_entrypoint_library(
90 #       DEPENDS <list of add_entrypoint_object targets>
91 #     )
92 function(add_gpu_entrypoint_library target_name base_target_name)
93   cmake_parse_arguments(
94     "ENTRYPOINT_LIBRARY"
95     "" # No optional arguments
96     "" # No single value arguments
97     "DEPENDS" # Multi-value arguments
98     ${ARGN}
99   )
100   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
101     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list "
102                         "of 'add_entrypoint_object' targets.")
103   endif()
105   get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS})
106   get_all_object_file_deps(all_deps "${fq_deps_list}")
108   # The GPU 'libc' needs to be exported in a format that can be linked with
109   # offloading langauges like OpenMP or CUDA. This wraps every GPU object into a
110   # fat binary and adds them to a static library.
111   set(objects "")
112   foreach(dep IN LISTS all_deps)
113     set(object $<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${dep}>,${dep}>:$<TARGET_OBJECTS:${dep}>>)
114     string(FIND ${dep} "." last_dot_loc REVERSE)
115     math(EXPR name_loc "${last_dot_loc} + 1")
116     string(SUBSTRING ${dep} ${name_loc} -1 name)
117     if(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
118       set(prefix --image=arch=generic,triple=nvptx64-nvidia-cuda,feature=+ptx63)
119     elseif(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
120       set(prefix --image=arch=generic,triple=amdgcn-amd-amdhsa)
121     endif()
123     # Use the 'clang-offload-packager' to merge these files into a binary blob.
124     add_custom_command(
125       OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/binary/${name}.gpubin"
126       COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/binary
127       COMMAND ${LIBC_CLANG_OFFLOAD_PACKAGER}
128               "${prefix},file=$<JOIN:${object},,file=>" -o
129               ${CMAKE_CURRENT_BINARY_DIR}/binary/${name}.gpubin
130       DEPENDS ${dep} ${base_target_name}
131       COMMENT "Packaging LLVM offloading binary for '${object}'"
132     )
133     add_custom_target(${dep}.__gpubin__ DEPENDS ${dep}
134                       "${CMAKE_CURRENT_BINARY_DIR}/binary/${name}.gpubin")
135     if(TARGET clang-offload-packager)
136       add_dependencies(${dep}.__gpubin__ clang-offload-packager)
137     endif()
139     # CMake does not permit setting the name on object files. In order to have
140     # human readable names we create an empty stub file with the entrypoint
141     # name. This empty file will then have the created binary blob embedded.
142     add_custom_command(
143       OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/stubs/${name}.cpp"
144       COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/stubs
145       COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/stubs/${name}.cpp
146       DEPENDS ${dep} ${dep}.__gpubin__ ${base_target_name}
147     )
148     add_custom_target(${dep}.__stub__
149                       DEPENDS ${dep}.__gpubin__ "${CMAKE_CURRENT_BINARY_DIR}/stubs/${name}.cpp")
151     add_library(${dep}.__fatbin__
152       EXCLUDE_FROM_ALL OBJECT
153       "${CMAKE_CURRENT_BINARY_DIR}/stubs/${name}.cpp"
154     )
156     # This is always compiled for the LLVM host triple instead of the native GPU
157     # triple that is used by default in the build.
158     target_compile_options(${dep}.__fatbin__ BEFORE PRIVATE -nostdlib)
159     target_compile_options(${dep}.__fatbin__ PRIVATE
160       --target=${LLVM_HOST_TRIPLE}
161       "SHELL:-Xclang -fembed-offload-object=${CMAKE_CURRENT_BINARY_DIR}/binary/${name}.gpubin")
162     add_dependencies(${dep}.__fatbin__
163                      ${dep} ${dep}.__stub__ ${dep}.__gpubin__ ${base_target_name})
165     # Set the list of newly create fat binaries containing embedded device code.
166     list(APPEND objects $<TARGET_OBJECTS:${dep}.__fatbin__>)
167   endforeach()
169   add_library(
170     ${target_name}
171     STATIC
172       ${objects}
173   )
174   set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${LIBC_LIBRARY_DIR})
175 endfunction(add_gpu_entrypoint_library)
177 # A rule to build a library from a collection of entrypoint objects and bundle
178 # it in a single LLVM-IR bitcode file.
179 # Usage:
180 #     add_gpu_entrypoint_library(
181 #       DEPENDS <list of add_entrypoint_object targets>
182 #     )
183 function(add_bitcode_entrypoint_library target_name base_target_name)
184   cmake_parse_arguments(
185     "ENTRYPOINT_LIBRARY"
186     "" # No optional arguments
187     "" # No single value arguments
188     "DEPENDS" # Multi-value arguments
189     ${ARGN}
190   )
191   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
192     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list "
193                         "of 'add_entrypoint_object' targets.")
194   endif()
196   get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS})
197   get_all_object_file_deps(all_deps "${fq_deps_list}")
199   set(objects "")
200   foreach(dep IN LISTS all_deps)
201     set(object $<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${dep}>,${dep}>:$<TARGET_OBJECTS:${dep}>>)
202     list(APPEND objects ${object})
203   endforeach()
205   set(output ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.bc)
206   add_custom_command(
207     OUTPUT ${output}
208     COMMAND ${LIBC_LLVM_LINK} ${objects} -o ${output}
209     DEPENDS ${all_deps} ${base_target_name}
210     COMMENT "Linking LLVM-IR bitcode for ${base_target_name}"
211     COMMAND_EXPAND_LISTS
212   )
213   add_custom_target(${target_name} DEPENDS ${output} ${all_deps})
214   set_target_properties(${target_name} PROPERTIES TARGET_OBJECT ${output})
215   if(TARGET llvm-link)
216     add_dependencies(${target_name} llvm-link)
217   endif()
218 endfunction(add_bitcode_entrypoint_library)
220 # A rule to build a library from a collection of entrypoint objects.
221 # Usage:
222 #     add_entrypoint_library(
223 #       DEPENDS <list of add_entrypoint_object targets>
224 #     )
226 # NOTE: If one wants an entrypoint to be available in a library, then they will
227 # have to list the entrypoint target explicitly in the DEPENDS list. Implicit
228 # entrypoint dependencies will not be added to the library.
229 function(add_entrypoint_library target_name)
230   cmake_parse_arguments(
231     "ENTRYPOINT_LIBRARY"
232     "" # No optional arguments
233     "" # No single value arguments
234     "DEPENDS" # Multi-value arguments
235     ${ARGN}
236   )
237   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
238     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list "
239                         "of 'add_entrypoint_object' targets.")
240   endif()
242   get_fq_deps_list(fq_deps_list ${ENTRYPOINT_LIBRARY_DEPENDS})
243   get_all_object_file_deps(all_deps "${fq_deps_list}")
245   set(objects "")
246   foreach(dep IN LISTS all_deps)
247     list(APPEND objects $<$<STREQUAL:$<TARGET_NAME_IF_EXISTS:${dep}>,${dep}>:$<TARGET_OBJECTS:${dep}>>)
248   endforeach(dep)
250   add_library(
251     ${target_name}
252     STATIC
253     ${objects}
254   )
255   set_target_properties(${target_name} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${LIBC_LIBRARY_DIR})
256 endfunction(add_entrypoint_library)
258 # Rule to build a shared library of redirector objects.
259 function(add_redirector_library target_name)
260   cmake_parse_arguments(
261     "REDIRECTOR_LIBRARY"
262     ""
263     ""
264     "DEPENDS"
265     ${ARGN}
266   )
268   set(obj_files "")
269   foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
270     # TODO: Ensure that each dep is actually a add_redirector_object target.
271     list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
272   endforeach(dep)
274   # TODO: Call the linker explicitly instead of calling the compiler driver to
275   # prevent DT_NEEDED on C++ runtime.
276   add_library(
277     ${target_name}
278     EXCLUDE_FROM_ALL
279     SHARED
280     ${obj_files}
281   )
282   set_target_properties(${target_name}  PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${LIBC_LIBRARY_DIR})
283   target_link_libraries(${target_name}  -nostdlib -lc -lm)
284   set_target_properties(${target_name}  PROPERTIES LINKER_LANGUAGE "C")
285 endfunction(add_redirector_library)
287 set(HDR_LIBRARY_TARGET_TYPE "HDR_LIBRARY")
289 # Internal function, used by `add_header_library`.
290 function(create_header_library fq_target_name)
291   cmake_parse_arguments(
292     "ADD_HEADER"
293     "" # Optional arguments
294     "" # Single value arguments
295     "HDRS;DEPENDS;FLAGS;COMPILE_OPTIONS" # Multi-value arguments
296     ${ARGN}
297   )
299   if(NOT ADD_HEADER_HDRS)
300     message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
301   endif()
303   if(SHOW_INTERMEDIATE_OBJECTS)
304     message(STATUS "Adding header library ${fq_target_name}")
305     if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
306       foreach(dep IN LISTS ADD_HEADER_DEPENDS)
307         message(STATUS "  ${fq_target_name} depends on ${dep}")
308       endforeach()
309     endif()
310   endif()
312   add_library(${fq_target_name} INTERFACE)
313   target_sources(${fq_target_name} INTERFACE ${ADD_HEADER_HDRS})
314   if(ADD_HEADER_DEPENDS)
315     add_dependencies(${fq_target_name} ${ADD_HEADER_DEPENDS})
317     # `*.__copied_hdr__` is created only to copy the header files to the target
318     # location, not to be linked against.
319     set(link_lib "")
320     foreach(dep ${ADD_HEADER_DEPENDS})
321       if (NOT dep MATCHES "__copied_hdr__")
322         list(APPEND link_lib ${dep})
323       endif()
324     endforeach()
326     target_link_libraries(${fq_target_name} INTERFACE ${link_lib})
327   endif()
328   if(ADD_HEADER_COMPILE_OPTIONS)
329     target_compile_options(${fq_target_name} INTERFACE ${ADD_HEADER_COMPILE_OPTIONS})
330   endif()
331   set_target_properties(
332     ${fq_target_name}
333     PROPERTIES
334       INTERFACE_FLAGS "${ADD_HEADER_FLAGS}"
335       TARGET_TYPE "${HDR_LIBRARY_TARGET_TYPE}"
336       DEPS "${ADD_HEADER_DEPENDS}"
337       FLAGS "${ADD_HEADER_FLAGS}"
338   )
339 endfunction(create_header_library)
341 # Rule to add header only libraries.
342 # Usage
343 #    add_header_library(
344 #      <target name>
345 #      HDRS  <list of .h files part of the library>
346 #      DEPENDS <list of dependencies>
347 #      FLAGS <list of flags>
348 #    )
350 function(add_header_library target_name)
351   add_target_with_flags(
352     ${target_name}
353     CREATE_TARGET create_header_library
354     ${ARGN}
355   )
356 endfunction(add_header_library)