429 lines · plain
1cmake_minimum_required(VERSION 3.20.0)2set(LLVM_SUBPROJECT_TITLE "libc")3 4if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)5 message(FATAL_ERROR "Builds rooted in the libc directory are not supported. "6 "Builds should be rooted in the runtimes directory instead. "7 "Please see the documentation at https://libc.llvm.org/build_and_test.html for more info.")8endif()9 10# Include LLVM's cmake policies.11if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS)12 set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)13endif()14include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake15 NO_POLICY_SCOPE)16include(CheckCXXCompilerFlag)17 18if (LIBC_CMAKE_VERBOSE_LOGGING)19 get_directory_property(LIBC_OLD_PREPROCESSOR_DEFS COMPILE_DEFINITIONS)20 foreach(OLD_DEF ${LIBC_OLD_PREPROCESSOR_DEFS})21 message(STATUS "Undefining ${OLD_DEF}")22 endforeach()23endif()24set_directory_properties(PROPERTIES25 # `llvm-project/llvm/CMakeLists.txt` adds the following directive26 # `include_directories( ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR})` We27 # undo it to be able to precisely control what is getting included.28 INCLUDE_DIRECTORIES ""29 # `llvm/cmake/modules/HandleLLVMOptions.cmake` uses `add_compile_definitions`30 # to set a few preprocessor defines which we do not want.31 COMPILE_DEFINITIONS ""32)33if (CMAKE_BUILD_TYPE STREQUAL "Debug")34 add_definitions("-D_DEBUG")35endif()36 37 38# Default to C++1739set(CMAKE_CXX_STANDARD 17)40 41list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")42 43# The top-level source directory.44set(LIBC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})45# The top-level directory in which libc is being built.46set(LIBC_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR})47 48set(LIBC_ENABLE_USE_BY_CLANG OFF CACHE BOOL "Whether or not to place libc in a build directory findable by a just built clang")49 50# Defining a global namespace to enclose all libc functions.51set(default_namespace "__llvm_libc")52if(LLVM_VERSION_MAJOR)53 string(REPLACE "-" "" NS_LLVM_VERSION_SUFFIX "${LLVM_VERSION_SUFFIX}")54 set(default_namespace "__llvm_libc_${LLVM_VERSION_MAJOR}_${LLVM_VERSION_MINOR}_${LLVM_VERSION_PATCH}_${NS_LLVM_VERSION_SUFFIX}")55endif()56set(LIBC_NAMESPACE ${default_namespace}57 CACHE STRING "The namespace to use to enclose internal implementations. Must start with '__llvm_libc'."58)59 60option(LIBC_CMAKE_VERBOSE_LOGGING61 "Log details warnings and notifications during CMake configuration." OFF)62 63# Path libc/scripts directory.64set(LIBC_BUILD_SCRIPTS_DIR "${LIBC_SOURCE_DIR}/utils/build_scripts")65 66if(NOT LIBC_NAMESPACE MATCHES "^__llvm_libc")67 message(FATAL_ERROR "Invalid LIBC_NAMESPACE. Must start with '__llvm_libc' was '${LIBC_NAMESPACE}'")68endif()69 70message(STATUS "Setting LIBC_NAMESPACE namespace to '${LIBC_NAMESPACE}'")71add_compile_definitions(LIBC_NAMESPACE=${LIBC_NAMESPACE})72 73# Flags to pass down to the compiler while building the libc functions.74set(LIBC_COMPILE_OPTIONS_DEFAULT "" CACHE STRING "Architecture to tell clang to optimize for (e.g. -march=... or -mcpu=...)")75set(LIBC_TEST_COMPILE_OPTIONS_DEFAULT "" CACHE STRING "Common compile options for all the tests.")76 77set(LIBC_LINK_OPTIONS_DEFAULT "" CACHE STRING "Arguments used when linking.")78set(LIBC_TEST_LINK_OPTIONS_DEFAULT "" CACHE STRING "Common link options for all the tests.")79 80set(LIBC_TEST_CMD "" CACHE STRING81 "The full test command in the form <command> binary=@BINARY@, if using another program to test (e.g. QEMU)")82set(LIBC_TEST_HERMETIC_ONLY "" OFF CACHE BOOL "Only enable hermetic tests.")83 84list(APPEND LIBC_COMPILE_OPTIONS_DEFAULT ${LIBC_COMMON_TUNE_OPTIONS})85 86# Check --print-resource-dir to find the compiler resource dir if this flag87# is supported by the compiler.88execute_process(89 OUTPUT_STRIP_TRAILING_WHITESPACE90 COMMAND ${CMAKE_CXX_COMPILER} --print-resource-dir91 RESULT_VARIABLE COMMAND_RETURN_CODE92 OUTPUT_VARIABLE COMPILER_RESOURCE_DIR93)94# Retrieve the host compiler's resource dir.95if(COMMAND_RETURN_CODE EQUAL 0)96 set(COMPILER_RESOURCE_DIR97 "${COMPILER_RESOURCE_DIR}" CACHE PATH "path to compiler resource dir"98 )99 message(STATUS "Set COMPILER_RESOURCE_DIR to "100 "${COMPILER_RESOURCE_DIR} using --print-resource-dir")101else()102 # Try with GCC option: -print-search-dirs, which will output in the form:103 # install: <path>104 # programs: ........105 # So we try to capture the <path> after "install: " in the first line of the106 # output.107 execute_process(108 OUTPUT_STRIP_TRAILING_WHITESPACE109 COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs110 RESULT_VARIABLE COMMAND_RETURN_CODE111 OUTPUT_VARIABLE COMPILER_RESOURCE_DIR112 )113 if(COMMAND_RETURN_CODE EQUAL 0)114 string(REPLACE " " ";" COMPILER_RESOURCE_DIR ${COMPILER_RESOURCE_DIR})115 string(REPLACE "\n" ";" COMPILER_RESOURCE_DIR "${COMPILER_RESOURCE_DIR}")116 list(GET COMPILER_RESOURCE_DIR 1 COMPILER_RESOURCE_DIR)117 message(STATUS "Set COMPILER_RESOURCE_DIR to "118 "${COMPILER_RESOURCE_DIR} using --print-search-dirs")119else()120 if (LIBC_TARGET_OS_IS_GPU)121 message(FATAL_ERROR "COMPILER_RESOURCE_DIR must be set for GPU builds")122 else()123 set(COMPILER_RESOURCE_DIR OFF)124 message(STATUS "COMPILER_RESOURCE_DIR not set125 --print-resource-dir not supported by host compiler")126 endif()127 endif()128endif()129 130# Defines LIBC_TARGET_ARCHITECTURE and associated macros.131set(LIBC_TARGET_TRIPLE "" CACHE STRING "The target triple for the libc build.")132include(LLVMLibCArchitectures)133 134# Some targets can only support the full build.135set(default_to_full_build OFF)136if(LIBC_TARGET_OS_IS_GPU)137 set(default_to_full_build ON)138endif()139 140option(LLVM_LIBC_FULL_BUILD "Build and test LLVM libc as if it is the full libc" ${default_to_full_build})141option(LLVM_LIBC_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR "Build LLVM libc tests assuming our implementation-defined behavior" ON)142option(LLVM_LIBC_ENABLE_LINTING "Enables linting of libc source files" OFF)143option(LLVM_LIBC_ALL_HEADERS "Outputs all functions in header files, regardless of whether they are enabled on this target" OFF)144 145option(LIBC_CONFIG_PATH "The path to user provided folder that configures the build for the target system." OFF)146 147if(LIBC_TARGET_OS_IS_LINUX)148 set(kernel_headers "/usr/include")149endif()150set(LIBC_KERNEL_HEADERS "${kernel_headers}" CACHE STRING "Path to Linux kernel headers")151 152set(LIBC_ENABLE_UNITTESTS ON)153set(LIBC_ENABLE_HERMETIC_TESTS ${LLVM_LIBC_FULL_BUILD})154 155set(LIBC_CONFIG_JSON_FILE_LIST "")156 157if(NOT LIBC_CONFIG_PATH)158 list(APPEND LIBC_CONFIG_JSON_FILE_LIST "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}")159 if(EXISTS "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_ARCHITECTURE}")160 list(APPEND LIBC_CONFIG_JSON_FILE_LIST "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_ARCHITECTURE}")161 set(LIBC_CONFIG_PATH "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/${LIBC_TARGET_ARCHITECTURE}")162 elseif(EXISTS "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}")163 set(LIBC_CONFIG_PATH "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}")164 endif()165else()166 list(APPEND LIBC_CONFIG_JSON_FILE_LIST "${LIBC_CONFIG_PATH}")167endif()168 169if(NOT LIBC_CONFIG_PATH)170 message(FATAL_ERROR "Configs for the platform '${LIBC_TARGET_OS}/${LIBC_TARGET_ARCHITECTURE}' do not exist and LIBC_CONFIG_PATH is not set.")171elseif(LIBC_CMAKE_VERBOSE_LOGGING)172 message(STATUS "Path for config files is: ${LIBC_CONFIG_PATH}")173endif()174 175# option(LIBC_ENABLE_WIDE_CHARACTERS176# "Whether to enable wide character functions on supported platforms. This may177# also set flags to enable or disable wide character support within other178# functions (e.g. printf)." ON)179 180#TODO: Add carve-out specific config files to the list here.181 182include(LibcConfig)183# Config loading happens in three steps:184# 1. Load the config file config/config.json and set up config vars.185# 2. Load config/${LIBC_TARGET_OS}/config.json if available and override186# vars as suitable.187# 3. Load config/${LIBC_TARGET_OS}/${LIBC_TARGET_ARCH}/config.json is188# available and override vars as suitable.189# All the three steps will not override options already set from the190# CMake command line. That is, the CMake command line option values take191# precedence over the values in config.json files.192set(main_config_file ${LIBC_SOURCE_DIR}/config/config.json)193read_libc_config(${main_config_file} global_config)194foreach(opt IN LISTS global_config)195 string(JSON opt_name ERROR_VARIABLE json_error MEMBER ${opt} 0)196 if(json_error)197 message(FATAL_ERROR ${json_error})198 endif()199 if(DEFINED ${opt_name})200 # The option is already defined from the command line so we ignore it here.201 # We still make note of it so that further config load can also ignore202 # this option.203 message(STATUS "${opt_name}: ${${opt_name}} (from command line)")204 list(APPEND cmd_line_conf ${opt_name})205 continue()206 endif()207 208 string(JSON opt_object ERROR_VARIABLE json_error GET ${opt} ${opt_name})209 if(json_error)210 message(FATAL_ERROR "Error reading info of option '${opt_name}': ${json_error}")211 endif()212 string(JSON opt_value ERROR_VARIABLE json_error GET ${opt_object} "value")213 if(json_error)214 message(FATAL_ERROR ${json_error})215 endif()216 message(STATUS "${opt_name}: ${opt_value}")217 set(${opt_name} ${opt_value})218endforeach()219generate_config_doc(${main_config_file} ${LIBC_SOURCE_DIR}/docs/configure.rst)220 221# Load each target specific config.222foreach(config_path IN LISTS LIBC_CONFIG_JSON_FILE_LIST)223 if(LIBC_CMAKE_VERBOSE_LOGGING)224 message(STATUS "Loading additional config: '${config_path}/config.json'")225 endif()226 load_libc_config(${config_path}/config.json ${cmd_line_conf})227endforeach()228 229if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)230 set(LIBC_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})231 if(LIBC_LIBDIR_SUBDIR)232 string(APPEND LIBC_TARGET_SUBDIR /${LIBC_LIBDIR_SUBDIR})233 endif()234 cmake_path(NORMAL_PATH LIBC_TARGET_SUBDIR)235endif()236 237if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND (LIBC_ENABLE_USE_BY_CLANG OR LIBC_TARGET_OS_IS_GPU))238 set(LIBC_INCLUDE_DIR ${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE})239 set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})240 set(LIBC_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LIBC_TARGET_SUBDIR})241else()242 if(NOT LIBC_ENABLE_USE_BY_CLANG)243 set(LIBC_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include)244 set(LIBC_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib)245 elseif(LLVM_LIBRARY_OUTPUT_INTDIR)246 set(LIBC_INCLUDE_DIR ${LLVM_BINARY_DIR}/include)247 set(LIBC_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})248 else()249 set(LIBC_INCLUDE_DIR ${CMAKE_BINARY_DIR}/include)250 set(LIBC_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})251 endif()252 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)253 if(LIBC_TARGET_TRIPLE)254 set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LIBC_TARGET_TRIPLE})255 else()256 set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})257 endif()258 else()259 set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})260 endif()261endif()262 263if(LIBC_TARGET_TRIPLE)264 set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBC_TARGET_TRIPLE})265elseif(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)266 set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBC_TARGET_SUBDIR})267else()268 set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX})269endif()270 271if(LIBC_TARGET_OS_IS_GPU)272 include(prepare_libc_gpu_build)273 set(LIBC_ENABLE_UNITTESTS OFF)274endif()275 276include(LLVMLibCCheckMPFR)277include(LLVMLibCCheckMPC)278 279if(LLVM_LIBC_CLANG_TIDY)280 set(LLVM_LIBC_ENABLE_LINTING ON)281endif()282 283if(LLVM_LIBC_ENABLE_LINTING)284 if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")285 set(LLVM_LIBC_ENABLE_LINTING OFF)286 message(WARNING "C++ compiler is not clang++, linting with be disabled.")287 else()288 if (NOT LLVM_LIBC_CLANG_TIDY)289 find_program(LLVM_LIBC_CLANG_TIDY NAMES clang-tidy)290 endif()291 292 if(LLVM_LIBC_CLANG_TIDY)293 # Check clang-tidy major version.294 execute_process(COMMAND ${LLVM_LIBC_CLANG_TIDY} "--version"295 OUTPUT_VARIABLE CLANG_TIDY_OUTPUT296 ERROR_VARIABLE CLANG_TIDY_ERROR297 RESULT_VARIABLE CLANG_TIDY_RESULT)298 299 if(CLANG_TIDY_RESULT AND NOT CLANG_TIDY_RESULT EQUAL 0)300 message(FATAL_ERROR "Failed to execute '${LLVM_LIBC_CLANG_TIDY} --version'301 output : '${CLANG_TIDY_OUTPUT}'302 error : '${CLANG_TIDY_ERROR}'303 result : '${CLANG_TIDY_RESULT}'304 ")305 endif()306 string(REGEX MATCH "[0-9]+" CLANG_TIDY_VERSION "${CLANG_TIDY_OUTPUT}")307 string(REGEX MATCH "[0-9]+" CLANG_MAJOR_VERSION308 "${CMAKE_CXX_COMPILER_VERSION}")309 310 if(NOT CLANG_TIDY_VERSION EQUAL CLANG_MAJOR_VERSION)311 set(LLVM_LIBC_ENABLE_LINTING OFF)312 message(WARNING "313 'clang-tidy' (version ${CLANG_TIDY_VERSION}) is not the same as314 'clang' (version ${CLANG_MAJOR_VERSION}). Linting will315 be disabled.316 317 The path to the clang-tidy binary can be set manually by passing318 -DLLVM_LIBC_CLANG_TIDY=<path/to/clang-tidy> to CMake.")319 endif()320 add_custom_target(libc-lint)321 else()322 message(FATAL_ERROR "323 Linting is enabled but 'clang-tidy' is not found!324 325 The path to the clang-tidy binary can be set manually by passing326 -DLLVM_LIBC_CLANG_TIDY=<path/to/clang-tidy> to CMake.327 328 To disable linting set LLVM_LIBC_ENABLE_LINTING to OFF329 (pass -DLLVM_LIBC_ENABLE_LINTING=OFF to cmake).")330 endif()331 endif()332endif()333 334option(LLVM_LIBC_INCLUDE_SCUDO "Include the SCUDO standalone as the allocator for LLVM libc" OFF)335if(LLVM_LIBC_INCLUDE_SCUDO)336 if (NOT ("compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS OR "compiler-rt" IN_LIST LLVM_ENABLE_RUNTIMES))337 message(FATAL_ERROR "SCUDO cannot be included without adding compiler-rt to LLVM_ENABLE_PROJECTS or LLVM_ENABLE_RUNTIMES")338 endif()339 if (DEFINED COMPILER_RT_BUILD_SANITIZERS AND NOT COMPILER_RT_BUILD_SANITIZERS)340 message(FATAL_ERROR "Disabling COMPILER_RT_BUILD_SANITIZERS will produce a libc without malloc/free")341 endif()342endif()343 344option(LIBC_INCLUDE_DOCS "Build the libc documentation." ${LLVM_INCLUDE_DOCS})345 346include(LLVMLibCCheckCpuFeatures)347include(CheckCompilerFeatures)348include(LLVMLibCRules)349 350set(TARGET_LLVMLIBC_ENTRYPOINTS "")351set(TARGET_LIBC_ENTRYPOINTS "")352set(TARGET_LIBM_ENTRYPOINTS "")353set(TARGET_LLVMLIBC_REMOVED_ENTRYPOINTS "")354 355# Check entrypoints.txt356if(EXISTS "${LIBC_CONFIG_PATH}/entrypoints.txt")357 include("${LIBC_CONFIG_PATH}/entrypoints.txt")358else()359 message(FATAL_ERROR "${LIBC_CONFIG_PATH}/entrypoints.txt file not found.")360endif()361 362# Check headers.txt363if(EXISTS "${LIBC_CONFIG_PATH}/headers.txt")364 include("${LIBC_CONFIG_PATH}/headers.txt")365elseif(LLVM_LIBC_FULL_BUILD)366 message(FATAL_ERROR "${LIBC_CONFIG_PATH}/headers.txt file not found and fullbuild requested.")367endif()368 369# Check exclude.txt that appends to TARGET_LLVMLIBC_REMOVED_ENTRYPOINTS list370if(EXISTS "${LIBC_CONFIG_PATH}/exclude.txt")371 include("${LIBC_CONFIG_PATH}/exclude.txt")372endif()373 374# #TODO: Set up support for premade configs adding their own exclude lists.375 376foreach(removed_entrypoint IN LISTS TARGET_LLVMLIBC_REMOVED_ENTRYPOINTS)377 if(LIBC_CMAKE_VERBOSE_LOGGING)378 message(STATUS "Removing entrypoint ${removed_entrypoint}")379 endif()380 list(REMOVE_ITEM TARGET_LLVMLIBC_ENTRYPOINTS ${removed_entrypoint})381 list(REMOVE_ITEM TARGET_LIBC_ENTRYPOINTS ${removed_entrypoint})382 list(REMOVE_ITEM TARGET_LIBM_ENTRYPOINTS ${removed_entrypoint})383endforeach()384 385set(TARGET_ENTRYPOINT_NAME_LIST "")386foreach(entrypoint IN LISTS TARGET_LLVMLIBC_ENTRYPOINTS)387 string(FIND ${entrypoint} "." last_dot_loc REVERSE)388 if(${last_dot_loc} EQUAL -1)389 message(FATAL_ERROR "Invalid entrypoint target name ${entrypoint}; Expected"390 " a '.' (dot) in the name.")391 endif()392 math(EXPR name_loc "${last_dot_loc} + 1")393 string(SUBSTRING ${entrypoint} ${name_loc} -1 entrypoint_name)394 list(APPEND TARGET_ENTRYPOINT_NAME_LIST ${entrypoint_name})395endforeach()396 397if(MSVC AND NOT MSYS)398 set(libc_opt_high_flag "/O2")399else()400 set(libc_opt_high_flag "-O3")401endif()402 403add_subdirectory(include)404add_subdirectory(config)405add_subdirectory(hdr)406add_subdirectory(src)407add_subdirectory(utils)408 409if(LLVM_LIBC_FULL_BUILD)410 # The startup system can potentially depend on the library components so add411 # it after the library implementation directories.412 add_subdirectory(startup)413endif()414 415# The lib and test directories are added at the very end as tests416# and libraries potentially draw from the components present in all417# of the other directories.418add_subdirectory(lib)419if(LLVM_INCLUDE_TESTS)420 add_subdirectory(test)421 add_subdirectory(fuzzing)422endif()423 424add_subdirectory(benchmarks)425 426if (LIBC_INCLUDE_DOCS)427 add_subdirectory(docs)428endif()429