#!/usr/bin/env bash #===----------------------------------------------------------------------===## # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # #===----------------------------------------------------------------------===## set -ex set -o pipefail unset LANG unset LC_ALL unset LC_COLLATE PROGNAME="$(basename "${0}")" function usage() { cat < [-h|--help] Display this help and exit. --llvm-root Path to the root of the LLVM monorepo. By default, we try to figure it out based on the current working directory. --build-dir The directory to use for building the library. By default, this is '/build/'. --osx-roots Path to pre-downloaded macOS dylibs. By default, we download them from Green Dragon. This is only relevant at all when running back-deployment testing if one wants to override the old dylibs we use to run the tests with different ones. EOF } while [[ $# -gt 0 ]]; do case ${1} in -h|--help) usage exit 0 ;; --llvm-root) MONOREPO_ROOT="${2}" shift; shift ;; --build-dir) BUILD_DIR="${2}" shift; shift ;; --osx-roots) OSX_ROOTS="${2}" shift; shift ;; *) BUILDER="${1}" shift ;; esac done MONOREPO_ROOT="${MONOREPO_ROOT:="$(git rev-parse --show-toplevel)"}" BUILD_DIR="${BUILD_DIR:=${MONOREPO_ROOT}/build/${BUILDER}}" INSTALL_DIR="${BUILD_DIR}/install" # If we can find Ninja/CMake provided by Xcode, use those since we know their # version will generally work with the Clang shipped in Xcode (e.g. if Clang # knows about -std=c++20, the CMake bundled in Xcode will probably know about # that flag too). if xcrun --find ninja &>/dev/null; then NINJA="$(xcrun --find ninja)"; else NINJA="ninja"; fi if xcrun --find cmake &>/dev/null; then CMAKE="$(xcrun --find cmake)"; else CMAKE="cmake"; fi function clean() { rm -rf "${BUILD_DIR}" } function generate-cmake-base() { echo "--- Generating CMake" ${CMAKE} \ -B "${BUILD_DIR}" \ -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -DLLVM_LIT_ARGS="-sv --show-unsupported --xunit-xml-output test-results.xml" \ "${@}" } function generate-cmake() { generate-cmake-base \ -S "${MONOREPO_ROOT}/llvm" \ -DLLVM_ENABLE_PROJECTS="libcxx;libunwind;libcxxabi" \ -DLIBCXX_CXX_ABI=libcxxabi \ "${@}" } function generate-cmake-libcxx-win() { # TODO: Clang-cl in MSVC configurations don't have access to compiler_rt # builtins helpers for int128 division. See # https://reviews.llvm.org/D91139#2429595 for a comment about longterm # intent for handling the issue. In the meantime, define # -D_LIBCPP_HAS_NO_INT128 (both when building the library itself and # when building tests) to allow enabling filesystem for running tests, # even if it uses a non-permanent ABI. generate-cmake-base \ -S "${MONOREPO_ROOT}/libcxx" \ -DCMAKE_C_COMPILER=clang-cl \ -DCMAKE_CXX_COMPILER=clang-cl \ -DLIBCXX_ENABLE_FILESYSTEM=YES \ -DCMAKE_CXX_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ -DLIBCXX_TEST_COMPILER_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ "${@}" } function check-cxx-cxxabi() { echo "--- Installing libc++ and libc++abi to a fake location" ${NINJA} -vC "${BUILD_DIR}" install-cxx install-cxxabi echo "+++ Running the libc++ tests" ${NINJA} -vC "${BUILD_DIR}" check-cxx echo "+++ Running the libc++abi tests" ${NINJA} -vC "${BUILD_DIR}" check-cxxabi } # TODO: The goal is to test this against all configurations. We should also move # this to the Lit test suite instead of being a separate CMake target. function check-abi-list() { echo "+++ Running the libc++ ABI list test" ${NINJA} -vC "${BUILD_DIR}" check-cxx-abilist || ( echo "+++ Generating the libc++ ABI list after failed check" ${NINJA} -vC "${BUILD_DIR}" generate-cxx-abilist false ) } function check-cxx-benchmarks() { echo "--- Running the benchmarks" ${NINJA} -vC "${BUILD_DIR}" check-cxx-benchmarks } # Print the version of a few tools to aid diagnostics in some cases ${CMAKE} --version ${NINJA} --version case "${BUILDER}" in check-format) clean echo "+++ Checking formatting" # We need to set --extensions so that clang-format checks extensionless files. mkdir -p ${BUILD_DIR} git-clang-format \ --binary /usr/bin/clang-format --diff \ --extensions ',h,hh,hpp,hxx,c,cc,cxx,cpp' HEAD~1 \ -- \ libcxx/{benchmarks,include,src,test} \ libcxxabi/{fuzz,include,src,test} \ | tee ${BUILD_DIR}/clang-format.patch # Check if the diff is empty, fail otherwise. ! grep -q '^--- a' ${BUILD_DIR}/clang-format.patch ;; check-generated-output) # `! foo` doesn't work properly with `set -e`, use `! foo || false` instead. # https://stackoverflow.com/questions/57681955/set-e-does-not-respect-logical-not clean echo "+++ Checking the output of the generator scripts" mkdir -p ${BUILD_DIR} # Reject patches that don't update the generated output correctly. python3 libcxx/utils/generate_feature_test_macro_components.py python3 libcxx/utils/generate_header_inclusion_tests.py python3 libcxx/utils/generate_header_tests.py git diff | tee ${BUILD_DIR}/generated_output.patch # Check if the diffs are empty, fail otherwise. ! grep -q '^--- a' ${BUILD_DIR}/generated_output.patch || false # Reject patches that introduce non-ASCII characters or hard tabs. # Depends on LC_COLLATE set at the top of this script. ! grep -rn '[^ -~]' libcxx/include/ || false # Check that no dependency cycles have been introduced. python3 libcxx/utils/graph_header_deps.py >/dev/null ;; generic-cxx03) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx03.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-cxx11) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx11.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-cxx14) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx14.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-cxx17) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx17.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-cxx20) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx20.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-cxx2b) export CC=clang-tot export CXX=clang++-tot clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-cxx2b.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-shared.cfg.in" check-cxx-cxxabi check-abi-list ;; generic-debug-iterators) export CC=clang-tot export CXX=clang++-tot clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-debug-iterators.cmake" check-cxx-cxxabi check-abi-list ;; generic-noexceptions) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-noexceptions.cmake" check-cxx-cxxabi ;; generic-static) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-static.cmake" \ -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/libcxx-trunk-static.cfg.in" check-cxx-cxxabi ;; generic-32bit) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-32bits.cmake" check-cxx-cxxabi ;; generic-gcc) export CC=gcc export CXX=g++ clean generate-cmake check-cxx-cxxabi ;; generic-asan) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-asan.cmake" check-cxx-cxxabi ;; generic-msan) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-msan.cmake" check-cxx-cxxabi ;; generic-tsan) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-tsan.cmake" check-cxx-cxxabi ;; generic-ubsan) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-ubsan.cmake" check-cxx-cxxabi ;; generic-with_llvm_unwinder) export CC=clang export CXX=clang++ clean generate-cmake -DLIBCXXABI_USE_LLVM_UNWINDER=ON check-cxx-cxxabi ;; generic-singlethreaded) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-singlethreaded.cmake" check-cxx-cxxabi ;; generic-no-debug) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-debug.cmake" check-cxx-cxxabi ;; generic-no-filesystem) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-filesystem.cmake" check-cxx-cxxabi ;; generic-no-random_device) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-random_device.cmake" check-cxx-cxxabi ;; generic-no-localization) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-localization.cmake" check-cxx-cxxabi ;; x86_64-apple-system) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Apple.cmake" check-cxx-cxxabi ;; x86_64-apple-system-noexceptions) export CC=clang export CXX=clang++ clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Apple.cmake" \ -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF check-cxx-cxxabi ;; x86_64-apple-system-backdeployment-*) clean if [[ "${OSX_ROOTS}" == "" ]]; then echo "--- Downloading previous macOS dylibs" PREVIOUS_DYLIBS_URL="https://dl.dropboxusercontent.com/s/liu4fmc53qzlfly/libcxx-roots.tar.gz" OSX_ROOTS="${BUILD_DIR}/macos-roots" mkdir -p "${OSX_ROOTS}" curl "${PREVIOUS_DYLIBS_URL}" | tar -xz --strip-components=1 -C "${OSX_ROOTS}" fi DEPLOYMENT_TARGET="${BUILDER#x86_64-apple-system-backdeployment-}" # TODO: On Apple platforms, we never produce libc++abi.1.dylib, always libc++abi.dylib. # Fix that in the build so that the tests stop searching for @rpath/libc++abi.1.dylib. cp "${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}/libc++abi.dylib" \ "${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}/libc++abi.1.dylib" PARAMS="target_triple=x86_64-apple-macosx${DEPLOYMENT_TARGET}" PARAMS+=";cxx_runtime_root=${OSX_ROOTS}/macOS/libc++/${DEPLOYMENT_TARGET}" PARAMS+=";abi_runtime_root=${OSX_ROOTS}/macOS/libc++abi/${DEPLOYMENT_TARGET}" PARAMS+=";use_system_cxx_lib=True" export CC=clang export CXX=clang++ generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Apple.cmake" \ -DLIBCXX_TEST_PARAMS="${PARAMS}" \ -DLIBCXXABI_TEST_PARAMS="${PARAMS}" check-cxx-cxxabi ;; benchmarks) export CC=clang export CXX=clang++ clean generate-cmake check-cxx-benchmarks ;; documentation) export CC=clang export CXX=clang++ clean generate-cmake -DLLVM_ENABLE_SPHINX=ON echo "+++ Generating documentation" ${NINJA} -vC "${BUILD_DIR}" docs-libcxx-html ;; unified-standalone) export CC=clang export CXX=clang++ clean echo "--- Generating CMake" ${CMAKE} \ -S "${MONOREPO_ROOT}/libcxx/utils/ci/runtimes" \ -B "${BUILD_DIR}" \ -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi;libunwind" check-cxx-cxxabi ;; runtimes-build) export CC=clang export CXX=clang++ clean echo "--- Generating CMake" ${CMAKE} \ -S "${MONOREPO_ROOT}/llvm" \ -B "${BUILD_DIR}" \ -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -DLLVM_ENABLE_PROJECTS="clang" \ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ -DLLVM_RUNTIME_TARGETS="x86_64-unknown-linux-gnu" echo "+++ Running the libc++ and libc++abi tests" ${NINJA} -C "${BUILD_DIR}" check-runtimes echo "--- Installing libc++ and libc++abi to a fake location" ${NINJA} -C "${BUILD_DIR}" install-cxx install-cxxabi ;; legacy-test-config) export CC=clang export CXX=clang++ clean generate-cmake -DLIBCXX_TEST_CONFIG="${MONOREPO_ROOT}/libcxx/test/configs/legacy.cfg.in" check-cxx-cxxabi ;; legacy-standalone) export CC=clang export CXX=clang++ clean echo "--- Generating CMake" ${CMAKE} \ -S "${MONOREPO_ROOT}/libcxx" \ -B "${BUILD_DIR}/libcxx" \ -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -DLLVM_PATH="${MONOREPO_ROOT}/llvm" \ -DLIBCXX_CXX_ABI=libcxxabi \ -DLIBCXX_CXX_ABI_INCLUDE_PATHS="${MONOREPO_ROOT}/libcxxabi/include" \ -DLIBCXX_CXX_ABI_LIBRARY_PATH="${BUILD_DIR}/libcxxabi/lib" ${CMAKE} \ -S "${MONOREPO_ROOT}/libcxxabi" \ -B "${BUILD_DIR}/libcxxabi" \ -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ -DLLVM_PATH="${MONOREPO_ROOT}/llvm" \ -DLIBCXXABI_LIBCXX_PATH="${MONOREPO_ROOT}/libcxx" \ -DLIBCXXABI_LIBCXX_INCLUDES="${BUILD_DIR}/libcxx/include/c++/v1" \ -DLIBCXXABI_LIBCXX_LIBRARY_PATH="${BUILD_DIR}/libcxx/lib" echo "+++ Generating libc++ headers" ${NINJA} -vC "${BUILD_DIR}/libcxx" generate-cxx-headers echo "+++ Building libc++abi" ${NINJA} -vC "${BUILD_DIR}/libcxxabi" cxxabi echo "+++ Building libc++" ${NINJA} -vC "${BUILD_DIR}/libcxx" cxx echo "+++ Running the libc++ tests" ${NINJA} -vC "${BUILD_DIR}/libcxx" check-cxx echo "+++ Running the libc++abi tests" ${NINJA} -vC "${BUILD_DIR}/libcxxabi" check-cxxabi ;; aarch64) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/AArch64.cmake" check-cxx-cxxabi ;; aarch64-noexceptions) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/AArch64.cmake" \ -DLIBCXX_ENABLE_EXCEPTIONS=OFF \ -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF check-cxx-cxxabi ;; # Aka Armv8 32 bit armv8) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv8Arm.cmake" check-cxx-cxxabi ;; armv8-noexceptions) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv8Thumb-noexceptions.cmake" check-cxx-cxxabi ;; # Armv7 32 bit. One building Arm only one Thumb only code. armv7) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv7Arm.cmake" check-cxx-cxxabi ;; armv7-noexceptions) clean generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv7Thumb-noexceptions.cmake" check-cxx-cxxabi ;; windows-dll) clean # TODO: Currently, building with the experimental library breaks running # tests (the test linking look for the c++experimental library with the # wrong name, and the statically linked c++experimental can't be linked # correctly when libc++ visibility attributes indicate dllimport linkage # anyway), thus just disable the experimental library. Remove this # setting when cmake and the test driver does the right thing automatically. generate-cmake-libcxx-win -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF echo "+++ Running the libc++ tests" ${NINJA} -vC "${BUILD_DIR}" check-cxx ;; windows-static) clean generate-cmake-libcxx-win -DLIBCXX_ENABLE_SHARED=OFF echo "+++ Running the libc++ tests" ${NINJA} -vC "${BUILD_DIR}" check-cxx ;; *) echo "${BUILDER} is not a known configuration" exit 1 ;; esac