1include(ExternalProject)
2include(CompilerRTUtils)
3include(HandleCompilerRT)
4
5function(set_target_output_directories target output_dir)
6  # For RUNTIME_OUTPUT_DIRECTORY variable, Multi-configuration generators
7  # append a per-configuration subdirectory to the specified directory.
8  # To avoid the appended folder, the configuration specific variable must be
9  # set 'RUNTIME_OUTPUT_DIRECTORY_${CONF}':
10  # RUNTIME_OUTPUT_DIRECTORY_DEBUG, RUNTIME_OUTPUT_DIRECTORY_RELEASE, ...
11  if(CMAKE_CONFIGURATION_TYPES)
12    foreach(build_mode ${CMAKE_CONFIGURATION_TYPES})
13      string(TOUPPER "${build_mode}" CONFIG_SUFFIX)
14      set_target_properties("${target}" PROPERTIES
15          "ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
16          "LIBRARY_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir}
17          "RUNTIME_OUTPUT_DIRECTORY_${CONFIG_SUFFIX}" ${output_dir})
18    endforeach()
19  else()
20    set_target_properties("${target}" PROPERTIES
21        ARCHIVE_OUTPUT_DIRECTORY ${output_dir}
22        LIBRARY_OUTPUT_DIRECTORY ${output_dir}
23        RUNTIME_OUTPUT_DIRECTORY ${output_dir})
24  endif()
25endfunction()
26
27# Tries to add an "object library" target for a given list of OSs and/or
28# architectures with name "<name>.<arch>" for non-Darwin platforms if
29# architecture can be targeted, and "<name>.<os>" for Darwin platforms.
30# add_compiler_rt_object_libraries(<name>
31#                                  OS <os names>
32#                                  ARCHS <architectures>
33#                                  SOURCES <source files>
34#                                  CFLAGS <compile flags>
35#                                  DEFS <compile definitions>
36#                                  DEPS <dependencies>
37#                                  ADDITIONAL_HEADERS <header files>)
38function(add_compiler_rt_object_libraries name)
39  cmake_parse_arguments(LIB "" "" "OS;ARCHS;SOURCES;CFLAGS;DEFS;DEPS;ADDITIONAL_HEADERS"
40    ${ARGN})
41  set(libnames)
42  if(APPLE)
43    foreach(os ${LIB_OS})
44      set(libname "${name}.${os}")
45      set(libnames ${libnames} ${libname})
46      set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS})
47      list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
48    endforeach()
49  else()
50    foreach(arch ${LIB_ARCHS})
51      set(libname "${name}.${arch}")
52      set(libnames ${libnames} ${libname})
53      set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS})
54      if(NOT CAN_TARGET_${arch})
55        message(FATAL_ERROR "Architecture ${arch} can't be targeted")
56        return()
57      endif()
58    endforeach()
59  endif()
60
61  # Add headers to LIB_SOURCES for IDEs
62  compiler_rt_process_sources(LIB_SOURCES
63    ${LIB_SOURCES}
64    ADDITIONAL_HEADERS
65      ${LIB_ADDITIONAL_HEADERS}
66  )
67
68  foreach(libname ${libnames})
69    add_library(${libname} OBJECT ${LIB_SOURCES})
70    if(LIB_DEPS)
71      add_dependencies(${libname} ${LIB_DEPS})
72    endif()
73
74    # Strip out -msse3 if this isn't macOS.
75    set(target_flags ${LIB_CFLAGS})
76    if(APPLE AND NOT "${libname}" MATCHES ".*\.osx.*")
77      list(REMOVE_ITEM target_flags "-msse3")
78    endif()
79
80    # Build the macOS sanitizers with Mac Catalyst support.
81    if (APPLE AND
82        "${COMPILER_RT_ENABLE_MACCATALYST}" AND
83        "${libname}" MATCHES ".*\.osx.*")
84      foreach(arch ${LIB_ARCHS_${libname}})
85        list(APPEND target_flags
86          "SHELL:-target ${arch}-apple-macos${DARWIN_osx_MIN_VER} -darwin-target-variant ${arch}-apple-ios13.1-macabi")
87      endforeach()
88    endif()
89
90    set_target_compile_flags(${libname}
91      ${extra_cflags_${libname}} ${target_flags})
92    set_property(TARGET ${libname} APPEND PROPERTY
93      COMPILE_DEFINITIONS ${LIB_DEFS})
94    set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Libraries")
95    if(APPLE)
96      set_target_properties(${libname} PROPERTIES
97        OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
98    endif()
99  endforeach()
100endfunction()
101
102# Takes a list of object library targets, and a suffix and appends the proper
103# TARGET_OBJECTS string to the output variable.
104# format_object_libs(<output> <suffix> ...)
105macro(format_object_libs output suffix)
106  foreach(lib ${ARGN})
107    list(APPEND ${output} $<TARGET_OBJECTS:${lib}.${suffix}>)
108  endforeach()
109endmacro()
110
111function(add_compiler_rt_component name)
112  add_custom_target(${name})
113  set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT Misc")
114  if(COMMAND runtime_register_component)
115    runtime_register_component(${name})
116  endif()
117  add_dependencies(compiler-rt ${name})
118endfunction()
119
120function(add_asm_sources output)
121  set(${output} ${ARGN} PARENT_SCOPE)
122  # CMake doesn't pass the correct architecture for Apple prior to CMake 3.19. https://gitlab.kitware.com/cmake/cmake/-/issues/20771
123  # MinGW didn't work correctly with assembly prior to CMake 3.17. https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4287 and https://reviews.llvm.org/rGb780df052dd2b246a760d00e00f7de9ebdab9d09
124  # Workaround these two issues by compiling as C.
125  # Same workaround used in libunwind. Also update there if changed here.
126  if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17))
127    set_source_files_properties(${ARGN} PROPERTIES LANGUAGE C)
128  endif()
129endfunction()
130
131macro(set_output_name output name arch)
132  if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
133    set(${output} ${name})
134  else()
135    if(ANDROID AND ${arch} STREQUAL "i386")
136      set(${output} "${name}-i686${COMPILER_RT_OS_SUFFIX}")
137    elseif("${arch}" MATCHES "^arm")
138      if(COMPILER_RT_DEFAULT_TARGET_ONLY)
139        set(triple "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
140      else()
141        set(triple "${LLVM_TARGET_TRIPLE}")
142      endif()
143      # Except for baremetal, when using arch-suffixed runtime library names,
144      # clang only looks for libraries named "arm" or "armhf", see
145      # getArchNameForCompilerRTLib in clang. Therefore, try to inspect both
146      # the arch name and the triple if it seems like we're building an armhf
147      # target.
148      if (COMPILER_RT_BAREMETAL_BUILD)
149        set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}")
150      elseif ("${arch}" MATCHES "hf$" OR "${triple}" MATCHES "hf$")
151        set(${output} "${name}-armhf${COMPILER_RT_OS_SUFFIX}")
152      else()
153        set(${output} "${name}-arm${COMPILER_RT_OS_SUFFIX}")
154      endif()
155    else()
156      set(${output} "${name}-${arch}${COMPILER_RT_OS_SUFFIX}")
157    endif()
158  endif()
159endmacro()
160
161# Adds static or shared runtime for a list of architectures and operating
162# systems and puts it in the proper directory in the build and install trees.
163# add_compiler_rt_runtime(<name>
164#                         {OBJECT|STATIC|SHARED|MODULE}
165#                         ARCHS <architectures>
166#                         OS <os list>
167#                         SOURCES <source files>
168#                         CFLAGS <compile flags>
169#                         LINK_FLAGS <linker flags>
170#                         DEFS <compile definitions>
171#                         DEPS <dependencies>
172#                         LINK_LIBS <linked libraries> (only for shared library)
173#                         OBJECT_LIBS <object libraries to use as sources>
174#                         PARENT_TARGET <convenience parent target>
175#                         ADDITIONAL_HEADERS <header files>)
176function(add_compiler_rt_runtime name type)
177  if(NOT type MATCHES "^(OBJECT|STATIC|SHARED|MODULE)$")
178    message(FATAL_ERROR
179            "type argument must be OBJECT, STATIC, SHARED or MODULE")
180    return()
181  endif()
182  cmake_parse_arguments(LIB
183    ""
184    "PARENT_TARGET"
185    "OS;ARCHS;SOURCES;CFLAGS;LINK_FLAGS;DEFS;DEPS;LINK_LIBS;OBJECT_LIBS;ADDITIONAL_HEADERS"
186    ${ARGN})
187  set(libnames)
188  # Until we support this some other way, build compiler-rt runtime without LTO
189  # to allow non-LTO projects to link with it.
190  if(COMPILER_RT_HAS_FNO_LTO_FLAG)
191    set(NO_LTO_FLAGS "-fno-lto")
192  else()
193    set(NO_LTO_FLAGS "")
194  endif()
195
196  # By default do not instrument or use profdata for compiler-rt.
197  set(NO_PGO_FLAGS "")
198  if(NOT COMPILER_RT_ENABLE_PGO)
199    if(LLVM_PROFDATA_FILE AND COMPILER_RT_HAS_FNO_PROFILE_INSTR_USE_FLAG)
200      list(APPEND NO_PGO_FLAGS "-fno-profile-instr-use")
201    endif()
202    if(LLVM_BUILD_INSTRUMENTED MATCHES IR AND COMPILER_RT_HAS_FNO_PROFILE_GENERATE_FLAG)
203      list(APPEND NO_PGO_FLAGS "-fno-profile-generate")
204    elseif((LLVM_BUILD_INSTRUMENTED OR LLVM_BUILD_INSTRUMENTED_COVERAGE) AND COMPILER_RT_HAS_FNO_PROFILE_INSTR_GENERATE_FLAG)
205      list(APPEND NO_PGO_FLAGS "-fno-profile-instr-generate")
206      if(LLVM_BUILD_INSTRUMENTED_COVERAGE AND COMPILER_RT_HAS_FNO_COVERAGE_MAPPING_FLAG)
207        list(APPEND NO_PGO_FLAGS "-fno-coverage-mapping")
208      endif()
209    endif()
210  endif()
211
212  list(LENGTH LIB_SOURCES LIB_SOURCES_LENGTH)
213  if (${LIB_SOURCES_LENGTH} GREATER 0)
214    # Add headers to LIB_SOURCES for IDEs. It doesn't make sense to
215    # do this for a runtime library that only consists of OBJECT
216    # libraries, so only add the headers when source files are present.
217    compiler_rt_process_sources(LIB_SOURCES
218      ${LIB_SOURCES}
219      ADDITIONAL_HEADERS
220        ${LIB_ADDITIONAL_HEADERS}
221    )
222  endif()
223
224  if(APPLE)
225    foreach(os ${LIB_OS})
226      # Strip out -msse3 if this isn't macOS.
227      list(LENGTH LIB_CFLAGS HAS_EXTRA_CFLAGS)
228      if(HAS_EXTRA_CFLAGS AND NOT "${os}" MATCHES "^(osx)$")
229        list(REMOVE_ITEM LIB_CFLAGS "-msse3")
230      endif()
231      if(type STREQUAL "STATIC")
232        set(libname "${name}_${os}")
233      else()
234        set(libname "${name}_${os}_dynamic")
235        set(extra_link_flags_${libname} ${DARWIN_${os}_LINK_FLAGS} ${LIB_LINK_FLAGS})
236      endif()
237      list_intersect(LIB_ARCHS_${libname} DARWIN_${os}_ARCHS LIB_ARCHS)
238      if(LIB_ARCHS_${libname})
239        list(APPEND libnames ${libname})
240        set(extra_cflags_${libname} ${DARWIN_${os}_CFLAGS} ${NO_LTO_FLAGS} ${NO_PGO_FLAGS} ${LIB_CFLAGS})
241        set(output_name_${libname} ${libname}${COMPILER_RT_OS_SUFFIX})
242        set(sources_${libname} ${LIB_SOURCES})
243        format_object_libs(sources_${libname} ${os} ${LIB_OBJECT_LIBS})
244        get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir_${libname})
245        get_compiler_rt_install_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} install_dir_${libname})
246      endif()
247
248      # Build the macOS sanitizers with Mac Catalyst support.
249      if ("${COMPILER_RT_ENABLE_MACCATALYST}" AND
250          "${os}" MATCHES "^(osx)$")
251        foreach(arch ${LIB_ARCHS_${libname}})
252          list(APPEND extra_cflags_${libname}
253            "SHELL:-target ${arch}-apple-macos${DARWIN_osx_MIN_VER} -darwin-target-variant ${arch}-apple-ios13.1-macabi")
254          list(APPEND extra_link_flags_${libname}
255            "SHELL:-target ${arch}-apple-macos${DARWIN_osx_MIN_VER} -darwin-target-variant ${arch}-apple-ios13.1-macabi")
256        endforeach()
257      endif()
258    endforeach()
259  else()
260    foreach(arch ${LIB_ARCHS})
261      if(NOT CAN_TARGET_${arch})
262        message(FATAL_ERROR "Architecture ${arch} can't be targeted")
263        return()
264      endif()
265      if(type STREQUAL "OBJECT")
266        set(libname "${name}-${arch}")
267        set_output_name(output_name_${libname} ${name}${COMPILER_RT_OS_SUFFIX} ${arch})
268      elseif(type STREQUAL "STATIC")
269        set(libname "${name}-${arch}")
270        set_output_name(output_name_${libname} ${name} ${arch})
271      else()
272        set(libname "${name}-dynamic-${arch}")
273        set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${LIB_CFLAGS})
274        set(extra_link_flags_${libname} ${TARGET_${arch}_LINK_FLAGS} ${LIB_LINK_FLAGS})
275        if(WIN32)
276          set_output_name(output_name_${libname} ${name}_dynamic ${arch})
277        else()
278          set_output_name(output_name_${libname} ${name} ${arch})
279        endif()
280      endif()
281      if(COMPILER_RT_USE_BUILTINS_LIBRARY AND NOT type STREQUAL "OBJECT" AND
282         NOT name STREQUAL "clang_rt.builtins")
283        get_compiler_rt_target(${arch} target)
284        find_compiler_rt_library(builtins builtins_${libname} TARGET ${target})
285        if(builtins_${libname} STREQUAL "NOTFOUND")
286          message(FATAL_ERROR "Cannot find builtins library for the target architecture")
287        endif()
288      endif()
289      set(sources_${libname} ${LIB_SOURCES})
290      format_object_libs(sources_${libname} ${arch} ${LIB_OBJECT_LIBS})
291      set(libnames ${libnames} ${libname})
292      set(extra_cflags_${libname} ${TARGET_${arch}_CFLAGS} ${NO_LTO_FLAGS} ${NO_PGO_FLAGS} ${LIB_CFLAGS})
293      get_compiler_rt_output_dir(${arch} output_dir_${libname})
294      get_compiler_rt_install_dir(${arch} install_dir_${libname})
295    endforeach()
296  endif()
297
298  if(NOT libnames)
299    return()
300  endif()
301
302  if(LIB_PARENT_TARGET)
303    # If the parent targets aren't created we should create them
304    if(NOT TARGET ${LIB_PARENT_TARGET})
305      add_custom_target(${LIB_PARENT_TARGET})
306      set_target_properties(${LIB_PARENT_TARGET} PROPERTIES
307                            FOLDER "Compiler-RT Misc")
308    endif()
309  endif()
310
311  foreach(libname ${libnames})
312    # If you are using a multi-configuration generator we don't generate
313    # per-library install rules, so we fall back to the parent target COMPONENT
314    if(CMAKE_CONFIGURATION_TYPES AND LIB_PARENT_TARGET)
315      set(COMPONENT_OPTION COMPONENT ${LIB_PARENT_TARGET})
316    else()
317      set(COMPONENT_OPTION COMPONENT ${libname})
318    endif()
319
320    if(type STREQUAL "OBJECT")
321      if(CMAKE_C_COMPILER_ID MATCHES Clang AND CMAKE_C_COMPILER_TARGET)
322        list(APPEND extra_cflags_${libname} "--target=${CMAKE_C_COMPILER_TARGET}")
323      endif()
324      if(CMAKE_SYSROOT)
325        list(APPEND extra_cflags_${libname} "--sysroot=${CMAKE_SYSROOT}")
326      endif()
327      string(REPLACE ";" " " extra_cflags_${libname} "${extra_cflags_${libname}}")
328      string(REGEX MATCHALL "<[A-Za-z0-9_]*>" substitutions
329             ${CMAKE_C_COMPILE_OBJECT})
330      set(compile_command_${libname} "${CMAKE_C_COMPILE_OBJECT}")
331
332      set(output_file_${libname} ${output_name_${libname}}${CMAKE_C_OUTPUT_EXTENSION})
333      foreach(substitution ${substitutions})
334        if(substitution STREQUAL "<CMAKE_C_COMPILER>")
335          string(REPLACE "<CMAKE_C_COMPILER>" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}"
336                 compile_command_${libname} ${compile_command_${libname}})
337        elseif(substitution STREQUAL "<OBJECT>")
338          string(REPLACE "<OBJECT>" "${output_dir_${libname}}/${output_file_${libname}}"
339                 compile_command_${libname} ${compile_command_${libname}})
340        elseif(substitution STREQUAL "<SOURCE>")
341          string(REPLACE "<SOURCE>" "${sources_${libname}}"
342                 compile_command_${libname} ${compile_command_${libname}})
343        elseif(substitution STREQUAL "<FLAGS>")
344          string(REPLACE "<FLAGS>" "${CMAKE_C_FLAGS} ${extra_cflags_${libname}}"
345                 compile_command_${libname} ${compile_command_${libname}})
346        else()
347          string(REPLACE "${substitution}" "" compile_command_${libname}
348                 ${compile_command_${libname}})
349        endif()
350      endforeach()
351      separate_arguments(compile_command_${libname})
352      add_custom_command(
353          OUTPUT ${output_dir_${libname}}/${output_file_${libname}}
354          COMMAND ${compile_command_${libname}}
355          DEPENDS ${sources_${libname}}
356          COMMENT "Building C object ${output_file_${libname}}")
357      add_custom_target(${libname} DEPENDS ${output_dir_${libname}}/${output_file_${libname}})
358      install(FILES ${output_dir_${libname}}/${output_file_${libname}}
359        DESTINATION ${install_dir_${libname}}
360        ${COMPONENT_OPTION})
361    else()
362      add_library(${libname} ${type} ${sources_${libname}})
363      set_target_compile_flags(${libname} ${extra_cflags_${libname}})
364      set_target_link_flags(${libname} ${extra_link_flags_${libname}})
365      set_property(TARGET ${libname} APPEND PROPERTY
366                   COMPILE_DEFINITIONS ${LIB_DEFS})
367      set_target_output_directories(${libname} ${output_dir_${libname}})
368      install(TARGETS ${libname}
369        ARCHIVE DESTINATION ${install_dir_${libname}}
370                ${COMPONENT_OPTION}
371        LIBRARY DESTINATION ${install_dir_${libname}}
372                ${COMPONENT_OPTION}
373        RUNTIME DESTINATION ${install_dir_${libname}}
374                ${COMPONENT_OPTION})
375    endif()
376    if(LIB_DEPS)
377      add_dependencies(${libname} ${LIB_DEPS})
378    endif()
379    set_target_properties(${libname} PROPERTIES
380        OUTPUT_NAME ${output_name_${libname}})
381    set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT Runtime")
382    if(LIB_LINK_LIBS)
383      target_link_libraries(${libname} PRIVATE ${LIB_LINK_LIBS})
384    endif()
385    if(builtins_${libname})
386      target_link_libraries(${libname} PRIVATE ${builtins_${libname}})
387    endif()
388    if(${type} STREQUAL "SHARED")
389      if(COMMAND llvm_setup_rpath)
390        llvm_setup_rpath(${libname})
391      endif()
392      if(WIN32 AND NOT CYGWIN AND NOT MINGW)
393        set_target_properties(${libname} PROPERTIES IMPORT_PREFIX "")
394        set_target_properties(${libname} PROPERTIES IMPORT_SUFFIX ".lib")
395      endif()
396      if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*")
397        # Ad-hoc sign the dylibs when using Xcode versions older than 12.
398        # Xcode 12 shipped with ld64-609.
399        # FIXME: Remove whole conditional block once everything uses Xcode 12+.
400        set(LD_V_OUTPUT)
401        execute_process(
402          COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1"
403          RESULT_VARIABLE HAD_ERROR
404          OUTPUT_VARIABLE LD_V_OUTPUT
405        )
406        if (HAD_ERROR)
407          message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}")
408        endif()
409        set(NEED_EXPLICIT_ADHOC_CODESIGN 1)
410        if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*")
411          string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT})
412          if (HOST_LINK_VERSION VERSION_GREATER_EQUAL 609)
413            set(NEED_EXPLICIT_ADHOC_CODESIGN 0)
414          endif()
415        endif()
416        if (NEED_EXPLICIT_ADHOC_CODESIGN)
417          add_custom_command(TARGET ${libname}
418            POST_BUILD
419            COMMAND codesign --sign - $<TARGET_FILE:${libname}>
420            WORKING_DIRECTORY ${COMPILER_RT_OUTPUT_LIBRARY_DIR}
421          )
422        endif()
423      endif()
424    endif()
425
426    set(parent_target_arg)
427    if(LIB_PARENT_TARGET)
428      set(parent_target_arg PARENT_TARGET ${LIB_PARENT_TARGET})
429    endif()
430    add_compiler_rt_install_targets(${libname} ${parent_target_arg})
431
432    if(APPLE)
433      set_target_properties(${libname} PROPERTIES
434      OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}")
435    endif()
436
437    if(type STREQUAL "SHARED")
438      rt_externalize_debuginfo(${libname})
439    endif()
440  endforeach()
441  if(LIB_PARENT_TARGET)
442    add_dependencies(${LIB_PARENT_TARGET} ${libnames})
443  endif()
444endfunction()
445
446# Compile and register compiler-rt tests.
447# generate_compiler_rt_tests(<output object files> <test_suite> <test_name>
448#                           <test architecture>
449#                           KIND <custom prefix>
450#                           SUBDIR <subdirectory for testing binary>
451#                           SOURCES <sources to compile>
452#                           RUNTIME <tests runtime to link in>
453#                           CFLAGS <compile-time flags>
454#                           COMPILE_DEPS <compile-time dependencies>
455#                           DEPS <dependencies>
456#                           LINK_FLAGS <flags to use during linking>
457# )
458function(generate_compiler_rt_tests test_objects test_suite testname arch)
459  cmake_parse_arguments(TEST "" "KIND;RUNTIME;SUBDIR"
460    "SOURCES;COMPILE_DEPS;DEPS;CFLAGS;LINK_FLAGS" ${ARGN})
461
462  foreach(source ${TEST_SOURCES})
463    sanitizer_test_compile(
464      "${test_objects}" "${source}" "${arch}"
465      KIND ${TEST_KIND}
466      COMPILE_DEPS ${TEST_COMPILE_DEPS}
467      DEPS ${TEST_DEPS}
468      CFLAGS ${TEST_CFLAGS}
469      )
470  endforeach()
471
472  set(TEST_DEPS ${${test_objects}})
473
474  if(NOT "${TEST_RUNTIME}" STREQUAL "")
475    list(APPEND TEST_DEPS ${TEST_RUNTIME})
476    list(APPEND "${test_objects}" $<TARGET_FILE:${TEST_RUNTIME}>)
477  endif()
478
479  add_compiler_rt_test(${test_suite} "${testname}" "${arch}"
480    SUBDIR ${TEST_SUBDIR}
481    OBJECTS ${${test_objects}}
482    DEPS ${TEST_DEPS}
483    LINK_FLAGS ${TEST_LINK_FLAGS}
484    )
485  set("${test_objects}" "${${test_objects}}" PARENT_SCOPE)
486endfunction()
487
488# Link objects into a single executable with COMPILER_RT_TEST_COMPILER,
489# using specified link flags. Make executable a part of provided
490# test_suite.
491# add_compiler_rt_test(<test_suite> <test_name> <arch>
492#                      SUBDIR <subdirectory for binary>
493#                      OBJECTS <object files>
494#                      DEPS <deps (e.g. runtime libs)>
495#                      LINK_FLAGS <link flags>)
496function(add_compiler_rt_test test_suite test_name arch)
497  cmake_parse_arguments(TEST "" "SUBDIR" "OBJECTS;DEPS;LINK_FLAGS" "" ${ARGN})
498  set(output_dir ${CMAKE_CURRENT_BINARY_DIR})
499  if(TEST_SUBDIR)
500    set(output_dir "${output_dir}/${TEST_SUBDIR}")
501  endif()
502  set(output_dir "${output_dir}/${CMAKE_CFG_INTDIR}")
503  file(MAKE_DIRECTORY "${output_dir}")
504  set(output_bin "${output_dir}/${test_name}")
505  if(MSVC)
506    set(output_bin "${output_bin}.exe")
507  endif()
508
509  # Use host compiler in a standalone build, and just-built Clang otherwise.
510  if(NOT COMPILER_RT_STANDALONE_BUILD)
511    list(APPEND TEST_DEPS clang)
512  endif()
513
514  get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS)
515  list(APPEND TEST_LINK_FLAGS ${TARGET_LINK_FLAGS})
516
517  # If we're not on MSVC, include the linker flags from CMAKE but override them
518  # with the provided link flags. This ensures that flags which are required to
519  # link programs at all are included, but the changes needed for the test
520  # trump. With MSVC we can't do that because CMake is set up to run link.exe
521  # when linking, not the compiler. Here, we hack it to use the compiler
522  # because we want to use -fsanitize flags.
523
524  # Only add CMAKE_EXE_LINKER_FLAGS when in a standalone bulid.
525  # Or else CMAKE_EXE_LINKER_FLAGS contains flags for build compiler of Clang/llvm.
526  # This might not be the same as what the COMPILER_RT_TEST_COMPILER supports.
527  # eg: the build compiler use lld linker and we build clang with default ld linker
528  # then to be tested clang will complain about lld options like --color-diagnostics.
529  if(NOT MSVC AND COMPILER_RT_STANDALONE_BUILD)
530    set(TEST_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${TEST_LINK_FLAGS}")
531    separate_arguments(TEST_LINK_FLAGS)
532  endif()
533  if(NOT COMPILER_RT_STANDALONE_BUILD AND COMPILER_RT_HAS_LLD AND "lld" IN_LIST LLVM_ENABLE_PROJECTS)
534    # CMAKE_EXE_LINKER_FLAGS may contain -fuse=lld
535    # FIXME: -DLLVM_ENABLE_LLD=ON and -DLLVM_ENABLE_PROJECTS without lld case.
536    list(APPEND TEST_DEPS lld)
537  endif()
538  add_custom_command(
539    OUTPUT "${output_bin}"
540    COMMAND ${COMPILER_RT_TEST_CXX_COMPILER} ${TEST_OBJECTS} -o "${output_bin}"
541            ${TEST_LINK_FLAGS}
542    DEPENDS ${TEST_DEPS}
543    )
544  add_custom_target(T${test_name} DEPENDS "${output_bin}")
545  set_target_properties(T${test_name} PROPERTIES FOLDER "Compiler-RT Tests")
546
547  # Make the test suite depend on the binary.
548  add_dependencies(${test_suite} T${test_name})
549endfunction()
550
551macro(add_compiler_rt_resource_file target_name file_name component)
552  set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}")
553  set(dst_file "${COMPILER_RT_OUTPUT_DIR}/share/${file_name}")
554  add_custom_command(OUTPUT ${dst_file}
555    DEPENDS ${src_file}
556    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${dst_file}
557    COMMENT "Copying ${file_name}...")
558  add_custom_target(${target_name} DEPENDS ${dst_file})
559  # Install in Clang resource directory.
560  install(FILES ${file_name}
561    DESTINATION ${COMPILER_RT_INSTALL_DATA_DIR}
562    COMPONENT ${component})
563  add_dependencies(${component} ${target_name})
564
565  set_target_properties(${target_name} PROPERTIES FOLDER "Compiler-RT Misc")
566endmacro()
567
568macro(add_compiler_rt_script name)
569  set(dst ${COMPILER_RT_EXEC_OUTPUT_DIR}/${name})
570  set(src ${CMAKE_CURRENT_SOURCE_DIR}/${name})
571  add_custom_command(OUTPUT ${dst}
572    DEPENDS ${src}
573    COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
574    COMMENT "Copying ${name}...")
575  add_custom_target(${name} DEPENDS ${dst})
576  install(FILES ${dst}
577    PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
578    DESTINATION ${COMPILER_RT_INSTALL_BINARY_DIR})
579endmacro(add_compiler_rt_script src name)
580
581# Builds custom version of libc++ and installs it in <prefix>.
582# Can be used to build sanitized versions of libc++ for running unit tests.
583# add_custom_libcxx(<name> <prefix>
584#                   DEPS <list of build deps>
585#                   CFLAGS <list of compile flags>
586#                   USE_TOOLCHAIN)
587macro(add_custom_libcxx name prefix)
588  if(NOT COMPILER_RT_LIBCXX_PATH)
589    message(FATAL_ERROR "libcxx not found!")
590  endif()
591  if(NOT COMPILER_RT_LIBCXXABI_PATH)
592    message(FATAL_ERROR "libcxxabi not found!")
593  endif()
594
595  cmake_parse_arguments(LIBCXX "USE_TOOLCHAIN" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN})
596
597  if(LIBCXX_USE_TOOLCHAIN)
598    set(compiler_args -DCMAKE_C_COMPILER=${COMPILER_RT_TEST_COMPILER}
599                      -DCMAKE_CXX_COMPILER=${COMPILER_RT_TEST_CXX_COMPILER})
600    if(NOT COMPILER_RT_STANDALONE_BUILD AND NOT LLVM_RUNTIMES_BUILD)
601      set(toolchain_deps $<TARGET_FILE:clang>)
602      set(force_deps DEPENDS $<TARGET_FILE:clang>)
603    endif()
604  else()
605    set(compiler_args -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
606                      -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
607  endif()
608
609  add_custom_target(${name}-clear
610    COMMAND ${CMAKE_COMMAND} -E remove_directory ${prefix}
611    COMMENT "Clobbering ${name} build directories"
612    USES_TERMINAL
613    )
614  set_target_properties(${name}-clear PROPERTIES FOLDER "Compiler-RT Misc")
615
616  add_custom_command(
617    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp
618    DEPENDS ${LIBCXX_DEPS} ${toolchain_deps}
619    COMMAND ${CMAKE_COMMAND} -E touch ${prefix}/CMakeCache.txt
620    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp
621    COMMENT "Clobbering bootstrap build directories"
622    )
623
624  add_custom_target(${name}-clobber
625    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp)
626  set_target_properties(${name}-clobber PROPERTIES FOLDER "Compiler-RT Misc")
627
628  set(PASSTHROUGH_VARIABLES
629    CMAKE_C_COMPILER_TARGET
630    CMAKE_CXX_COMPILER_TARGET
631    CMAKE_SHARED_LINKER_FLAGS
632    CMAKE_MODULE_LINKER_FLAGS
633    CMAKE_EXE_LINKER_FLAGS
634    CMAKE_INSTALL_PREFIX
635    CMAKE_MAKE_PROGRAM
636    CMAKE_LINKER
637    CMAKE_AR
638    CMAKE_RANLIB
639    CMAKE_NM
640    CMAKE_OBJCOPY
641    CMAKE_OBJDUMP
642    CMAKE_STRIP
643    CMAKE_READELF
644    CMAKE_SYSROOT
645    LIBCXX_HAS_MUSL_LIBC
646    LIBCXX_HAS_GCC_S_LIB
647    LIBCXX_HAS_PTHREAD_LIB
648    LIBCXX_HAS_RT_LIB
649    LIBCXX_USE_COMPILER_RT
650    LIBCXXABI_HAS_PTHREAD_LIB
651    PYTHON_EXECUTABLE
652    Python3_EXECUTABLE
653    Python2_EXECUTABLE
654    CMAKE_SYSTEM_NAME)
655  foreach(variable ${PASSTHROUGH_VARIABLES})
656    get_property(is_value_set CACHE ${variable} PROPERTY VALUE SET)
657    if(${is_value_set})
658      get_property(value CACHE ${variable} PROPERTY VALUE)
659      list(APPEND CMAKE_PASSTHROUGH_VARIABLES -D${variable}=${value})
660    endif()
661  endforeach()
662
663  string(REPLACE ";" " " LIBCXX_C_FLAGS "${LIBCXX_CFLAGS}")
664  get_property(C_FLAGS CACHE CMAKE_C_FLAGS PROPERTY VALUE)
665  set(LIBCXX_C_FLAGS "${LIBCXX_C_FLAGS} ${C_FLAGS}")
666
667  string(REPLACE ";" " " LIBCXX_CXX_FLAGS "${LIBCXX_CFLAGS}")
668  get_property(CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
669  set(LIBCXX_CXX_FLAGS "${LIBCXX_CXX_FLAGS} ${CXX_FLAGS}")
670
671  ExternalProject_Add(${name}
672    DEPENDS ${name}-clobber ${LIBCXX_DEPS}
673    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/${name}
674    SOURCE_DIR ${LLVM_MAIN_SRC_DIR}/../runtimes
675    BINARY_DIR ${prefix}
676    CMAKE_ARGS ${CMAKE_PASSTHROUGH_VARIABLES}
677               ${compiler_args}
678               -DCMAKE_C_FLAGS=${LIBCXX_C_FLAGS}
679               -DCMAKE_CXX_FLAGS=${LIBCXX_CXX_FLAGS}
680               -DCMAKE_BUILD_TYPE=Release
681               -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY
682               -DLLVM_PATH=${LLVM_MAIN_SRC_DIR}
683               -DLLVM_ENABLE_RUNTIMES=libcxx|libcxxabi
684               -DLIBCXXABI_ENABLE_SHARED=OFF
685               -DLIBCXXABI_HERMETIC_STATIC_LIBRARY=ON
686               -DLIBCXXABI_INCLUDE_TESTS=OFF
687               -DLIBCXX_CXX_ABI=libcxxabi
688               -DLIBCXX_ENABLE_SHARED=OFF
689               -DLIBCXX_HERMETIC_STATIC_LIBRARY=ON
690               -DLIBCXX_INCLUDE_BENCHMARKS=OFF
691               -DLIBCXX_INCLUDE_TESTS=OFF
692               -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON
693               ${LIBCXX_CMAKE_ARGS}
694    INSTALL_COMMAND ""
695    STEP_TARGETS configure build
696    BUILD_ALWAYS 1
697    USES_TERMINAL_CONFIGURE 1
698    USES_TERMINAL_BUILD 1
699    USES_TERMINAL_INSTALL 1
700    LIST_SEPARATOR |
701    EXCLUDE_FROM_ALL TRUE
702    BUILD_BYPRODUCTS "${prefix}/lib/libc++.a" "${prefix}/lib/libc++abi.a"
703    )
704
705  if (CMAKE_GENERATOR MATCHES "Make")
706    set(run_clean "$(MAKE)" "-C" "${prefix}" "clean")
707  else()
708    set(run_clean ${CMAKE_COMMAND} --build ${prefix} --target clean
709                                   --config "$<CONFIG>")
710  endif()
711
712  ExternalProject_Add_Step(${name} clean
713    COMMAND ${run_clean}
714    COMMENT "Cleaning ${name}..."
715    DEPENDEES configure
716    ${force_deps}
717    WORKING_DIRECTORY ${prefix}
718    EXCLUDE_FROM_MAIN 1
719    USES_TERMINAL 1
720    )
721  ExternalProject_Add_StepTargets(${name} clean)
722
723  if(LIBCXX_USE_TOOLCHAIN)
724    add_dependencies(${name}-clean ${name}-clobber)
725    set_target_properties(${name}-clean PROPERTIES
726      SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp)
727  endif()
728endmacro()
729
730function(rt_externalize_debuginfo name)
731  if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO)
732    return()
733  endif()
734
735  if(NOT COMPILER_RT_EXTERNALIZE_DEBUGINFO_SKIP_STRIP)
736    set(strip_command COMMAND xcrun strip -Sl $<TARGET_FILE:${name}>)
737  endif()
738
739  if(APPLE)
740    if(CMAKE_CXX_FLAGS MATCHES "-flto"
741      OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto")
742
743      set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${name}-lto.o)
744      set_property(TARGET ${name} APPEND_STRING PROPERTY
745        LINK_FLAGS " -Wl,-object_path_lto -Wl,${lto_object}")
746    endif()
747    add_custom_command(TARGET ${name} POST_BUILD
748      COMMAND xcrun dsymutil $<TARGET_FILE:${name}>
749      ${strip_command})
750  else()
751    message(FATAL_ERROR "COMPILER_RT_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!")
752  endif()
753endfunction()
754
755
756# Configure lit configuration files, including compiler-rt specific variables.
757function(configure_compiler_rt_lit_site_cfg input output)
758  set_llvm_build_mode()
759
760  get_compiler_rt_output_dir(${COMPILER_RT_DEFAULT_TARGET_ARCH} output_dir)
761
762  string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_TEST_COMPILER ${COMPILER_RT_TEST_COMPILER})
763  string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} COMPILER_RT_RESOLVED_LIBRARY_OUTPUT_DIR ${output_dir})
764
765  configure_lit_site_cfg(${input} ${output})
766endfunction()
767