[clang] Avoid linking libdl unless needed
[llvm-project.git] / libc / cmake / modules / LLVMLibCObjectRules.cmake
blob898831ca6818f7633d31b4131d2dcc100074d27f
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 #       DEPENDS <list of dependencies>
11 #       COMPILE_OPTIONS <optional list of special compile options for this target>
12 function(add_object_library target_name)
13   cmake_parse_arguments(
14     "ADD_OBJECT"
15     "" # No option arguments
16     "" # Single value arguments
17     "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments
18     ${ARGN}
19   )
21   if(NOT ADD_OBJECT_SRCS)
22     message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
23   endif()
25   get_fq_target_name(${target_name} fq_target_name)
26   add_library(
27     ${fq_target_name}
28     OBJECT
29     ${ADD_OBJECT_SRCS}
30     ${ADD_OBJECT_HDRS}
31   )
32   target_include_directories(
33     ${fq_target_name}
34     PRIVATE
35       ${LIBC_BUILD_DIR}/include
36       ${LIBC_SOURCE_DIR}
37       ${LIBC_BUILD_DIR}
38   )
39   if(ADD_OBJECT_COMPILE_OPTIONS)
40     target_compile_options(
41       ${fq_target_name}
42       PRIVATE ${ADD_OBJECT_COMPILE_OPTIONS}
43     )
44   endif()
46   get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
47   if(fq_deps_list)
48     add_dependencies(${fq_target_name} ${fq_deps_list})
49   endif()
51   set_target_properties(
52     ${fq_target_name}
53     PROPERTIES
54       "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE}
55       "OBJECT_FILES" "$<TARGET_OBJECTS:${fq_target_name}>"
56       "DEPS" "${fq_deps_list}"
57   )
58 endfunction(add_object_library)
60 set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
62 # A rule for entrypoint object targets.
63 # Usage:
64 #     add_entrypoint_object(
65 #       <target_name>
66 #       [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
67 #       [NAME] <the C name of the entrypoint if different from target_name>
68 #       SRCS <list of .cpp files>
69 #       HDRS <list of .h files>
70 #       DEPENDS <list of dependencies>
71 #       COMPILE_OPTIONS <optional list of special compile options for this target>
72 #       SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
73 #     )
74 function(add_entrypoint_object target_name)
75   cmake_parse_arguments(
76     "ADD_ENTRYPOINT_OBJ"
77     "ALIAS;REDIRECTED" # Optional argument
78     "NAME" # Single value arguments
79     "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS"  # Multi value arguments
80     ${ARGN}
81   )
83   get_fq_target_name(${target_name} fq_target_name)
85   if(ADD_ENTRYPOINT_OBJ_ALIAS)
86     # Alias targets help one add aliases to other entrypoint object targets.
87     # One can use alias targets setup OS/machine independent entrypoint targets.
88     list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
89     if(NOT (${deps_size} EQUAL "1"))
90       message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
91     endif()
92     list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
93     get_fq_dep_name(fq_dep_name ${dep_target})
94     if(NOT TARGET ${fq_dep_name})
95       message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
96                       "Target ${target_name} will be ignored.")
97       return()
98     endif()
100     get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
101     if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})))
102       message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
103     endif()
105     add_custom_target(${fq_target_name})
106     add_dependencies(${fq_target_name} ${fq_dep_name})
107     get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
108     get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
109     set_target_properties(
110       ${fq_target_name}
111       PROPERTIES
112         "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
113         "IS_ALIAS" "YES"
114         "OBJECT_FILE" ""
115         "OBJECT_FILE_RAW" ""
116         "DEPS" "${fq_dep_name}"
117     )
118     return()
119   endif()
121   if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
122     message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
123   endif()
124   if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
125     message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
126   endif()
128   set(entrypoint_name ${target_name})
129   if(ADD_ENTRYPOINT_OBJ_NAME)
130     set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME})
131   endif()
133   set(objects_target_name "${fq_target_name}_objects")
135   add_library(
136     ${objects_target_name}
137     # We want an object library as the objects will eventually get packaged into
138     # an archive (like libc.a).
139     OBJECT
140     ${ADD_ENTRYPOINT_OBJ_SRCS}
141     ${ADD_ENTRYPOINT_OBJ_HDRS}
142   )
143   target_compile_options(
144     ${objects_target_name}
145     BEFORE
146     PRIVATE
147       -fpie ${LLVM_CXX_STD_default} -ffreestanding
148   )
149   target_include_directories(
150     ${objects_target_name}
151     PRIVATE
152       ${LIBC_BUILD_DIR}/include
153       ${LIBC_SOURCE_DIR}
154       ${LIBC_BUILD_DIR}
155   )
156   get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
157   add_dependencies(
158     ${objects_target_name}
159     libc.src.__support.common
160     ${fq_deps_list}
161   )
163   if(ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS)
164     target_compile_options(
165       ${objects_target_name}
166       PRIVATE ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}
167     )
168   endif()
170   set(object_file_raw "${CMAKE_CURRENT_BINARY_DIR}/${target_name}_raw.o")
171   set(object_file "${CMAKE_CURRENT_BINARY_DIR}/${target_name}.o")
173   set(input_objects $<TARGET_OBJECTS:${objects_target_name}>)
174   add_custom_command(
175     OUTPUT ${object_file_raw}
176     DEPENDS ${input_objects}
177     COMMAND ${CMAKE_LINKER} -r ${input_objects} -o ${object_file_raw}
178   )
180   set(alias_attributes "0,function,global")
181   if(ADD_ENTRYPOINT_OBJ_REDIRECTED)
182     set(alias_attributes "${alias_attributes},hidden")
183   endif()
185   add_custom_command(
186     OUTPUT ${object_file}
187     # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag.
188     DEPENDS ${object_file_raw} ${llvm-objcopy}
189     COMMAND $<TARGET_FILE:llvm-objcopy> --add-symbol
190             "${entrypoint_name}=.llvm.libc.entrypoint.${entrypoint_name}:${alias_attributes}"
191             ${object_file_raw} ${object_file}
192   )
194   add_custom_target(
195     ${fq_target_name}
196     ALL
197     DEPENDS ${object_file}
198   )
199   set_target_properties(
200     ${fq_target_name}
201     PROPERTIES
202       "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
203       "OBJECT_FILE" "${object_file}"
204       "OBJECT_FILE_RAW" "${object_file_raw}"
205       "DEPS" "${fq_deps_list}"
206   )
208   if(LLVM_LIBC_ENABLE_LINTING)
210     # We only want a second invocation of clang-tidy to run
211     # restrict-system-libc-headers if the compiler-resource-dir was set in
212     # order to prevent false-positives due to a mismatch between the host
213     # compiler and the compiled clang-tidy.
214     if(COMPILER_RESOURCE_DIR)
215       # We run restrict-system-libc-headers with --system-headers to prevent
216       # transitive inclusion through compler provided headers.
217       set(restrict_system_headers_check_invocation
218         COMMAND $<TARGET_FILE:clang-tidy> --system-headers
219         --checks="-*,llvmlibc-restrict-system-libc-headers"
220         # We explicitly set the resource dir here to match the
221         # resource dir of the host compiler.
222         "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
223         --quiet
224         -p ${PROJECT_BINARY_DIR}
225         ${ADD_ENTRYPOINT_OBJ_SRCS}
226       )
227     else()
228       set(restrict_system_headers_check_invocation
229         COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
230     endif()
232     set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__")
233     add_custom_command(
234       OUTPUT ${lint_timestamp}
235       # --quiet is used to surpress warning statistics from clang-tidy like:
236       #     Suppressed X warnings (X in non-user code).
237       # There seems to be a bug in clang-tidy where by even with --quiet some
238       # messages from clang's own diagnostics engine leak through:
239       #     X warnings generated.
240       # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
241       # these.
242       COMMAND $<TARGET_FILE:clang-tidy>
243               "--extra-arg=-fno-caret-diagnostics" --quiet
244               # Path to directory containing compile_commands.json
245               -p ${PROJECT_BINARY_DIR}
246               ${ADD_ENTRYPOINT_OBJ_SRCS}
247       # See above: this might be a second invocation of clang-tidy depending on
248       # the conditions above.
249       ${restrict_system_headers_check_invocation}
250       # We have two options for running commands, add_custom_command and
251       # add_custom_target. We don't want to run the linter unless source files
252       # have changed. add_custom_target explicitly runs everytime therefore we
253       # use add_custom_command. This function requires an output file and since
254       # linting doesn't produce a file, we create a dummy file using a
255       # crossplatform touch.
256       COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp}
257       COMMENT "Linting... ${target_name}"
258       DEPENDS ${clang-tidy} ${objects_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
259       WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
260     )
262     add_custom_target(${fq_target_name}.__lint__
263       DEPENDS ${lint_timestamp})
264     add_dependencies(lint-libc ${fq_target_name}.__lint__)
265     add_dependencies(${fq_target_name} ${fq_target_name}.__lint__)
266   endif()
268 endfunction(add_entrypoint_object)
270 # Rule build a redirector object file.
271 function(add_redirector_object target_name)
272   cmake_parse_arguments(
273     "REDIRECTOR_OBJECT"
274     "" # No optional arguments
275     "SRC" # The cpp file in which the redirector is defined.
276     "" # No multivalue arguments
277     ${ARGN}
278   )
279   if(NOT REDIRECTOR_OBJECT_SRC)
280     message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
281   endif()
283   add_library(
284     ${target_name}
285     OBJECT
286     ${REDIRECTOR_OBJECT_SRC}
287   )
288   target_compile_options(
289     ${target_name}
290     BEFORE PRIVATE -fPIC
291   )
292 endfunction(add_redirector_object)