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