[libc] Add an optional `NAME` argument to `add_entrypoint_object` rule.
[lldb.git] / libc / cmake / modules / LLVMLibCRules.cmake
1
2 # A rule for self contained header file targets.
3 # This rule merely copies the header file from the current source directory to
4 # the current binary directory.
5 # Usage:
6 #     add_header(
7 #       <target name>
8 #       HDR <header file>
9 #     )
10 function(add_header target_name)
11   cmake_parse_arguments(
12     "ADD_HEADER"
13     ""    # No optional arguments
14     "HDR" # Single value arguments
15     "DEPENDS"    # No multi value arguments
16     ${ARGN}
17   )
18   if(NOT ADD_HEADER_HDR)
19     message(FATAL_ERROR "'add_header' rules requires the HDR argument specifying a headef file.")
20   endif()
21
22   set(dest_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_HEADER_HDR})
23   set(src_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_HEADER_HDR})
24
25   add_custom_command(
26     OUTPUT ${dest_file}
27     COMMAND cp ${src_file} ${dest_file}
28     DEPENDS ${src_file}
29   )
30
31   add_custom_target(
32     ${target_name}
33     DEPENDS ${dest_file}
34   )
35
36   if(ADD_HEADER_DEPENDS)
37   add_dependencies(
38     ${target_name} ${ADD_HEADER_DEPENDS}
39   )
40   endif()
41 endfunction(add_header)
42
43 # A rule for generated header file targets.
44 # Usage:
45 #     add_gen_header(
46 #       <target name>
47 #       DEF_FILE <.h.def file>
48 #       GEN_HDR <generated header file name>
49 #       PARAMS <list of name=value pairs>
50 #       DATA_FILES <list input data files>
51 #     )
52 function(add_gen_header target_name)
53   cmake_parse_arguments(
54     "ADD_GEN_HDR"
55     "" # No optional arguments
56     "DEF_FILE;GEN_HDR" # Single value arguments
57     "PARAMS;DATA_FILES;DEPENDS"     # Multi value arguments
58     ${ARGN}
59   )
60   if(NOT ADD_GEN_HDR_DEF_FILE)
61     message(FATAL_ERROR "`add_gen_hdr` rule requires DEF_FILE to be specified.")
62   endif()
63   if(NOT ADD_GEN_HDR_GEN_HDR)
64     message(FATAL_ERROR "`add_gen_hdr` rule requires GEN_HDR to be specified.")
65   endif()
66
67   set(out_file ${CMAKE_CURRENT_BINARY_DIR}/${ADD_GEN_HDR_GEN_HDR})
68   set(in_file ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_GEN_HDR_DEF_FILE})
69
70   set(fq_data_files "")
71   if(ADD_GEN_HDR_DATA_FILES)
72     foreach(data_file IN LISTS ADD_GEN_HDR_DATA_FILES)
73       list(APPEND fq_data_files "${CMAKE_CURRENT_SOURCE_DIR}/${data_file}")
74     endforeach(data_file)
75   endif()
76
77   set(replacement_params "")
78   if(ADD_GEN_HDR_PARAMS)
79     list(APPEND replacement_params "--args" ${ADD_GEN_HDR_PARAMS})
80   endif()
81
82   set(gen_hdr_script "${LIBC_BUILD_SCRIPTS_DIR}/gen_hdr.py")
83
84   add_custom_command(
85     OUTPUT ${out_file}
86     COMMAND $<TARGET_FILE:libc-hdrgen> -o ${out_file} --header ${ADD_GEN_HDR_GEN_HDR} --def ${in_file} ${replacement_params} -I ${LIBC_SOURCE_DIR} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td
87     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
88     DEPENDS ${in_file} ${fq_data_files} ${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/api.td libc-hdrgen
89   )
90
91   add_custom_target(
92     ${target_name}
93     DEPENDS ${out_file} ${ADD_GEN_HDR_DEPENDS}
94   )
95 endfunction(add_gen_header)
96
97 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
98
99 # A rule for entrypoint object targets.
100 # Usage:
101 #     add_entrypoint_object(
102 #       <target_name>
103 #       [REDIRECTED] # Specified if the entrypoint is redirected.
104 #       [NAME] <the C name of the entrypoint if different from target_name>
105 #       SRCS <list of .cpp files>
106 #       HDRS <list of .h files>
107 #       DEPENDS <list of dependencies>
108 #     )
109 function(add_entrypoint_object target_name)
110   cmake_parse_arguments(
111     "ADD_ENTRYPOINT_OBJ"
112     "REDIRECTED" # Optional argument
113     "NAME" # Single value arguments
114     "SRCS;HDRS;DEPENDS"  # Multi value arguments
115     ${ARGN}
116   )
117   if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
118     message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
119   endif()
120   if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
121     message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
122   endif()
123
124   set(entrypoint_name ${target_name})
125   if(ADD_ENTRYPOINT_OBJ_NAME)
126     set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME})
127   endif()
128
129   add_library(
130     "${target_name}_objects"
131     # We want an object library as the objects will eventually get packaged into
132     # an archive (like libc.a).
133     OBJECT
134     ${ADD_ENTRYPOINT_OBJ_SRCS}
135     ${ADD_ENTRYPOINT_OBJ_HDRS}
136   )
137   target_compile_options(
138     ${target_name}_objects
139     BEFORE
140     PRIVATE
141       -fpie ${LLVM_CXX_STD_default}
142   )
143   target_include_directories(
144     ${target_name}_objects
145     PRIVATE
146       "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
147   )
148   add_dependencies(
149     ${target_name}_objects
150     support_common_h
151   )
152   if(ADD_ENTRYPOINT_OBJ_DEPENDS)
153     add_dependencies(
154       ${target_name}_objects
155       ${ADD_ENTRYPOINT_OBJ_DEPENDS}
156     )
157   endif()
158
159   set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
160   set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
161
162   add_custom_command(
163     OUTPUT ${object_file_raw}
164     DEPENDS $<TARGET_OBJECTS:${target_name}_objects>
165     COMMAND ${CMAKE_LINKER} -r $<TARGET_OBJECTS:${target_name}_objects> -o ${object_file_raw}
166   )
167
168   set(alias_attributes "0,function,global")
169   if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
170     set(alias_attributes "${alias_attributes},hidden")
171   endif()
172
173   add_custom_command(
174     OUTPUT ${object_file}
175     # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag.
176     DEPENDS ${object_file_raw} ${llvm-objcopy}
177     COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}" ${object_file_raw} ${object_file}
178   )
179
180   add_custom_target(
181     ${target_name}
182     ALL
183     DEPENDS ${object_file}
184   )
185   set_target_properties(
186     ${target_name}
187     PROPERTIES
188       "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
189       "OBJECT_FILE" ${object_file}
190       "OBJECT_FILE_RAW" ${object_file_raw}
191   )
192 endfunction(add_entrypoint_object)
193
194 # A rule to build a library from a collection of entrypoint objects.
195 # Usage:
196 #     add_entrypoint_library(
197 #       DEPENDS <list of add_entrypoint_object targets>
198 #     )
199 function(add_entrypoint_library target_name)
200   cmake_parse_arguments(
201     "ENTRYPOINT_LIBRARY"
202     "" # No optional arguments
203     "" # No single value arguments
204     "DEPENDS" # Multi-value arguments
205     ${ARGN}
206   )
207   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
208     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
209   endif()
210
211   set(obj_list "")
212   foreach(dep IN LISTS ENTRYPOINT_LIBRARY_DEPENDS)
213     get_target_property(dep_type ${dep} "TARGET_TYPE")
214     string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
215     if(NOT dep_is_entrypoint)
216       message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is not an 'add_entrypoint_object' target.")
217     endif()
218     get_target_property(target_obj_file ${dep} "OBJECT_FILE")
219     list(APPEND obj_list "${target_obj_file}")
220   endforeach(dep)
221
222   set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
223   add_custom_command(
224     OUTPUT ${library_file}
225     COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
226     DEPENDS ${obj_list}
227   )
228   add_custom_target(
229     ${target_name}
230     ALL
231     DEPENDS ${library_file}
232   )
233 endfunction(add_entrypoint_library)
234
235 # Rule build a redirector object file.
236 function(add_redirector_object target_name)
237   cmake_parse_arguments(
238     "REDIRECTOR_OBJECT"
239     "" # No optional arguments
240     "SRC" # The cpp file in which the redirector is defined.
241     "" # No multivalue arguments
242     ${ARGN}
243   )
244   if(NOT REDIRECTOR_OBJECT_SRC)
245     message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
246   endif()
247
248   add_library(
249     ${target_name}
250     OBJECT
251     ${REDIRECTOR_OBJECT_SRC}
252   )
253   target_compile_options(
254     ${target_name}
255     BEFORE PRIVATE -fPIC
256   )
257 endfunction(add_redirector_object)
258
259 # Rule to build a shared library of redirector objects.
260 function(add_redirector_library target_name)
261   cmake_parse_arguments(
262     "REDIRECTOR_LIBRARY"
263     ""
264     ""
265     "DEPENDS"
266     ${ARGN}
267   )
268
269   set(obj_files "")
270   foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
271     # TODO: Ensure that each dep is actually a add_redirector_object target.
272     list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
273   endforeach(dep)
274
275   # TODO: Call the linker explicitly instead of calling the compiler driver to
276   # prevent DT_NEEDED on C++ runtime.
277   add_library(
278     ${target_name}
279     SHARED
280     ${obj_files}
281   )
282   set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
283
284   target_link_libraries(
285     ${target_name}
286     -nostdlib -lc -lm
287   )
288
289   set_target_properties(
290     ${target_name}
291     PROPERTIES
292       LINKER_LANGUAGE "C"
293   )
294 endfunction(add_redirector_library)
295
296 # Rule to add a libc unittest.
297 # Usage
298 #    add_libc_unittest(
299 #      <target name>
300 #      SUITE <name of the suite this test belongs to>
301 #      SRCS  <list of .cpp files for the test>
302 #      HDRS  <list of .h files for the test>
303 #      DEPENDS <list of dependencies>
304 #    )
305 function(add_libc_unittest target_name)
306   if(NOT LLVM_INCLUDE_TESTS)
307     return()
308   endif()
309   
310   cmake_parse_arguments(
311     "LIBC_UNITTEST"
312     "" # No optional arguments
313     "SUITE" # Single value arguments
314     "SRCS;HDRS;DEPENDS" # Multi-value arguments
315     ${ARGN}
316   )
317   if(NOT LIBC_UNITTEST_SRCS)
318     message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp files.")
319   endif()
320   if(NOT LIBC_UNITTEST_DEPENDS)
321     message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
322   endif()
323
324   set(library_deps "")
325   foreach(dep IN LISTS LIBC_UNITTEST_DEPENDS)
326     get_target_property(dep_type ${dep} "TARGET_TYPE")
327     if (dep_type)
328       string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
329       if(dep_is_entrypoint)
330         get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
331         list(APPEND library_deps ${obj_file})
332         continue()
333       endif()
334     endif()
335     # TODO: Check if the dep is a normal CMake library target. If yes, then add it
336     # to the list of library_deps.
337   endforeach(dep)
338
339   add_executable(
340     ${target_name}
341     EXCLUDE_FROM_ALL
342     ${LIBC_UNITTEST_SRCS}
343     ${LIBC_UNITTEST_HDRS}
344   )
345   target_include_directories(
346     ${target_name}
347     PRIVATE
348       ${LIBC_SOURCE_DIR}
349       ${LIBC_BUILD_DIR}
350       ${LIBC_BUILD_DIR}/include
351   )
352
353   if(library_deps)
354     target_link_libraries(${target_name} PRIVATE ${library_deps})
355   endif()
356
357   set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
358
359   add_dependencies(
360     ${target_name}
361     ${LIBC_UNITTEST_DEPENDS}
362   )
363
364   target_link_libraries(${target_name} PRIVATE LibcUnitTest libc_test_utils)
365
366   add_custom_command(
367     TARGET ${target_name}
368     POST_BUILD
369     COMMAND $<TARGET_FILE:${target_name}>
370   )
371   if(LIBC_UNITTEST_SUITE)
372     add_dependencies(
373       ${LIBC_UNITTEST_SUITE}
374       ${target_name}
375     )
376   endif()
377 endfunction(add_libc_unittest)
378
379 function(add_libc_testsuite suite_name)
380   add_custom_target(${suite_name})
381   add_dependencies(check-libc ${suite_name})
382 endfunction(add_libc_testsuite)
383
384 # Rule to add a fuzzer test.
385 # Usage
386 #    add_libc_fuzzer(
387 #      <target name>
388 #      SRCS  <list of .cpp files for the test>
389 #      HDRS  <list of .h files for the test>
390 #      DEPENDS <list of dependencies>
391 #    )
392 function(add_libc_fuzzer target_name)
393   cmake_parse_arguments(
394     "LIBC_FUZZER"
395     "" # No optional arguments
396     "" # Single value arguments
397     "SRCS;HDRS;DEPENDS" # Multi-value arguments
398     ${ARGN}
399   )
400   if(NOT LIBC_FUZZER_SRCS)
401     message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp files.")
402   endif()
403   if(NOT LIBC_FUZZER_DEPENDS)
404     message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
405   endif()
406
407   set(library_deps "")
408   foreach(dep IN LISTS LIBC_FUZZER_DEPENDS)
409     get_target_property(dep_type ${dep} "TARGET_TYPE")
410     if (dep_type)
411       string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
412       if(dep_is_entrypoint)
413         get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
414         list(APPEND library_deps ${obj_file})
415         continue()
416       endif()
417     endif()
418     # TODO: Check if the dep is a normal CMake library target. If yes, then add it
419     # to the list of library_deps.
420   endforeach(dep)
421
422   add_executable(
423     ${target_name}
424     EXCLUDE_FROM_ALL
425     ${LIBC_FUZZER_SRCS}
426     ${LIBC_FUZZER_HDRS}
427   )
428   target_include_directories(
429     ${target_name}
430     PRIVATE
431       ${LIBC_SOURCE_DIR}
432       ${LIBC_BUILD_DIR}
433       ${LIBC_BUILD_DIR}/include
434   )
435
436   if(library_deps)
437     target_link_libraries(${target_name} PRIVATE ${library_deps})
438   endif()
439
440   set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
441
442   add_dependencies(
443     ${target_name}
444     ${LIBC_FUZZER_DEPENDS}
445   )
446   add_dependencies(libc-fuzzer ${target_name})
447 endfunction(add_libc_fuzzer)
448
449 # Rule to add header only libraries.
450 # Usage
451 #    add_header_library(
452 #      <target name>
453 #      HDRS  <list of .h files part of the library>
454 #      DEPENDS <list of dependencies>
455 #    )
456 function(add_header_library target_name)
457   cmake_parse_arguments(
458     "ADD_HEADER"
459     "" # No optional arguments
460     "" # No Single value arguments
461     "HDRS;DEPENDS" # Multi-value arguments
462     ${ARGN}
463   )
464
465   if(NOT ADD_HEADER_HDRS)
466     message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
467   endif()
468
469   set(FULL_HDR_PATHS "")
470   # TODO: Remove this foreach block when we can switch to the new
471   # version of the CMake policy CMP0076.
472   foreach(hdr IN LISTS ADD_HEADER_HDRS)
473     list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
474   endforeach()
475
476   set(interface_target_name "${target_name}_header_library__")
477
478   add_library(${interface_target_name} INTERFACE)
479   target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
480   if(ADD_HEADER_DEPENDS)
481     add_dependencies(${interface_target_name} ${ADD_HEADER_DEPENDS})
482   endif()
483
484   add_custom_target(${target_name})
485   add_dependencies(${target_name} ${interface_target_name})
486   set_target_properties(
487     ${target_name}
488     PROPERTIES
489       "TARGET_TYPE" "HDR_LIBRARY"
490   )
491 endfunction(add_header_library)