Issue 180298
Summary [Compiler-rt][Sanitizers] compiler-rt ignores CMAKE_*_LINKER_FLAGS_INIT and add_link_options() when building sanitizers for Android
Labels new issue
Assignees
Reporter mccakit
    **Title:** compiler-rt ignores CMAKE_*_LINKER_FLAGS_INIT and add_link_options() when building sanitizers for Android

**Description:**

When cross-compiling compiler-rt sanitizers for Android with a custom libc++ and compiler-rt builtins, the build system ignores standard CMake linker flags (`CMAKE_SHARED_LINKER_FLAGS_INIT`, `add_link_options()`) and instead hardcodes `-lstdc++` and `-latomic`, causing link failures.

**Environment:**
- LLVM version: 20 (main branch)
- Target: aarch64-linux-android30
- Host: Linux x86_64
- Build system: CMake + Ninja

**Problem:**

The compiler-rt build system does not respect `CMAKE_SHARED_LINKER_FLAGS_INIT` or `add_link_options()` when linking sanitizer shared libraries. Instead, it uses its own internal `SANITIZER_COMMON_LINK_LIBS` variable which defaults to libstdc++ and libatomic, causing link failures when using a custom-built libc++ and compiler-rt builtins.

**Expected behavior:**

Standard CMake linker flags should be respected, or at minimum, the build should use `-rtlib=compiler-rt` when specified in compiler flags.

**Actual behavior:**

Link command shows:
```
-lstdc++ -lc -ldl -llog -static-libstdc++ -latomic -lm
```

Instead of the configured flags:
```
-nostdlib++ -L/path/to/custom/libcxx/lib -lc++_static -lc++abi -lclang_rt.builtins-aarch64-android
```

This results in linker errors for missing symbols from compiler-rt builtins:
```
ld.lld: error: undefined symbol: __aarch64_swp1_acq
ld.lld: error: undefined symbol: __extenddftf2
ld.lld: error: undefined symbol: typeinfo for __cxxabiv1::__si_class_type_info
```

**Workaround:**

Manually override `SANITIZER_COMMON_LINK_LIBS` in the toolchain file:
```cmake
list(APPEND SANITIZER_COMMON_LINK_LIBS
 -L/home/user/dev/libcxx/aarch64-linux-android/lib
    -Wl,-Bstatic
 -lc++_static
    -lc++abi
    -Wl,-Bdynamic
 -L/home/user/dev/compiler-rt/aarch64-linux-android/lib/linux
 -lclang_rt.builtins-aarch64-android
)
```

**Steps to Reproduce:**

1. Build compiler-rt builtins (stage 0):
```bash
cmake -S llvm-project/compiler-rt -B build-builtins -G Ninja \
 -DCOMPILER_RT_BUILD_BUILTINS=ON \
  -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
 -DCOMPILER_RT_BUILD_PROFILE=OFF \
  -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
 -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
 -DCMAKE_INSTALL_PREFIX=$HOME/dev/compiler-rt/aarch64-linux-android \
 -DCMAKE_TOOLCHAIN_FILE=toolchain-stage0.cmake

cmake --build build-builtins
cmake --install build-builtins
```

2. Build libc++ and libc++abi:
```bash
cmake -S llvm-project/runtimes -B build-libcxx -G Ninja \
  -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
 -DCMAKE_INSTALL_PREFIX=$HOME/dev/libcxx/aarch64-linux-android \
 -DCMAKE_TOOLCHAIN_FILE=toolchain-libcxx.cmake

cmake --build build-libcxx
cmake --install build-libcxx
```

3. Build compiler-rt sanitizers (stage 1) - **this fails**:
```bash
cmake -S llvm-project/compiler-rt -B build-sanitizers -G Ninja \
 -DCOMPILER_RT_BUILD_SANITIZERS=ON \
  -DCOMPILER_RT_USE_LIBCXX=OFF \
 -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \
 -DCMAKE_INSTALL_PREFIX=$HOME/dev/compiler-rt/aarch64-linux-android \
 -DCMAKE_TOOLCHAIN_FILE=toolchain-stage1.cmake

cmake --build build-sanitizers  # Link failures here
```

**Toolchain Files:**

<details>
<summary>Stage 0 toolchain (compiler-rt builtins only)</summary>
```cmake
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_SYSTEM_VERSION 30)
set(CMAKE_ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_ABI arm64-v8a)
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

set(CMAKE_C_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_CXX_COMPILER /home/mccakit/dev/llvm/bin/clang++)
set(CMAKE_ASM_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_RC_COMPILER /home/mccakit/dev/llvm/bin/llvm-rc)
set(CMAKE_AR /home/mccakit/dev/llvm/bin/llvm-ar)
set(CMAKE_RANLIB /home/mccakit/dev/llvm/bin/llvm-ranlib)
set(CMAKE_MT /home/mccakit/dev/llvm/bin/llvm-mt)
set(PKG_CONFIG_EXECUTABLE "/home/mccakit/dev/pkgconf/bin/pkgconf.py" CACHE FILEPATH "" FORCE)

set(CMAKE_FIND_ROOT_PATH /home/mccakit/dev /home/.conan)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_EXTENSIONS ON)

set(CMAKE_CXX_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=c++26 -nostdinc++ -nostdlib++ -isystem /home/mccakit/dev/libcxx/android-arm64/include/c++/v1 -O3 -DNDEBUG")
set(CMAKE_C_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=gnu23 -O3 -DNDEBUG")

add_link_options(
    -fuse-ld=lld
 --target=aarch64-linux-android30
 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot
 -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64
)

set(CMAKE_BUILD_TYPE RELEASE)
set(BUILD_SHARED_LIBS OFF)
```
</details>

<details>
<summary>libc++ toolchain</summary>
```cmake
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_SYSTEM_VERSION 30)
set(CMAKE_ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_ABI arm64-v8a)
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

set(CMAKE_C_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_CXX_COMPILER /home/mccakit/dev/llvm/bin/clang++)
set(CMAKE_ASM_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_RC_COMPILER /home/mccakit/dev/llvm/bin/llvm-rc)
set(CMAKE_AR /home/mccakit/dev/llvm/bin/llvm-ar)
set(CMAKE_RANLIB /home/mccakit/dev/llvm/bin/llvm-ranlib)
set(CMAKE_MT /home/mccakit/dev/llvm/bin/llvm-mt)
set(PKG_CONFIG_EXECUTABLE "/home/mccakit/dev/pkgconf/bin/pkgconf.py" CACHE FILEPATH "" FORCE)

set(CMAKE_FIND_ROOT_PATH /home/mccakit/dev /home/.conan)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_EXTENSIONS ON)

set(CMAKE_CXX_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=c++26 -O3 -DNDEBUG")
set(CMAKE_C_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=gnu23 -O3 -DNDEBUG")

add_link_options(
    -fuse-ld=lld
 -rtlib=compiler-rt
    --target=aarch64-linux-android30
 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot
 -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64
)

set(CMAKE_BUILD_TYPE RELEASE)
set(BUILD_SHARED_LIBS OFF)

set(LIBCXX_SHARED_OUTPUT_NAME c++_shared CACHE STRING "")
set(LIBCXX_STATIC_OUTPUT_NAME c++_static CACHE STRING "")
set(LIBCXX_ABI_VERSION 1 CACHE STRING "")
set(LIBCXX_ABI_NAMESPACE __ndk1 CACHE STRING "")
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
set(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXXABI_USE_LLVM_UNWINDER OFF CACHE BOOL "")
set(CMAKE_C_COMPILER_WORKS ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_WORKS ON CACHE BOOL "")
```
</details>

<details>
<summary>Stage 1 toolchain (compiler-rt with sanitizers) - **FAILS WITHOUT WORKAROUND**</summary>
```cmake
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_SYSTEM_VERSION 30)
set(CMAKE_ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_NDK /home/mccakit/dev/android-clt/ndk/29.0.13599879)
set(ANDROID_ABI arm64-v8a)
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

set(CMAKE_C_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_CXX_COMPILER /home/mccakit/dev/llvm/bin/clang++)
set(CMAKE_ASM_COMPILER /home/mccakit/dev/llvm/bin/clang)
set(CMAKE_RC_COMPILER /home/mccakit/dev/llvm/bin/llvm-rc)
set(CMAKE_AR /home/mccakit/dev/llvm/bin/llvm-ar)
set(CMAKE_RANLIB /home/mccakit/dev/llvm/bin/llvm-ranlib)
set(CMAKE_MT /home/mccakit/dev/llvm/bin/llvm-mt)
set(PKG_CONFIG_EXECUTABLE "/home/mccakit/dev/pkgconf/bin/pkgconf.py" CACHE FILEPATH "" FORCE)

set(CMAKE_FIND_ROOT_PATH /home/mccakit/dev /home/.conan)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_EXTENSIONS ON)

set(CMAKE_CXX_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=c++26 -nostdinc++ -nostdlib++ -isystem /home/mccakit/dev/libcxx/aarch64-linux-android/include/c++/v1 -O3 -DNDEBUG")
set(CMAKE_C_FLAGS "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -std=gnu23 -O3 -DNDEBUG")
set(CMAKE_CXX_STDLIB_MODULES_JSON "/home/mccakit/dev/libcxx/aarch64-linux-android/lib/libc++.modules.json")

set(CMAKE_EXE_LINKER_FLAGS_INIT "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fuse-ld=lld -rtlib=compiler-rt -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64")

set(CMAKE_SHARED_LINKER_FLAGS_INIT "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fuse-ld=lld -rtlib=compiler-rt -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64")

set(CMAKE_MODULE_LINKER_FLAGS_INIT "--target=aarch64-linux-android30 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fuse-ld=lld -rtlib=compiler-rt -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64")

add_link_options(
 -fuse-ld=lld
    -rtlib=compiler-rt
 --target=aarch64-linux-android30
 --sysroot=/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/sysroot
 -L/home/mccakit/dev/android-clt/ndk/29.0.13599879/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/20/lib/linux/aarch64
 -nostdlib++
    -L/home/mccakit/dev/libcxx/aarch64-linux-android/lib
 -Wl,-Bstatic
    -lc++_static
    -lc++abi
 -Wl,-Bdynamic
)

set(CMAKE_BUILD_TYPE RELEASE)
set(BUILD_SHARED_LIBS OFF)

# WORKAROUND - Without this, the build fails
list(APPEND SANITIZER_COMMON_LINK_LIBS
 -L/home/mccakit/dev/libcxx/aarch64-linux-android/lib
    -Wl,-Bstatic
 -lc++_static
    -lc++abi
    -Wl,-Bdynamic
 -L/home/mccakit/dev/compiler-rt/aarch64-linux-android/lib/linux
 -lclang_rt.builtins-aarch64-android
)
```
</details>

**Proposed Solution:**

The compiler-rt build system should respect standard CMake linker flags, or alternatively:

1. When `-rtlib=compiler-rt` is specified in `CMAKE_CXX_FLAGS` or `CMAKE_C_FLAGS`, automatically link against `libclang_rt.builtins-<arch>-android.a`
2. When `-nostdlib++` is specified, do not add `-lstdc++` or `-lc++` to `SANITIZER_COMMON_LINK_LIBS`
3. Respect `CMAKE_SHARED_LINKER_FLAGS_INIT` and `add_link_options()` when building sanitizer libraries
4. Document the `SANITIZER_COMMON_LINK_LIBS` variable as the official way to override default link libraries if the above are not feasible

**Related Code:**

The issue appears to be in `compiler-rt/cmake/base-config-ix.cmake` around lines 280-310 where `SANITIZER_COMMON_LINK_LIBS` is populated based on hardcoded assumptions about libstdc++ and libatomic availability.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to