在Ubuntu 20.04上为Android ARM64编译LLVM 15.0.7的保姆级避坑指南(附NDK 24配置)
在Ubuntu 20.04上为Android ARM64编译LLVM 15.0.7的保姆级避坑指南(附NDK 24配置)
当Android NDK官方预编译的工具链无法满足特定需求时,自行编译LLVM成为解决定制化问题的终极方案。本文将带您从零开始,在Ubuntu 20.04系统上为ARM64架构的Android设备编译LLVM 15.0.7,并详细解决编译过程中可能遇到的各种"坑"。
1. 环境准备与源码获取
1.1 系统与工具要求
确保您的Ubuntu 20.04系统已安装以下基础工具:
sudo apt update && sudo apt install -y \ git cmake ninja-build \ python3 python3-pip \ g++ make zlib1g-dev注意:建议使用物理机而非虚拟机进行编译,LLVM编译过程对CPU和内存资源消耗较大。
1.2 获取LLVM源码
使用git克隆LLVM项目源码并切换到15.0.7版本:
git clone --depth 1 --branch llvmorg-15.0.7 https://github.com/llvm/llvm-project.git cd llvm-project提示:添加
--depth 1参数可以显著减少下载时间,但会丢失历史提交记录。
1.3 Android NDK配置
下载NDK 24并设置环境变量:
wget https://dl.google.com/android/repository/android-ndk-r24-linux-x86_64.zip unzip android-ndk-r24-linux-x86_64.zip export ANDROID_NDK=$(pwd)/android-ndk-r242. 关键CMake脚本修改
LLVM源码中有几个模块在Android环境下会导致编译失败,需要进行针对性修改。
2.1 修改LLVMHello模块
编辑llvm/lib/Transforms/CMakeLists.txt文件:
# 原始内容 add_llvm_library(LLVMHello MODULE BUILDTREE_ONLY Hello.cpp DEPENDS intrinsics_gen PLUGIN_TOOL opt ) # 修改为 if(NOT ANDROID) add_llvm_library(LLVMHello MODULE BUILDTREE_ONLY Hello.cpp DEPENDS intrinsics_gen PLUGIN_TOOL opt ) endif()2.2 修改BugpointPasses模块
编辑llvm/tools/bugpoint-passes/CMakeLists.txt:
# 原始内容 add_llvm_library(BugpointPasses MODULE BUILDTREE_ONLY TestPasses.cpp DEPENDS intrinsics_gen bugpoint ) # 修改为 if(NOT ANDROID) add_llvm_library(BugpointPasses MODULE BUILDTREE_ONLY TestPasses.cpp DEPENDS intrinsics_gen bugpoint ) endif()2.3 修改Bye示例模块
编辑llvm/examples/Bye/CMakeLists.txt:
# 原始内容 add_llvm_pass_plugin(Bye Bye.cpp DEPENDS intrinsics_gen BUILDTREE_ONLY ) install(TARGETS ${name} RUNTIME DESTINATION "${LLVM_EXAMPLES_INSTALL_DIR}") set_target_properties(${name} PROPERTIES FOLDER "Examples") # 修改为 if(NOT WIN32 AND NOT ANDROID) add_llvm_pass_plugin(Bye Bye.cpp DEPENDS intrinsics_gen BUILDTREE_ONLY ) install(TARGETS ${name} RUNTIME DESTINATION "${LLVM_EXAMPLES_INSTALL_DIR}") set_target_properties(${name} PROPERTIES FOLDER "Examples") endif()3. 编译配置与执行
3.1 创建编译脚本
创建build_android.sh文件,内容如下:
#!/bin/bash # 设置路径变量 build_dir=$(pwd)/build-android install_dir=$(pwd)/install-android llvm_dir=$(pwd)/llvm-project # 创建构建目录 mkdir -p $build_dir mkdir -p $install_dir # 配置CMake cmake -G Ninja -S $llvm_dir/llvm -B $build_dir \ -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DANDROID_ABI="arm64-v8a" \ -DANDROID_PLATFORM=android-24 \ -DCMAKE_INSTALL_PREFIX=$install_dir \ -DLLVM_INCLUDE_TESTS=OFF \ -DLLVM_BUILD_TESTS=OFF \ -DLLVM_INCLUDE_BENCHMARKS=OFF \ -DCMAKE_BUILD_TYPE=Release # 开始编译 ninja -C $build_dir install -j$(nproc)3.2 执行编译
给脚本添加执行权限并运行:
chmod +x build_android.sh ./build_android.sh编译过程可能需要数小时,具体时间取决于您的硬件配置。建议:
- 使用高性能CPU(至少8核)
- 分配足够的内存(建议16GB以上)
- 使用SSD存储加速编译
4. 部署与测试
4.1 将编译结果推送到Android设备
adb connect <设备IP> adb push ./install-android /data/local/tmp/llvm4.2 解决头文件缺失问题
在Android设备上编译时,可能会遇到标准库头文件缺失的问题。解决方法:
# 从NDK中复制必要的头文件 cp -r $ANDROID_NDK/sysroot/usr/include $install_dir/usr/然后在编译时添加包含路径:
./bin/clang++ main.cc \ -I include/c++/v1 \ -I usr/include \ -I usr/local/include \ -I usr/include/aarch64-linux-android4.3 解决链接器缺失问题
Android设备上可能缺少必要的链接器工具,解决方案:
- 编译ARM64版本的binutils工具链
- 将编译好的ld工具复制到Android设备的
/data/local/tmp/llvm/bin目录 - 设置环境变量:
export PATH=$PATH:/data/local/tmp/llvm/bin5. 常见问题与解决方案
5.1 编译过程中内存不足
如果遇到内存不足导致编译失败,可以尝试:
- 减少并行编译任务数:将
-j$(nproc)改为-j4 - 增加系统交换空间:
sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile5.2 CMake配置错误
如果CMake配置阶段失败,检查:
- NDK路径是否正确设置
- 系统是否安装了所有依赖项
- CMake版本是否足够新(至少3.13.4)
5.3 运行时符号找不到
在Android设备上运行时如果遇到symbol not found错误,可能需要:
- 设置正确的LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/data/local/tmp/llvm/lib:$LD_LIBRARY_PATH- 静态链接相关库:
./bin/clang++ -static main.cc6. 性能优化与高级配置
6.1 启用LTO(链接时优化)
在CMake配置中添加:
-DLLVM_ENABLE_LTO=Thin这可以显著提高生成代码的性能,但会增加编译时间和内存消耗。
6.2 选择性编译组件
如果只需要特定组件,可以修改-DLLVM_ENABLE_PROJECTS参数。例如,仅编译Clang:
-DLLVM_ENABLE_PROJECTS="clang"6.3 交叉编译其他Android架构
要编译其他架构(如armeabi-v7a),只需修改-DANDROID_ABI参数:
-DANDROID_ABI="armeabi-v7a"7. 实际应用案例
7.1 使用自定义LLVM编译Android NDK项目
在Android.mk或CMakeLists.txt中指定自定义工具链:
set(CMAKE_C_COMPILER /data/local/tmp/llvm/bin/clang) set(CMAKE_CXX_COMPILER /data/local/tmp/llvm/bin/clang++)7.2 启用实验性功能
如果需要使用LLVM中的实验性功能(如新的优化pass),可以在编译时启用:
-DLLVM_ENABLE_EXPERIMENTAL=ON7.3 调试信息生成
为了便于调试,可以生成调试信息:
-DCMAKE_BUILD_TYPE=RelWithDebInfo8. 维护与更新
8.1 更新LLVM版本
要更新到新版本LLVM:
git fetch --tags git checkout llvmorg-16.0.0 # 示例:切换到16.0.0版本 git submodule update --init --recursive然后重新执行编译流程。
8.2 创建补丁文件
对源码的修改可以保存为补丁文件,方便后续使用:
git diff > android_arm64.patch应用补丁:
git apply android_arm64.patch8.3 二进制分发
可以将编译好的工具链打包分发:
tar -czvf llvm-15.0.7-android-arm64.tar.gz install-android