[libc] Add a library of standalone C++ utilities.
[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 #       SRCS <list of .cpp files>
105 #       HDRS <list of .h files>
106 #       DEPENDS <list of dependencies>
107 #     )
108 function(add_entrypoint_object target_name)
109   cmake_parse_arguments(
110     "ADD_ENTRYPOINT_OBJ"
111     "REDIRECTED" # Optional argument
112     "" # No single value arguments
113     "SRCS;HDRS;DEPENDS"  # Multi value arguments
114     ${ARGN}
115   )
116   if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
117     message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
118   endif()
119   if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
120     message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
121   endif()
122
123   add_library(
124     "${target_name}_objects"
125     # We want an object library as the objects will eventually get packaged into
126     # an archive (like libc.a).
127     OBJECT
128     ${ADD_ENTRYPOINT_OBJ_SRCS}
129     ${ADD_ENTRYPOINT_OBJ_HDRS}
130   )
131   target_compile_options(
132     ${target_name}_objects
133     BEFORE
134     PRIVATE
135       -fpie ${LLVM_CXX_STD_default}
136   )
137   target_include_directories(
138     ${target_name}_objects
139     PRIVATE
140       "${LIBC_BUILD_DIR}/include;${LIBC_SOURCE_DIR};${LIBC_BUILD_DIR}"
141   )
142   add_dependencies(
143     ${target_name}_objects
144     support_common_h
145   )
146   if(ADD_ENTRYPOINT_OBJ_DEPENDS)
147     add_dependencies(
148       ${target_name}_objects
149       ${ADD_ENTRYPOINT_OBJ_DEPENDS}
150     )
151   endif()
152
153   set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
154   set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
155
156   add_custom_command(
157     OUTPUT ${object_file_raw}
158     DEPENDS $<TARGET_OBJECTS:${target_name}_objects>
159     COMMAND ${CMAKE_LINKER} -r $<TARGET_OBJECTS:${target_name}_objects> -o ${object_file_raw}
160   )
161
162   set(alias_attributes "0,function,global")
163   if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
164     set(alias_attributes "${alias_attributes},hidden")
165   endif()
166
167   add_custom_command(
168     OUTPUT ${object_file}
169     # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag.
170     DEPENDS ${object_file_raw} ${llvm-objcopy}
171     COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol "${target_name}=.llvm.libc.entrypoint.${target_name}:${alias_attributes}" ${object_file_raw} ${object_file}
172   )
173
174   add_custom_target(
175     ${target_name}
176     ALL
177     DEPENDS ${object_file}
178   )
179   set_target_properties(
180     ${target_name}
181     PROPERTIES
182       "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
183       "OBJECT_FILE" ${object_file}
184       "OBJECT_FILE_RAW" ${object_file_raw}
185   )
186 endfunction(add_entrypoint_object)
187
188 # A rule to build a library from a collection of entrypoint objects.
189 # Usage:
190 #     add_entrypoint_library(
191 #       DEPENDS <list of add_entrypoint_object targets>
192 #     )
193 function(add_entrypoint_library target_name)
194   cmake_parse_arguments(
195     "ENTRYPOINT_LIBRARY"
196     "" # No optional arguments
197     "" # No single value arguments
198     "DEPENDS" # Multi-value arguments
199     ${ARGN}
200   )
201   if(NOT ENTRYPOINT_LIBRARY_DEPENDS)
202     message(FATAL_ERROR "'add_entrypoint_library' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
203   endif()
204
205   set(obj_list "")
206   foreach(dep IN LISTS ENTRYPOINT_LIBRARY_DEPENDS)
207     get_target_property(dep_type ${dep} "TARGET_TYPE")
208     string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
209     if(NOT dep_is_entrypoint)
210       message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_collection' is not an 'add_entrypoint_object' target.")
211     endif()
212     get_target_property(target_obj_file ${dep} "OBJECT_FILE")
213     list(APPEND obj_list "${target_obj_file}")
214   endforeach(dep)
215
216   set(library_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${target_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
217   add_custom_command(
218     OUTPUT ${library_file}
219     COMMAND ${CMAKE_AR} -r ${library_file} ${obj_list}
220     DEPENDS ${obj_list}
221   )
222   add_custom_target(
223     ${target_name}
224     ALL
225     DEPENDS ${library_file}
226   )
227 endfunction(add_entrypoint_library)
228
229 # Rule build a redirector object file.
230 function(add_redirector_object target_name)
231   cmake_parse_arguments(
232     "REDIRECTOR_OBJECT"
233     "" # No optional arguments
234     "SRC" # The cpp file in which the redirector is defined.
235     "" # No multivalue arguments
236     ${ARGN}
237   )
238   if(NOT REDIRECTOR_OBJECT_SRC)
239     message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
240   endif()
241
242   add_library(
243     ${target_name}
244     OBJECT
245     ${REDIRECTOR_OBJECT_SRC}
246   )
247   target_compile_options(
248     ${target_name}
249     BEFORE PRIVATE -fPIC
250   )
251 endfunction(add_redirector_object)
252
253 # Rule to build a shared library of redirector objects.
254 function(add_redirector_library target_name)
255   cmake_parse_arguments(
256     "REDIRECTOR_LIBRARY"
257     ""
258     ""
259     "DEPENDS"
260     ${ARGN}
261   )
262
263   set(obj_files "")
264   foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS)
265     # TODO: Ensure that each dep is actually a add_redirector_object target.
266     list(APPEND obj_files $<TARGET_OBJECTS:${dep}>)
267   endforeach(dep)
268
269   # TODO: Call the linker explicitly instead of calling the compiler driver to
270   # prevent DT_NEEDED on C++ runtime.
271   add_library(
272     ${target_name}
273     SHARED
274     ${obj_files}
275   )
276   set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
277
278   target_link_libraries(
279     ${target_name}
280     -nostdlib -lc -lm
281   )
282
283   set_target_properties(
284     ${target_name}
285     PROPERTIES
286       LINKER_LANGUAGE "C"
287   )
288 endfunction(add_redirector_library)
289
290 # Rule to add a gtest unittest.
291 # Usage
292 #    add_libc_unittest(
293 #      <target name>
294 #      SUITE <name of the suite this test belongs to>
295 #      SRCS  <list of .cpp files for the test>
296 #      HDRS  <list of .h files for the test>
297 #      DEPENDS <list of dependencies>
298 #    )
299 function(add_libc_unittest target_name)
300   if(NOT LLVM_INCLUDE_TESTS)
301     return()
302   endif()
303
304   cmake_parse_arguments(
305     "LIBC_UNITTEST"
306     "" # No optional arguments
307     "SUITE" # Single value arguments
308     "SRCS;HDRS;DEPENDS" # Multi-value arguments
309     ${ARGN}
310   )
311   if(NOT LIBC_UNITTEST_SRCS)
312     message(FATAL_ERROR "'add_libc_unittest' target requires a SRCS list of .cpp files.")
313   endif()
314   if(NOT LIBC_UNITTEST_DEPENDS)
315     message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
316   endif()
317
318   set(library_deps "")
319   foreach(dep IN LISTS LIBC_UNITTEST_DEPENDS)
320     get_target_property(dep_type ${dep} "TARGET_TYPE")
321     if (dep_type)
322       string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
323       if(dep_is_entrypoint)
324         get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
325         list(APPEND library_deps ${obj_file})
326         continue()
327       endif()
328     endif()
329     # TODO: Check if the dep is a normal CMake library target. If yes, then add it
330     # to the list of library_deps.
331   endforeach(dep)
332
333   add_executable(
334     ${target_name}
335     EXCLUDE_FROM_ALL
336     ${LIBC_UNITTEST_SRCS}
337     ${LIBC_UNITTEST_HDRS}
338   )
339   target_include_directories(
340     ${target_name}
341     PRIVATE
342       ${LIBC_SOURCE_DIR}
343       ${LIBC_BUILD_DIR}
344       ${LIBC_BUILD_DIR}/include
345   )
346
347   if(library_deps)
348     target_link_libraries(${target_name} PRIVATE ${library_deps})
349   endif()
350
351   set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
352
353   add_dependencies(
354     ${target_name}
355     ${LIBC_UNITTEST_DEPENDS}
356     gtest
357   )
358
359   target_link_libraries(${target_name} PRIVATE LibcUnitTest)
360
361   add_custom_command(
362     TARGET ${target_name}
363     POST_BUILD
364     COMMAND $<TARGET_FILE:${target_name}>
365   )
366   if(LIBC_UNITTEST_SUITE)
367     add_dependencies(
368       ${LIBC_UNITTEST_SUITE}
369       ${target_name}
370     )
371   endif()
372 endfunction(add_libc_unittest)
373
374 function(add_libc_testsuite suite_name)
375   add_custom_target(${suite_name})
376   add_dependencies(check-libc ${suite_name})
377 endfunction(add_libc_testsuite)
378
379 # Rule to add header only libraries.
380 # Usage
381 #    add_header_library(
382 #      <target name>
383 #      HDRS  <list of .h files part of the library>
384 #      DEPENDS <list of dependencies>
385 #    )
386 function(add_header_library target_name)
387   cmake_parse_arguments(
388     "ADD_HEADER"
389     "" # No optional arguments
390     "" # No Single value arguments
391     "HDRS;DEPENDS" # Multi-value arguments
392     ${ARGN}
393   )
394
395   if(NOT ADD_HEADER_HDRS)
396     message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
397   endif()
398
399   set(FULL_HDR_PATHS "")
400   # TODO: Remove this foreach block when we can switch to the new
401   # version of the CMake policy CMP0076.
402   foreach(hdr IN LISTS ADD_HEADER_HDRS)
403     list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
404   endforeach()
405
406   set(interface_target_name "${target_name}_header_library__")
407
408   add_library(${interface_target_name} INTERFACE)
409   target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
410   if(ADD_HEADER_DEPENDS)
411     add_dependencies(${interface_target_name} ${ADD_HEADER_DEPENDS})
412   endif()
413
414   add_custom_target(${target_name})
415   add_dependencies(${target_name} ${interface_target_name})
416   set_target_properties(
417     ${target_name}
418     PROPERTIES
419       "TARGET_TYPE" "HDR_LIBRARY"
420   )
421 endfunction(add_header_library)