1set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY")
2
3function(_get_common_compile_options output_var)
4  set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT} ${ARGN})
5  if(NOT ${LIBC_TARGET_OS} STREQUAL "windows")
6    set(compile_options ${compile_options} -fpie -ffreestanding -fno-builtin)
7  endif()
8  if(LLVM_COMPILER_IS_GCC_COMPATIBLE)
9    list(APPEND compile_options "-fno-exceptions")
10    list(APPEND compile_options "-fno-unwind-tables")
11    list(APPEND compile_options "-fno-asynchronous-unwind-tables")
12    list(APPEND compile_options "-fno-rtti")
13  elseif(MSVC)
14    list(APPEND compile_options "/EHs-c-")
15    list(APPEND compile_options "/GR-")
16  endif()
17  set(${output_var} ${compile_options} PARENT_SCOPE)
18endfunction()
19
20# Rule which is essentially a wrapper over add_library to compile a set of
21# sources to object files.
22# Usage:
23#     add_object_library(
24#       <target_name>
25#       HDRS <list of header files>
26#       SRCS <list of source files>
27#       DEPENDS <list of dependencies>
28#       COMPILE_OPTIONS <optional list of special compile options for this target>
29#       FLAGS <optional list of flags>
30function(create_object_library fq_target_name)
31  cmake_parse_arguments(
32    "ADD_OBJECT"
33    "" # No optional arguments
34    "CXX_STANDARD" # Single value arguments
35    "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments
36    ${ARGN}
37  )
38
39  if(NOT ADD_OBJECT_SRCS)
40    message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.")
41  endif()
42
43  add_library(
44    ${fq_target_name}
45    EXCLUDE_FROM_ALL
46    OBJECT
47    ${ADD_OBJECT_SRCS}
48    ${ADD_OBJECT_HDRS}
49  )
50  target_include_directories(
51    ${fq_target_name}
52    PRIVATE
53      ${LIBC_BUILD_DIR}/include
54      ${LIBC_SOURCE_DIR}
55      ${LIBC_BUILD_DIR}
56  )
57  _get_common_compile_options(compile_options ${ADD_OBJECT_COMPILE_OPTIONS})
58  target_compile_options(${fq_target_name} PRIVATE ${compile_options})
59
60  get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS})
61
62  if(SHOW_INTERMEDIATE_OBJECTS)
63    message(STATUS "Adding object library ${fq_target_name}")
64    if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
65      foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
66        message(STATUS "  ${fq_target_name} depends on ${dep}")
67      endforeach()
68    endif()
69  endif()
70
71  if(fq_deps_list)
72    add_dependencies(${fq_target_name} ${fq_deps_list})
73  endif()
74
75  if(NOT ADD_OBJECT_CXX_STANDARD)
76    set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
77  endif()
78
79  set_target_properties(
80    ${fq_target_name}
81    PROPERTIES
82      TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE}
83      OBJECT_FILES "$<TARGET_OBJECTS:${fq_target_name}>"
84      CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD}
85      DEPS "${fq_deps_list}"
86      FLAGS "${ADD_OBJECT_FLAGS}"
87  )
88endfunction(create_object_library)
89
90# Internal function, used by `add_object_library`.
91function(expand_flags_for_object_library target_name flags)
92  cmake_parse_arguments(
93    "EXPAND_FLAGS"
94    "IGNORE_MARKER" # Optional arguments
95    "" # Single-value arguments
96    "DEPENDS;FLAGS" # Multi-value arguments
97    ${ARGN}
98  )
99
100  list(LENGTH flags nflags)
101  if(NOT ${nflags})
102    create_object_library(
103      ${target_name}
104      DEPENDS ${EXPAND_FLAGS_DEPENDS}
105      FLAGS ${EXPAND_FLAGS_FLAGS}
106      ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
107    )
108    return()
109  endif()
110
111  list(POP_FRONT flags flag)
112  extract_flag_modifier(${flag} real_flag modifier)
113
114  if(NOT "${modifier}" STREQUAL "NO")
115    expand_flags_for_object_library(
116      ${target_name}
117      "${flags}"
118      DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
119      FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
120      "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
121    )
122  endif()
123
124  if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
125    return()
126  endif()
127
128  set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
129  list(REMOVE_ITEM NEW_FLAGS ${flag})
130  get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
131
132  # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
133  # `flag__ONLY` do not.
134  if(NOT "${modifier}")
135    set(TARGET_NAME "${target_name}.__NO_${flag}")
136  else()
137    set(TARGET_NAME "${target_name}")
138  endif()
139
140  expand_flags_for_object_library(
141    ${TARGET_NAME}
142    "${flags}"
143    DEPENDS "${NEW_DEPS}" IGNORE_MARKER
144    FLAGS "${NEW_FLAGS}" IGNORE_MARKER
145    "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
146  )
147endfunction(expand_flags_for_object_library)
148
149function(add_object_library target_name)
150  cmake_parse_arguments(
151    "ADD_TO_EXPAND"
152    "" # Optional arguments
153    "" # Single value arguments
154    "DEPENDS;FLAGS" # Multi-value arguments
155    ${ARGN}
156  )
157
158  get_fq_target_name(${target_name} fq_target_name)
159
160  if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
161    message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
162  endif()
163
164  get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
165  get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
166
167  list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
168  remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
169  list(SORT flags)
170
171  if(SHOW_INTERMEDIATE_OBJECTS AND flags)
172    message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}")
173  endif()
174
175  expand_flags_for_object_library(
176    ${fq_target_name}
177    "${flags}"
178    DEPENDS "${fq_deps_list}" IGNORE_MARKER
179    FLAGS "${flags}" IGNORE_MARKER
180    ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
181  )
182endfunction(add_object_library)
183
184set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
185
186# A rule for entrypoint object targets.
187# Usage:
188#     add_entrypoint_object(
189#       <target_name>
190#       [ALIAS|REDIRECTED] # Specified if the entrypoint is redirected or an alias.
191#       [NAME] <the C name of the entrypoint if different from target_name>
192#       SRCS <list of .cpp files>
193#       HDRS <list of .h files>
194#       DEPENDS <list of dependencies>
195#       COMPILE_OPTIONS <optional list of special compile options for this target>
196#       SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`>
197#       FLAGS <optional list of flags>
198#     )
199function(create_entrypoint_object fq_target_name)
200  cmake_parse_arguments(
201    "ADD_ENTRYPOINT_OBJ"
202    "ALIAS;REDIRECTED" # Optional argument
203    "NAME;CXX_STANDARD" # Single value arguments
204    "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS"  # Multi value arguments
205    ${ARGN}
206  )
207
208  list(FIND TARGET_ENTRYPOINT_NAME_LIST ${ADD_ENTRYPOINT_OBJ_NAME} entrypoint_name_index)
209  if(${entrypoint_name_index} EQUAL -1)
210    add_custom_target(${fq_target_name})
211    set_target_properties(
212      ${fq_target_name}
213      PROPERTIES
214        "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME}
215        "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE}
216        "OBJECT_FILE" ""
217        "OBJECT_FILE_RAW" ""
218        "DEPS" ""
219        "SKIPPED" "YES"
220    )
221    message(STATUS "Skipping libc entrypoint ${fq_target_name}.")
222    return()
223  endif()
224
225  if(ADD_ENTRYPOINT_OBJ_ALIAS)
226    # Alias targets help one add aliases to other entrypoint object targets.
227    # One can use alias targets setup OS/machine independent entrypoint targets.
228    list(LENGTH ADD_ENTRYPOINT_OBJ_DEPENDS deps_size)
229    if(NOT (${deps_size} EQUAL "1"))
230      message(FATAL_ERROR "An entrypoint alias should have exactly one dependency.")
231    endif()
232    list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target)
233    get_fq_dep_name(fq_dep_name ${dep_target})
234
235    if(SHOW_INTERMEDIATE_OBJECTS)
236      message(STATUS "Adding entrypoint object ${fq_target_name} as an alias of"
237              " ${fq_dep_name}")
238    endif()
239
240    if(NOT TARGET ${fq_dep_name})
241      message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; "
242                      "Target ${target_name} will be ignored.")
243      return()
244    endif()
245
246    get_target_property(obj_type ${fq_dep_name} "TARGET_TYPE")
247    if((NOT obj_type) OR (NOT (${obj_type} STREQUAL ${ENTRYPOINT_OBJ_TARGET_TYPE})))
248      message(FATAL_ERROR "The aliasee of an entrypoint alias should be an entrypoint.")
249    endif()
250
251    add_custom_target(${fq_target_name})
252    add_dependencies(${fq_target_name} ${fq_dep_name})
253    get_target_property(object_file ${fq_dep_name} "OBJECT_FILE")
254    get_target_property(object_file_raw ${fq_dep_name} "OBJECT_FILE_RAW")
255    set_target_properties(
256      ${fq_target_name}
257      PROPERTIES
258        ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
259        TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE}
260        IS_ALIAS "YES"
261        OBJECT_FILE ""
262        OBJECT_FILE_RAW ""
263        DEPS "${fq_dep_name}"
264        FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
265    )
266    return()
267  endif()
268
269  if(NOT ADD_ENTRYPOINT_OBJ_SRCS)
270    message(FATAL_ERROR "`add_entrypoint_object` rule requires SRCS to be specified.")
271  endif()
272  if(NOT ADD_ENTRYPOINT_OBJ_HDRS)
273    message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.")
274  endif()
275  if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD)
276    set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD})
277  endif()
278
279  _get_common_compile_options(common_compile_options ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS})
280  set(internal_target_name ${fq_target_name}.__internal__)
281  set(include_dirs ${LIBC_BUILD_DIR}/include ${LIBC_SOURCE_DIR} ${LIBC_BUILD_DIR})
282  get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS})
283  set(full_deps_list ${fq_deps_list} libc.src.__support.common)
284
285  if(SHOW_INTERMEDIATE_OBJECTS)
286    message(STATUS "Adding entrypoint object ${fq_target_name}")
287    if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS")
288      foreach(dep IN LISTS ADD_OBJECT_DEPENDS)
289        message(STATUS "  ${fq_target_name} depends on ${dep}")
290      endforeach()
291    endif()
292  endif()
293
294  add_library(
295    ${internal_target_name}
296    # TODO: We don't need an object library for internal consumption.
297    # A future change should switch this to a normal static library.
298    EXCLUDE_FROM_ALL
299    OBJECT
300    ${ADD_ENTRYPOINT_OBJ_SRCS}
301    ${ADD_ENTRYPOINT_OBJ_HDRS}
302  )
303  target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options})
304  target_include_directories(${internal_target_name} PRIVATE ${include_dirs})
305  add_dependencies(${internal_target_name} ${full_deps_list})
306  set_target_properties(
307    ${internal_target_name}
308    PROPERTIES
309      CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
310      FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
311  )
312
313  add_library(
314    ${fq_target_name}
315    # We want an object library as the objects will eventually get packaged into
316    # an archive (like libc.a).
317    EXCLUDE_FROM_ALL
318    OBJECT
319    ${ADD_ENTRYPOINT_OBJ_SRCS}
320    ${ADD_ENTRYPOINT_OBJ_HDRS}
321  )
322  target_compile_options(${fq_target_name} BEFORE PRIVATE ${common_compile_options} -DLLVM_LIBC_PUBLIC_PACKAGING)
323  target_include_directories(${fq_target_name} PRIVATE ${include_dirs})
324  add_dependencies(${fq_target_name} ${full_deps_list})
325
326  set_target_properties(
327    ${fq_target_name}
328    PROPERTIES
329      ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME}
330      TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE}
331      OBJECT_FILE "$<TARGET_OBJECTS:${fq_target_name}>"
332      # TODO: We don't need to list internal object files if the internal
333      # target is a normal static library.
334      OBJECT_FILE_RAW "$<TARGET_OBJECTS:${internal_target_name}>"
335      CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD}
336      DEPS "${fq_deps_list}"
337      FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}"
338  )
339
340  if(LLVM_LIBC_ENABLE_LINTING)
341    if(NOT LLVM_LIBC_CLANG_TIDY)
342      message(FATAL_ERROR "Something is wrong!  LLVM_LIBC_ENABLE_LINTING is "
343              "ON but LLVM_LIBC_CLANG_TIDY is not set.")
344    endif()
345
346    # We only want a second invocation of clang-tidy to run
347    # restrict-system-libc-headers if the compiler-resource-dir was set in
348    # order to prevent false-positives due to a mismatch between the host
349    # compiler and the compiled clang-tidy.
350    if(COMPILER_RESOURCE_DIR)
351      # We run restrict-system-libc-headers with --system-headers to prevent
352      # transitive inclusion through compler provided headers.
353      set(restrict_system_headers_check_invocation
354        COMMAND ${LLVM_LIBC_CLANG_TIDY} --system-headers
355        --checks="-*,llvmlibc-restrict-system-libc-headers"
356        # We explicitly set the resource dir here to match the
357        # resource dir of the host compiler.
358        "--extra-arg=-resource-dir=${COMPILER_RESOURCE_DIR}"
359        --quiet
360        -p ${PROJECT_BINARY_DIR}
361        ${ADD_ENTRYPOINT_OBJ_SRCS}
362      )
363    else()
364      set(restrict_system_headers_check_invocation
365        COMMAND ${CMAKE_COMMAND} -E echo "Header file check skipped")
366    endif()
367
368    set(lint_timestamp "${CMAKE_CURRENT_BINARY_DIR}/.${target_name}.__lint_timestamp__")
369    add_custom_command(
370      OUTPUT ${lint_timestamp}
371      # --quiet is used to surpress warning statistics from clang-tidy like:
372      #     Suppressed X warnings (X in non-user code).
373      # There seems to be a bug in clang-tidy where by even with --quiet some
374      # messages from clang's own diagnostics engine leak through:
375      #     X warnings generated.
376      # Until this is fixed upstream, we use -fno-caret-diagnostics to surpress
377      # these.
378      COMMAND ${LLVM_LIBC_CLANG_TIDY}
379              "--extra-arg=-fno-caret-diagnostics" --quiet
380              # Path to directory containing compile_commands.json
381              -p ${PROJECT_BINARY_DIR}
382              ${ADD_ENTRYPOINT_OBJ_SRCS}
383      # See above: this might be a second invocation of clang-tidy depending on
384      # the conditions above.
385      ${restrict_system_headers_check_invocation}
386      # We have two options for running commands, add_custom_command and
387      # add_custom_target. We don't want to run the linter unless source files
388      # have changed. add_custom_target explicitly runs everytime therefore we
389      # use add_custom_command. This function requires an output file and since
390      # linting doesn't produce a file, we create a dummy file using a
391      # crossplatform touch.
392      COMMAND "${CMAKE_COMMAND}" -E touch ${lint_timestamp}
393      COMMENT "Linting... ${target_name}"
394      DEPENDS clang-tidy ${internal_target_name} ${ADD_ENTRYPOINT_OBJ_SRCS}
395      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
396    )
397  endif()
398
399endfunction(create_entrypoint_object)
400
401# Internal function, used by `add_entrypoint_object`.
402function(expand_flags_for_entrypoint_object target_name flags)
403  cmake_parse_arguments(
404    "EXPAND_FLAGS"
405    "IGNORE_MARKER" # Optional arguments
406    "" # Single-value arguments
407    "DEPENDS;FLAGS" # Multi-value arguments
408    ${ARGN}
409  )
410
411  list(LENGTH flags nflags)
412  if(NOT ${nflags})
413    create_entrypoint_object(
414      ${target_name}
415      DEPENDS ${EXPAND_FLAGS_DEPENDS}
416      FLAGS ${EXPAND_FLAGS_FLAGS}
417      ${EXPAND_FLAGS_UNPARSED_ARGUMENTS}
418    )
419    return()
420  endif()
421
422  list(POP_FRONT flags flag)
423  extract_flag_modifier(${flag} real_flag modifier)
424
425  if(NOT "${modifier}" STREQUAL "NO")
426    expand_flags_for_entrypoint_object(
427      ${target_name}
428      "${flags}"
429      DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER
430      FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER
431      "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
432    )
433  endif()
434
435  if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY")
436    return()
437  endif()
438
439  set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS})
440  list(REMOVE_ITEM NEW_FLAGS ${flag})
441  get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS})
442
443  # Only target with `flag` has `.__NO_flag` target, `flag__NO` and
444  # `flag__ONLY` do not.
445  if(NOT "${modifier}")
446    set(TARGET_NAME "${target_name}.__NO_${flag}")
447  else()
448    set(TARGET_NAME "${target_name}")
449  endif()
450
451  expand_flags_for_entrypoint_object(
452    ${TARGET_NAME}
453    "${flags}"
454    DEPENDS "${NEW_DEPS}" IGNORE_MARKER
455    FLAGS "${NEW_FLAGS}" IGNORE_MARKER
456    "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}"
457  )
458endfunction(expand_flags_for_entrypoint_object)
459
460function(add_entrypoint_object target_name)
461  cmake_parse_arguments(
462    "ADD_TO_EXPAND"
463    "" # Optional arguments
464    "NAME" # Single value arguments
465    "DEPENDS;FLAGS" # Multi-value arguments
466    ${ARGN}
467  )
468
469  get_fq_target_name(${target_name} fq_target_name)
470
471  if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS"))
472    message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}")
473  endif()
474
475  get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS})
476  get_flags_from_dep_list(deps_flag_list ${fq_deps_list})
477
478  list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list})
479  remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags)
480  list(SORT flags)
481
482  if(SHOW_INTERMEDIATE_OBJECTS AND flags)
483    message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}")
484  endif()
485
486  if(NOT ADD_TO_EXPAND_NAME)
487    set(ADD_TO_EXPAND_NAME ${target_name})
488  endif()
489
490  expand_flags_for_entrypoint_object(
491    ${fq_target_name}
492    "${flags}"
493    NAME ${ADD_TO_EXPAND_NAME} IGNORE_MARKER
494    DEPENDS "${fq_deps_list}" IGNORE_MARKER
495    FLAGS "${flags}" IGNORE_MARKER
496    ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS}
497  )
498endfunction(add_entrypoint_object)
499
500set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT")
501
502# A rule for external entrypoint targets.
503# Usage:
504#     add_entrypoint_external(
505#       <target_name>
506#       DEPENDS <list of dependencies>
507#     )
508function(add_entrypoint_external target_name)
509  cmake_parse_arguments(
510    "ADD_ENTRYPOINT_EXT"
511    "" # No optional arguments
512    "" # No single value arguments
513    "DEPENDS"  # Multi value arguments
514    ${ARGN}
515  )
516  get_fq_target_name(${target_name} fq_target_name)
517  set(entrypoint_name ${target_name})
518
519  add_custom_target(${fq_target_name})
520  set_target_properties(
521    ${fq_target_name}
522    PROPERTIES
523      "ENTRYPOINT_NAME" ${entrypoint_name}
524      "TARGET_TYPE" ${ENTRYPOINT_EXT_TARGET_TYPE}
525      "DEPS" "${ADD_ENTRYPOINT_EXT_DEPENDS}"
526  )
527
528endfunction(add_entrypoint_external)
529
530# Rule build a redirector object file.
531function(add_redirector_object target_name)
532  cmake_parse_arguments(
533    "REDIRECTOR_OBJECT"
534    "" # No optional arguments
535    "SRC" # The cpp file in which the redirector is defined.
536    "" # No multivalue arguments
537    ${ARGN}
538  )
539  if(NOT REDIRECTOR_OBJECT_SRC)
540    message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.")
541  endif()
542
543  add_library(
544    ${target_name}
545    EXCLUDE_FROM_ALL
546    OBJECT
547    ${REDIRECTOR_OBJECT_SRC}
548  )
549  target_compile_options(
550    ${target_name}
551    BEFORE PRIVATE -fPIC ${LIBC_COMPILE_OPTIONS_DEFAULT}
552  )
553endfunction(add_redirector_object)
554