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