xref: /llvm-project/libcxx/utils/ci/apple-install-libcxx.sh (revision 52dc4918ca8b874ddd4e4fcad873a66ecc5b6953)
1#!/usr/bin/env bash
2# ===----------------------------------------------------------------------===##
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#
8# ===----------------------------------------------------------------------===##
9
10set -e
11
12PROGNAME="$(basename "${0}")"
13
14function error() { printf "error: %s\n" "$*"; exit 1; }
15
16function usage() {
17cat <<EOF
18Usage:
19${PROGNAME} [options]
20
21[-h|--help]                  Display this help and exit.
22
23--llvm-root <DIR>            Path to the root of the LLVM monorepo. Only the libcxx
24                             and libcxxabi directories are required.
25
26--build-dir <DIR>            Path to the directory to use for building. This will
27                             contain intermediate build products.
28
29--install-dir <DIR>          Path to the directory to install the library to.
30
31--symbols-dir <DIR>          Path to the directory to install the .dSYM bundle to.
32
33--architectures "<arch>..."  A whitespace separated list of architectures to build for.
34                             The library will be built for each architecture independently,
35                             and a universal binary containing all architectures will be
36                             created from that.
37
38--headers-only               Only install the header part of the library -- don't actually
39                             build the full library.
40
41--version X[.Y[.Z]]          The version of the library to encode in the dylib.
42EOF
43}
44
45while [[ $# -gt 0 ]]; do
46    case ${1} in
47        -h|--help)
48            usage
49            exit 0
50            ;;
51        --llvm-root)
52            llvm_root="${2}"
53            shift; shift
54            ;;
55        --build-dir)
56            build_dir="${2}"
57            shift; shift
58            ;;
59        --symbols-dir)
60            symbols_dir="${2}"
61            shift; shift
62            ;;
63        --install-dir)
64            install_dir="${2}"
65            shift; shift
66            ;;
67        --architectures)
68            architectures="${2}"
69            shift; shift
70            ;;
71        --headers-only)
72            headers_only=true
73            shift
74            ;;
75        --version)
76            version="${2}"
77            shift; shift
78            ;;
79        *)
80            error "Unknown argument '${1}'"
81            ;;
82    esac
83done
84
85for arg in llvm_root build_dir symbols_dir install_dir architectures version; do
86    if [ -z ${!arg+x} ]; then
87        error "Missing required argument '--${arg//_/-}'"
88    elif [ "${!arg}" == "" ]; then
89        error "Argument to --${arg//_/-} must not be empty"
90    fi
91done
92
93# Allow using relative paths
94function realpath() {
95    if [[ $1 = /* ]]; then echo "$1"; else echo "$(pwd)/${1#./}"; fi
96}
97for arg in llvm_root build_dir symbols_dir install_dir; do
98    path="$(realpath "${!arg}")"
99    eval "${arg}=\"${path}\""
100done
101
102function step() {
103    separator="$(printf "%0.s-" $(seq 1 ${#1}))"
104    echo
105    echo "${separator}"
106    echo "${1}"
107    echo "${separator}"
108}
109
110for arch in ${architectures}; do
111    # Construct the target-triple that we're testing for. Otherwise, the target triple is currently detected
112    # as <arch>-apple-darwin<version> instead of <arch>-apple-macosx<version>, which trips up the test suite.
113    # TODO: This shouldn't be necessary anymore if `clang -print-target-triple` behaved properly, see https://llvm.org/PR61762.
114    #       Then LLVM would guess the LLVM_DEFAULT_TARGET_TRIPLE properly and we wouldn't have to specify it.
115    target=$(xcrun clang -arch ${arch} -xc - -### 2>&1 | grep --only-matching -E '"-triple" ".+?"' | grep --only-matching -E '"[^ ]+-apple-[^ ]+?"' | tr -d '"')
116
117    mkdir -p "${build_dir}/${arch}"
118
119    step "Building shims to make libc++ compatible with the system libc++ on Apple platforms when running the tests"
120    shims_library="${build_dir}/${arch}/apple-system-shims.a"
121    # Note that this doesn't need to match the Standard version used to build the rest of the library.
122    xcrun clang++ -c -std=c++2b -target ${target} "${llvm_root}/libcxxabi/src/vendor/apple/shims.cpp" -static -o "${shims_library}"
123
124    step "Building libc++.dylib and libc++abi.dylib for architecture ${arch}"
125    xcrun cmake -S "${llvm_root}/runtimes" \
126                -B "${build_dir}/${arch}" \
127                -GNinja \
128                -DCMAKE_MAKE_PROGRAM="$(xcrun --find ninja)" \
129                -C "${llvm_root}/libcxx/cmake/caches/Apple.cmake" \
130                -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
131                -DCMAKE_INSTALL_PREFIX="${build_dir}/${arch}-install" \
132                -DCMAKE_OSX_ARCHITECTURES="${arch}" \
133                -DLIBCXXABI_LIBRARY_VERSION="${version}" \
134                -DLIBCXX_LIBRARY_VERSION="${version}" \
135                -DLIBCXX_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}" \
136                -DLIBCXXABI_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}" \
137                -DLIBUNWIND_TEST_PARAMS="target_triple=${target};apple_system_shims=${shims_library}"
138
139    if [ "$headers_only" = true ]; then
140        xcrun cmake --build "${build_dir}/${arch}" --target install-cxx-headers install-cxxabi-headers -- -v
141    else
142        xcrun cmake --build "${build_dir}/${arch}" --target install-cxx install-cxxabi -- -v
143    fi
144done
145
146function universal_dylib() {
147    dylib=${1}
148
149    inputs=$(for arch in ${architectures}; do echo "${build_dir}/${arch}-install/lib/${dylib}"; done)
150
151    step "Creating a universal dylib ${dylib} from the dylibs for all architectures"
152    xcrun lipo -create ${inputs} -output "${build_dir}/${dylib}"
153
154    step "Installing the (stripped) universal dylib to ${install_dir}/usr/lib"
155    mkdir -p "${install_dir}/usr/lib"
156    cp "${build_dir}/${dylib}" "${install_dir}/usr/lib/${dylib}"
157    xcrun strip -S "${install_dir}/usr/lib/${dylib}"
158
159    step "Installing the unstripped dylib and the dSYM bundle to ${symbols_dir}"
160    xcrun dsymutil "${build_dir}/${dylib}" -o "${symbols_dir}/${dylib}.dSYM"
161    cp "${build_dir}/${dylib}" "${symbols_dir}/${dylib}"
162}
163
164if [ "$headers_only" != true ]; then
165    universal_dylib libc++.1.dylib
166    universal_dylib libc++abi.dylib
167    (cd "${install_dir}/usr/lib" && ln -s "libc++.1.dylib" libc++.dylib)
168
169    experimental_libs=$(for arch in ${architectures}; do echo "${build_dir}/${arch}-install/lib/libc++experimental.a"; done)
170    xcrun lipo -create ${experimental_libs} -output "${install_dir}/usr/lib/libc++experimental.a"
171fi
172
173# Install the headers by copying the headers from one of the built architectures
174# into the install directory. Headers from all architectures should be the same.
175step "Installing the libc++ and libc++abi headers to ${install_dir}/usr/include"
176any_arch=$(echo ${architectures} | cut -d ' ' -f 1)
177mkdir -p "${install_dir}/usr/include"
178ditto "${build_dir}/${any_arch}-install/include" "${install_dir}/usr/include"
179if [[ $EUID -eq 0 ]]; then # Only chown if we're running as root
180    chown -R root:wheel "${install_dir}/usr/include"
181fi
182
183if [ "$headers_only" != true ]; then
184    step "Installing the libc++ and libc++abi licenses"
185    mkdir -p "${install_dir}/usr/local/OpenSourceLicenses"
186    cp "${llvm_root}/libcxx/LICENSE.TXT" "${install_dir}/usr/local/OpenSourceLicenses/libcxx.txt"
187    cp "${llvm_root}/libcxxabi/LICENSE.TXT" "${install_dir}/usr/local/OpenSourceLicenses/libcxxabi.txt"
188
189    # Also install universal static archives for libc++ and libc++abi
190    libcxx_archives=$(for arch in ${architectures}; do echo "${build_dir}/${arch}-install/lib/libc++.a"; done)
191    libcxxabi_archives=$(for arch in ${architectures}; do echo "${build_dir}/${arch}-install/lib/libc++abi.a"; done)
192    step "Creating universal static archives for libc++ and libc++abi from the static archives for each architecture"
193    mkdir -p "${install_dir}/usr/local/lib/libcxx"
194    xcrun libtool -static ${libcxx_archives} -o "${install_dir}/usr/local/lib/libcxx/libc++-static.a"
195    xcrun libtool -static ${libcxxabi_archives} -o "${install_dir}/usr/local/lib/libcxx/libc++abi-static.a"
196fi
197