419 lines · plain
1# This file handles building LLVM runtime sub-projects.2cmake_minimum_required(VERSION 3.20.0)3 4# This file can be used in two ways: the bootstrapping build calls it from5# llvm/runtimes/CMakeLists.txt where we reuse the build tree of the top-level6# build or it can be directly invoked in this directory. In the latter case we7# might be building against a LLVM install tree and might not have a valid build8# tree set up yet. We can detect whether we are using the bootstrapping build9# by checking for the HAVE_LLVM_LIT flag that is passed explicitly to10# llvm_ExternalProject_Add().11if (HAVE_LLVM_LIT)12 message(STATUS "Performing bootstrapping runtimes build.")13else()14 message(STATUS "Performing standalone runtimes build.")15endif()16# Add path for custom and the LLVM build's modules to the CMake module path.17set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")18include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake19 NO_POLICY_SCOPE)20 21include(${LLVM_COMMON_CMAKE_UTILS}/Modules/LLVMVersion.cmake)22 23project(Runtimes C CXX ASM)24set(LLVM_SUBPROJECT_TITLE "Runtimes")25set_property(GLOBAL PROPERTY USE_FOLDERS ON)26 27list(INSERT CMAKE_MODULE_PATH 028 "${CMAKE_CURRENT_SOURCE_DIR}/cmake"29 "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"30 "${LLVM_COMMON_CMAKE_UTILS}"31 "${LLVM_COMMON_CMAKE_UTILS}/Modules"32 "${CMAKE_CURRENT_SOURCE_DIR}/../llvm/cmake"33 "${CMAKE_CURRENT_SOURCE_DIR}/../llvm/cmake/modules"34)35 36# We order libraries to mirror roughly how they are layered, except that compiler-rt can depend37# on libc++, so we put it after.38set(LLVM_DEFAULT_RUNTIMES "libc;libunwind;libcxxabi;libcxx;compiler-rt;libclc;openmp;offload")39set(LLVM_SUPPORTED_RUNTIMES "${LLVM_DEFAULT_RUNTIMES};llvm-libgcc;flang-rt;libsycl;orc-rt")40set(LLVM_ENABLE_RUNTIMES "" CACHE STRING41 "Semicolon-separated list of runtimes to build, or \"all\" (${LLVM_DEFAULT_RUNTIMES}). Supported runtimes are ${LLVM_SUPPORTED_RUNTIMES}.")42if(LLVM_ENABLE_RUNTIMES STREQUAL "all" )43 set(LLVM_ENABLE_RUNTIMES ${LLVM_DEFAULT_RUNTIMES})44endif()45include(SortSubset)46sort_subset("${LLVM_SUPPORTED_RUNTIMES}" "${LLVM_ENABLE_RUNTIMES}" LLVM_ENABLE_RUNTIMES)47foreach(proj ${LLVM_ENABLE_RUNTIMES})48 set(proj_dir "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")49 if(IS_DIRECTORY ${proj_dir} AND EXISTS ${proj_dir}/CMakeLists.txt)50 list(APPEND runtimes ${proj_dir})51 else()52 message(FATAL_ERROR "LLVM_ENABLE_RUNTIMES requests ${proj} but directory not found: ${proj_dir}")53 endif()54 string(TOUPPER "${proj}" canon_name)55 STRING(REGEX REPLACE "-" "_" canon_name ${canon_name})56 set(LLVM_EXTERNAL_${canon_name}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")57endforeach()58 59function(runtime_register_component name)60 set_property(GLOBAL APPEND PROPERTY SUB_COMPONENTS ${name})61endfunction()62 63find_package(LLVM PATHS "${LLVM_BINARY_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)64find_package(Clang PATHS "${LLVM_BINARY_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)65 66set(LLVM_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../third-party")67 68# If building standalone by pointing CMake at this runtimes directory,69# LLVM_BINARY_DIR isn't set, find_package(LLVM) will fail and these70# intermediate paths are unset.71if (NOT LLVM_BINARY_DIR)72 set(LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})73endif()74if (NOT LLVM_FOUND)75 set(LLVM_TOOLS_BINARY_DIR ${LLVM_BINARY_DIR}/bin)76 set(LLVM_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include)77 set(LLVM_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})78endif()79 80# This variable makes sure that e.g. llvm-lit is found.81set(LLVM_MAIN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../llvm)82set(LLVM_CMAKE_DIR ${LLVM_MAIN_SRC_DIR}/cmake/modules)83 84include(CheckLibraryExists)85include(LLVMCheckCompilerLinkerFlag)86include(CheckCCompilerFlag)87include(CheckCXXCompilerFlag)88 89 90# Determine whether we are in the runtimes/runtimes-bins directory of a91# bootstrap build.92set(LLVM_TREE_AVAILABLE OFF)93if (LLVM_LIBRARY_DIR AND LLVM_TOOLS_BINARY_DIR AND PACKAGE_VERSION)94 set(LLVM_TREE_AVAILABLE ON)95endif()96 97if(LLVM_TREE_AVAILABLE)98 # Setting these variables will allow the sub-build to put their outputs into99 # the library and bin directories of the top-level build.100 set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})101 set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})102else()103 # Use own build directory for artifact output.104 set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")105 set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")106endif()107 108# CMake omits default compiler include paths, but in runtimes build, we use109# -nostdinc and -nostdinc++ and control include paths manually so this behavior110# is undesirable. Filtering CMAKE_{LANG}_IMPLICIT_INCLUDE_DIRECTORIES to remove111# paths that are inside the build directory disables this behavior.112#113# See https://gitlab.kitware.com/cmake/cmake/-/issues/19227 for further details.114 115function(filter_prefixed list prefix outvar)116 foreach(str ${list})117 string(FIND "${str}" "${prefix}" out)118 if(NOT "${out}" EQUAL 0)119 list(APPEND result ${str})120 endif()121 endforeach()122 set(${outvar} ${result} PARENT_SCOPE)123endfunction()124 125filter_prefixed("${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}" ${LLVM_BINARY_DIR} CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES)126filter_prefixed("${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}" ${LLVM_BINARY_DIR} CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)127filter_prefixed("${CMAKE_ASM_IMPLICIT_INCLUDE_DIRECTORIES}" ${LLVM_BINARY_DIR} CMAKE_ASM_IMPLICIT_INCLUDE_DIRECTORIES)128 129# The compiler driver may be implicitly trying to link against libunwind,130# which might not work if libunwind doesn't exist yet. Try to check if131# --unwindlib=none is supported, and use that if possible.132#133# TODO: Note that this is problematic when LLVM_USE_SANITIZER is used134# because some sanitizers require the unwinder and so the combination of135# -fsanitize=... --unwindlib=none will always result in a linking error.136# Currently, we counteract this issue by adding -fno-sanitize=all flag in137# the project specific code within */cmake/config-ix.cmake files but that's138# brittle. We should ideally move this to runtimes/CMakeLists.txt.139llvm_check_compiler_linker_flag(C "--unwindlib=none" CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG)140if (CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG)141 set(ORIG_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")142 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} --unwindlib=none")143 # TODO: When we can require CMake 3.14, we should use144 # CMAKE_REQUIRED_LINK_OPTIONS here. Until then, we need a workaround:145 # When using CMAKE_REQUIRED_FLAGS, this option gets added both to146 # compilation and linking commands. That causes warnings in the147 # compilation commands during cmake tests. This is normally benign, but148 # when testing whether -Werror works, that test fails (due to the149 # preexisting warning).150 #151 # Therefore, before we can use CMAKE_REQUIRED_LINK_OPTIONS, check if we152 # can use --start-no-unused-arguments to silence the warnings about153 # --unwindlib=none during compilation.154 #155 # We must first add --unwindlib=none to CMAKE_REQUIRED_FLAGS above, to156 # allow this subsequent test to succeed, then rewrite CMAKE_REQUIRED_FLAGS157 # below.158 check_c_compiler_flag("--start-no-unused-arguments" C_SUPPORTS_START_NO_UNUSED_ARGUMENTS)159 if (C_SUPPORTS_START_NO_UNUSED_ARGUMENTS)160 set(CMAKE_REQUIRED_FLAGS "${ORIG_CMAKE_REQUIRED_FLAGS} --start-no-unused-arguments --unwindlib=none --end-no-unused-arguments")161 endif()162endif()163 164# Disable use of the installed C++ standard library when building runtimes.165# Check for -nostdlib++ first; if there's no C++ standard library yet,166# all check_cxx_compiler_flag commands will fail until we add -nostdlib++167# (or -nodefaultlibs).168#169# CMAKE_REQUIRED_FLAGS is used both for C and C++ compilation. This breaks170# compiling with GCC (and we should not need to force -nostd* for GCC anyway),171# so apply it only with Clang. However, since there are cases when appending172# the flag actually breaks the build, still perform the checks rather than173# appending it unconditionally.174#175# TODO: find a better solution. See the discussion on:176# https://github.com/llvm/llvm-project/issues/90332177# https://github.com/llvm/llvm-project/pull/108357178 179if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")180 llvm_check_compiler_linker_flag(CXX "-nostdlib++" CXX_SUPPORTS_NOSTDLIBXX_FLAG)181 if (CXX_SUPPORTS_NOSTDLIBXX_FLAG)182 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++")183 endif()184 check_cxx_compiler_flag(-nostdinc++ CXX_SUPPORTS_NOSTDINCXX_FLAG)185 if (CXX_SUPPORTS_NOSTDINCXX_FLAG)186 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdinc++")187 endif()188endif()189 190# The NVPTX target needs to override linking to pass compiler flag checks.191if("${LLVM_RUNTIMES_TARGET}" MATCHES "^nvptx")192 set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -flto -c")193endif()194 195# Avoid checking whether the compiler is working.196set(LLVM_COMPILER_CHECKED ON)197 198# Handle common options used by all runtimes.199include(AddLLVM)200include(HandleLLVMOptions)201 202# Loot at the PATH first to avoid a version mismatch between the command-line203# python and the CMake-found version204set(Python3_FIND_REGISTRY LAST)205find_package(Python3 REQUIRED COMPONENTS Interpreter)206 207# Host triple is used by tests to check if they are running natively.208include(GetHostTriple)209get_host_triple(LLVM_HOST_TRIPLE)210message(STATUS "LLVM host triple: ${LLVM_HOST_TRIPLE}")211 212# TODO: We shouldn't be using LLVM_DEFAULT_TARGET_TRIPLE for runtimes since we213# aren't generating code, LLVM_TARGET_TRIPLE is a better fit.214set(LLVM_DEFAULT_TARGET_TRIPLE "${LLVM_HOST_TRIPLE}" CACHE STRING215 "Default target for which the runtimes will be built.")216message(STATUS "LLVM default target triple: ${LLVM_DEFAULT_TARGET_TRIPLE}")217 218set(LLVM_TARGET_TRIPLE "${LLVM_DEFAULT_TARGET_TRIPLE}")219 220if(CMAKE_C_COMPILER_ID MATCHES "Clang")221 set(option_prefix "")222 if (CMAKE_C_SIMULATE_ID MATCHES "MSVC")223 set(option_prefix "/clang:")224 endif()225 set(print_target_triple ${CMAKE_C_COMPILER} ${option_prefix}--target=${LLVM_DEFAULT_TARGET_TRIPLE} ${option_prefix}-print-target-triple)226 execute_process(COMMAND ${print_target_triple}227 RESULT_VARIABLE result228 OUTPUT_VARIABLE output229 OUTPUT_STRIP_TRAILING_WHITESPACE)230 if(result EQUAL 0)231 set(LLVM_DEFAULT_TARGET_TRIPLE ${output})232 else()233 string(REPLACE ";" " " print_target_triple "${print_target_triple}")234 # TODO(#97876): Report an error.235 message(WARNING "Failed to execute `${print_target_triple}` to normalize target triple.")236 endif()237endif()238 239option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)240option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)241option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)242option(RUNTIMES_EXECUTE_ONLY_CODE "Compile runtime libraries as execute-only." OFF)243 244if (RUNTIMES_EXECUTE_ONLY_CODE)245 # If a target doesn't support or recognise -mexecute-only, Clang will simply ignore the flag.246 # We can check for this case using -Werror=unused-command-line-argument.247 check_c_compiler_flag("-mexecute-only -Werror=unused-command-line-argument" C_SUPPORTS_MEXECUTE_ONLY)248 if (NOT C_SUPPORTS_MEXECUTE_ONLY)249 message(FATAL_ERROR "RUNTIMES_EXECUTE_ONLY_CODE was turned on, but the target '${LLVM_TARGET_TRIPLE}'"250 " doesn't support the -mexecute-only flag")251 endif()252 253 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mexecute-only")254 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mexecute-only")255endif()256 257# Use libtool instead of ar if you are both on an Apple host, and targeting Apple.258if(CMAKE_HOST_APPLE AND APPLE)259 include(UseLibtool)260endif()261 262# This can be used to detect whether we're in the runtimes build.263set(LLVM_RUNTIMES_BUILD ON)264 265# Make GTest available to all runtimes266# The runtime must call make_gtest_target() for it to become available. This is267# to avoid build failures when gtest is not actually needed. In particular,268# mingw-incomplete-sysroot is missing C++ header files that GTest needs to269# compile.270function(build_gtest)271 if(TARGET default_gtest)272 # Already available273 return()274 endif()275 276 add_subdirectory("${LLVM_THIRD_PARTY_DIR}/unittest" "${CMAKE_BINARY_DIR}/third-party/runtimes_gtest")277endfunction()278 279foreach(entry ${runtimes})280 get_filename_component(projName ${entry} NAME)281 282 # TODO: Clean this up as part of an interface standardization283 string(REPLACE "-" "_" canon_name ${projName})284 string(TOUPPER ${canon_name} canon_name)285 286 # TODO: compiler-rt has to use standalone build for now. We tried to remove287 # this in D57992 but this broke the build because compiler-rt assumes that288 # LLVM and Clang are configured in the same build to set up dependencies. We289 # should clean up the compiler-rt build and remove this eventually.290 if ("${canon_name}" STREQUAL "COMPILER_RT")291 set(${canon_name}_STANDALONE_BUILD ON)292 endif()293 294 if(LLVM_RUNTIMES_LIBDIR_SUBDIR)295 set(${canon_name}_LIBDIR_SUBDIR "${LLVM_RUNTIMES_LIBDIR_SUBDIR}" CACHE STRING "" FORCE)296 endif()297 298 # Setting a variable to let sub-projects detect which other projects299 # will be included under here.300 set(HAVE_${canon_name} ON)301endforeach()302if(LLVM_INCLUDE_TESTS)303 # If built with the runtimes build (rooted at runtimes/CMakeLists.txt), we304 # won't have llvm-lit. If built with the bootstrapping build (rooted at305 # llvm/CMakeLists.txt), the top-level llvm CMake invocation already generated306 # the llvm-lit script.307 if (NOT HAVE_LLVM_LIT)308 # Ensure that the appropriate variables for lit are set before adding any309 # runtimes since their CMake tests configuration might depend on lit being310 # present. This ensures that the testsuites use a local lit from the build311 # dir rather than ${LLVM_INSTALL_DIR}/bin/llvm-lit (which may not exist if312 # LLVM_BINARY_DIR points at an installed LLVM tree rather than a build tree).313 set(LLVM_LIT_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)314 get_llvm_lit_path(_base_dir _file_name ALLOW_EXTERNAL)315 set(LLVM_EXTERNAL_LIT "${_base_dir}/${_file_name}" CACHE STRING "Command used to spawn lit" FORCE)316 # Avoid warning about missing llvm-lit from runtimes CMake files. This is317 # fine since we call configure_file() to create llvm-lit at the end of this318 # file (after recursing into all runtimes' CMake logic), so it will exist.319 set(LLVM_EXTERNAL_LIT_MISSING_WARNED_ONCE YES CACHE INTERNAL "")320 endif()321 322 set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported")323 if (MSVC OR XCODE)324 set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")325 endif()326 set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")327 328 umbrella_lit_testsuite_begin(check-runtimes)329endif()330 331# We do this in two loops so that HAVE_* is set for each runtime before the332# other runtimes are added.333foreach(entry ${runtimes})334 get_filename_component(projName ${entry} NAME)335 336 add_subdirectory(${entry} ${projName})337endforeach()338 339# Define runtimes-test-depends so the parent build can use it unconditionally.340add_custom_target(runtimes-test-depends)341 342if(LLVM_INCLUDE_TESTS)343 # LLVM_RUNTIMES_LIT_DEPENDS is populated when lit tests are added between344 # umbrella_list_testsuite begin and end. The bootstrap runtimes builds345 # currently assumes this target exists.346 get_property(LLVM_RUNTIMES_LIT_DEPENDS GLOBAL PROPERTY LLVM_RUNTIMES_LIT_DEPENDS)347 if(LLVM_RUNTIMES_LIT_DEPENDS)348 # add_dependencies complains if called with no dependencies349 add_dependencies(runtimes-test-depends ${LLVM_RUNTIMES_LIT_DEPENDS})350 endif()351 # Add a global check rule now that all subdirectories have been traversed352 # and we know the total set of lit testsuites.353 umbrella_lit_testsuite_end(check-runtimes)354 355 if (NOT HAVE_LLVM_LIT)356 # If built by manually invoking cmake on this directory, we don't have357 # llvm-lit. If invoked via llvm/runtimes, the toplevel llvm cmake358 # invocation already generated the llvm-lit script.359 # NOTE: this must be called after all testsuites have been added, since360 # otherwise the generated llvm-lit does not have all required path mappings.361 add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit362 ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit)363 endif()364 365 get_property(LLVM_RUNTIMES_LIT_TESTSUITES GLOBAL PROPERTY LLVM_RUNTIMES_LIT_TESTSUITES)366 string(REPLACE ";" "\n" LLVM_RUNTIMES_LIT_TESTSUITES "${LLVM_RUNTIMES_LIT_TESTSUITES}")367 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/lit.tests ${LLVM_RUNTIMES_LIT_TESTSUITES})368else()369 # Create empty files so the parent build can use these unconditionally.370 file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/lit.tests)371endif()372 373get_property(SUB_COMPONENTS GLOBAL PROPERTY SUB_COMPONENTS)374if(SUB_COMPONENTS)375 list(REMOVE_DUPLICATES SUB_COMPONENTS)376 foreach(component ${SUB_COMPONENTS})377 if(NOT TARGET ${component})378 message(SEND_ERROR "Missing target for runtime component ${component}!")379 continue()380 endif()381 382 if(TARGET check-${component})383 list(APPEND SUB_CHECK_TARGETS check-${component})384 endif()385 386 if(TARGET install-${component})387 list(APPEND SUB_INSTALL_TARGETS install-${component})388 endif()389 endforeach()390 391 if(LLVM_RUNTIMES_TARGET)392 configure_file(393 ${CMAKE_CURRENT_SOURCE_DIR}/Components.cmake.in394 ${CMAKE_CURRENT_BINARY_DIR}/runtimes/${LLVM_RUNTIMES_TARGET}/Components.cmake)395 else()396 configure_file(397 ${CMAKE_CURRENT_SOURCE_DIR}/Components.cmake.in398 ${CMAKE_CURRENT_BINARY_DIR}/runtimes/Components.cmake)399 endif()400endif()401 402# If the user requested 'compile_commands.json' we merge the generated JSON from403# the created directories.404if(CMAKE_EXPORT_COMPILE_COMMANDS AND NOT ("${LLVM_BINARY_DIR}" STREQUAL "${CMAKE_BINARY_DIR}"))405 # Make a dependency so that we don't error if the file gets deleted somehow.406 add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/compile_commands.json407 COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/compile_commands.json)408 409 file(TO_NATIVE_PATH "${LLVM_MAIN_SRC_DIR}/utils/merge-json.py" MERGE_JSON_PATH)410 add_custom_command(OUTPUT ${LLVM_BINARY_DIR}/compile_commands.json411 COMMAND ${CMAKE_COMMAND} -E touch ${LLVM_BINARY_DIR}/compile_commands.json412 COMMAND ${Python3_EXECUTABLE} ${MERGE_JSON_PATH}413 ${LLVM_BINARY_DIR}/compile_commands.json414 ${CMAKE_BINARY_DIR}/compile_commands.json415 -o ${LLVM_BINARY_DIR}/compile_commands.json416 DEPENDS ${CMAKE_BINARY_DIR}/compile_commands.json)417 add_custom_target(merge_runtime_commands ALL DEPENDS ${LLVM_BINARY_DIR}/compile_commands.json)418endif()419