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