如何在Android项目CMAKE_TOOLCHAIN_FILE中正确设置CMAKE_SYSROOT?
问题
为Android项目编写CMAKE_TOOLCHAIN_FILE时遇到路径错误:
设置的CMAKE_SYSROOT:
set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot")
该路径展开为${CMAKE_SOURCE_DIR}/external/cmdline-tools/latest/../.sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/sysroot,是实际存在的目录。
但执行CMake配置时出现错误:
-- CMAKE_SYSROOT /home/user/demo_project/external/cmdline-tools/latest/../.sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/sysroot -- Android: Selected Clang toolchain 'aarch64-linux-android-clang' with GCC toolchain '' -- The C compiler identification is Clang 14.0.7 -- The CXX compiler identification is Clang 14.0.7 -- Check for working C compiler: /home/user/demo_project/external/cmdline-tools/latest/../.sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/clang CMake Error at /usr/share/cmake-3.10/Modules/Platform/Android-Initialize.cmake:31 (message): Android: The system root directory needed for the selected Android version and architecture does not exist: /home/user/demo_project/CMakeFiles/CMakeTmp/external/cmdline-tools/latest/../.sdk/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/sysroot
操作步骤:
~/demo_project$ mkdir build ~/demo_project$ cd build ~/demo_project$ cmake ../ -DCMAKE_TOOLCHAIN_FILE=../tool/buildtools/cmake_toolchain/android.cmake
注意到错误中的路径比STATUS输出多了CMakeFiles/CMakeTmp/前缀,导致路径无效。完整的CMAKE_TOOLCHAIN_FILE内容如下:
set(HOST_TAG "linux-x86_64") set(ANDROID_API 31) set(SDK "../.sdk") set(ANDROID_CMD ${CMAKE_SOURCE_DIR}/external/cmdline-tools/latest) #for android_sdkmanager_install macro to work, set this set(ANDROID_PACKAGES "") set(NDK_PATH ${ANDROID_CMD}/${SDK}/ndk/25.2.9519653) set(CMAKE_ANDROID_NDK ${NDK_PATH}) set(CMAKE_ANDROID_API ${ANDROID_API}) set(ANDROID_TARGET aarch64-linux-android${ANDROID_API}) set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(ANDROID_TARGET_TRIPLE "aarch64-linux-android") set(ANDROID_TARGET_ARCH "armv8") set(CMAKE_ANDROID_ARCH_ABI "arm64-v8a") set(CMAKE_SYSTEM_NAME Android) SET(ANDROID_TOOLCHAIN_ROOT ${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64) set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot") # Disable some features that are not available on Android SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
用于配置NDK的脚本:
SCRIPT_DIR="$( dirname -- "${BASH_SOURCE[0]}"; )" SCRIPT_DIR=$(realpath $SCRIPT_DIR) ANDROID_API=31 cd $SCRIPT_DIR/../external/cmdline-tools/latest/ echo Handle android licenses yes | ./bin/sdkmanager --sdk_root=../.sdk --licenses sdk_install() { PACKAGE_NAME=$1 echo Handle package "$PACKAGE_NAME" ./bin/sdkmanager --sdk_root=../.sdk --install "$PACKAGE_NAME" } sdk_install "build-tools;34.0.0-rc4" sdk_install "ndk;25.2.9519653" sdk_install "platforms;android-$ANDROID_API" PLATFORMS_DIR=$(realpath $SCRIPT_DIR/../external/cmdline-tools/.sdk/platforms) ln -sf $PLATFORMS_DIR ../.sdk/ndk/25.2.9519653/platforms
原因分析
错误核心是相对路径在CMake测试编译阶段被错误解析:
- 你设置的
CMAKE_SYSROOT包含../相对路径,在项目根目录下解析正确。 - 但CMake检测编译器可用性时,会切换到临时目录
build/CMakeFiles/CMakeTmp执行测试编译,此时../会指向demo_project/CMakeFiles而非项目根目录,导致拼接后的路径多出CMakeFiles/CMakeTmp前缀,最终路径不存在。
解决方法
将所有路径转换为绝对路径,避免相对路径在不同工作目录下的解析错误,有两种实现方式:
方式1:基于toolchain文件位置构建绝对路径
修改CMAKE_TOOLCHAIN_FILE中路径相关配置,用CMAKE_CURRENT_LIST_DIR(当前toolchain文件的绝对路径)定位项目根目录,再构建其他绝对路径:
set(HOST_TAG "linux-x86_64") set(ANDROID_API 31) # 获取当前toolchain文件的绝对路径,假设该文件在 tool/buildtools/cmake_toolchain/ 下 set(TOOLCHAIN_ABS_DIR ${CMAKE_CURRENT_LIST_DIR}) # 向上三级目录到达项目根目录(根据实际目录结构调整层级) set(PROJECT_ROOT_ABS ${TOOLCHAIN_ABS_DIR}/../../..) # 用绝对路径定义所有路径变量 set(ANDROID_CMD ${PROJECT_ROOT_ABS}/external/cmdline-tools/latest) set(SDK ${PROJECT_ROOT_ABS}/.sdk) set(NDK_PATH ${SDK}/ndk/25.2.9519653) set(CMAKE_ANDROID_NDK ${NDK_PATH}) set(CMAKE_ANDROID_API ${ANDROID_API}) set(ANDROID_TARGET aarch64-linux-android${ANDROID_API}) set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(ANDROID_TARGET_TRIPLE "aarch64-linux-android") set(ANDROID_TARGET_ARCH "armv8") set(CMAKE_ANDROID_ARCH_ABI "arm64-v8a") set(CMAKE_SYSTEM_NAME Android) SET(ANDROID_TOOLCHAIN_ROOT ${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64) set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot") # Disable some features that are not available on Android SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
方式2:用file(REAL_PATH)转换相对路径为绝对路径
如果不想调整目录层级,可以用CMake的file(REAL_PATH)命令将相对路径解析为绝对路径:
set(HOST_TAG "linux-x86_64") set(ANDROID_API 31) set(SDK "../.sdk") set(ANDROID_CMD ${CMAKE_SOURCE_DIR}/external/cmdline-tools/latest) set(ANDROID_PACKAGES "") # 将相对路径转换为绝对路径 file(REAL_PATH "${ANDROID_CMD}/${SDK}/ndk/25.2.9519653" NDK_PATH) set(CMAKE_ANDROID_NDK ${NDK_PATH}) set(CMAKE_ANDROID_API ${ANDROID_API}) set(ANDROID_TARGET aarch64-linux-android${ANDROID_API}) set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang) set(ANDROID_TARGET_TRIPLE "aarch64-linux-android") set(ANDROID_TARGET_ARCH "armv8") set(CMAKE_ANDROID_ARCH_ABI "arm64-v8a") set(CMAKE_SYSTEM_NAME Android) SET(ANDROID_TOOLCHAIN_ROOT ${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64) set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot") # Disable some features that are not available on Android SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
两种方式都能确保CMAKE_SYSROOT是绝对路径,无论CMake在哪个目录执行测试编译,都能正确定位到NDK的sysroot目录。
内容的提问来源于stack exchange,提问作者Silver
相关产品推荐
相关产品推荐

