LLVM 全面解析:NDK 为什么离不开它?如何亲手编译调试 clang

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

1. LLVM 简介

LLVM(Low Level Virtual Machine)最初是一个编译器研究项目,如今已发展成一个模块化、可重用的编译器框架。

它包含前端(Frontend)、中间表示(IR, Intermediate Representation)、优化器(Optimizer)和后端(Backend, Code Generator)等组件。

开发者可以使用 LLVM 将高级语言源代码(如 C/C++、Rust、Swift 等)转换成中间表示,再经过优化和代码生成,最终编译为机器码。与传统编译器不同,LLVM 的设计高度模块化,方便扩展、优化和跨平台支持。

相关链接:

2. LLVM 与 Android NDK 的关系

在 Android NDK 中,我们通常用 C/C++ 编写性能敏感的模块,最终需要编译为运行在 ARM、ARM64、x86 等架构上的本地机器码。这个过程的核心就是 LLVM/Clang。

整个编译大致可以分为以下几个阶段:

C/C++ 源码  
   ↓ (Clang 前端)  
LLVM IR  
   ↓ (LLVM 优化器)  
优化后的 IR  
   ↓ (LLVM 后端 CodeGen)  
汇编 / 机器码  
   ↓ (链接器 lld)  
.so 动态库

NDK 中 LLVM/Clang 所在路径

word/media/image1.png

查看 clang 版本,这里版本是 18.0.2

(base) PS D:\App\android\sdk\ndk\27.1.12297006\toolchains\llvm\prebuilt\windows-x86_64\bin> ./clang --version

Android (12285214, based on r522817b) clang version 18.0.2 (https://android.googlesource.com/toolchain/llvm-project d8003a456d14a3deb8054cdaa529ffbf02d9b262)
Target: x86_64-w64-windows-gnu
Thread model: posix
InstalledDir: D:/App/android/sdk/ndk/27.1.12297006/toolchains/llvm/prebuilt/windows-x86_64/bin

自 Android NDK r18 开始,Google 弃用了 GCC,全面转向使用 LLVM/Clang 作为 NDK 的编译工具链。

为什么 NDK 要用 LLVM?

  • 跨平台:一次编写,轻松编译成适配多架构的库。

  • 高性能优化:LLVM 提供强大的优化工具,能在有限硬件环境下榨干性能。

  • 现代化生态:相比 GCC,LLVM/Clang 更新更快、支持 C++ 标准更完善,也更利于 Android 长期维护。

3. 下载 LLVM

LLVM 下载地址:https://releases.llvm.org/

word/media/image2.png
选择与 NDK 中 LLVM/Clang 版本相近的下载,比如这里是 ndk 版本 27.1.12297006,clang 版本 18.0.2,所以选择版本相近的 LLVM 18.1.8 。

通过下面命令,把 LLVM 18.1.8 版本源码下载到本地

git clone --depth 1 --branch llvmorg-18.1.8 https://github.com/llvm/llvm-project.git

4. LLVM 项目结构

llvm-project/
├── .clang-tidy                 # Clang-Tidy 配置文件,用于代码静态分析和代码质量检查
├── .gitattributes              # Git 属性配置文件,控制文件的检查、合并和不同平台的换行符设置
├── .git-blame-ignore-revs      # Git blame 忽略特定提交,用于排除格式化提交的影响
├── .gitignore                  # Git 忽略文件配置,定义哪些文件和目录不应纳入版本控制
├── .mailmap                    # Git 邮件映射文件,用于规范化提交者的邮箱地址
├── CODE_OF_CONDUCT.md          # 社区行为规范,规定贡献者的行为守则
├── CONTRIBUTING.md             # 贡献指南,介绍如何为项目做贡献
├── LICENSE.TXT                 # 项目开源许可证,通常为 Apache License 2.0
├── README.md                   # 项目简介和快速入门指南
├── SECURITY.md                 # 安全报告流程,说明如何报告安全漏洞
├── .ci                         # 持续集成相关配置文件
├── .github                     # GitHub 特定文件(如 issue 模板、pull request 模板、CI 配置等)

├── bolt                        # BOLT (Binary Optimization and Layout Tool),用于对二进制文件进行优化和布局调整
├── clang                       # Clang 编译器前端,支持 C、C++、Objective-C 等语言
├── clang-tools-extra           # Clang 相关的额外工具,如 clang-tidy、clangd、include-fixer 等
├── cmake                       # CMake 模块和工具,辅助构建 LLVM 项目
├── compiler-rt                 # 运行时库,包括 AddressSanitizer、ThreadSanitizer、UBSan 等
├── cross-project-tests         # 跨项目测试,确保各个子项目在一起工作时的兼容性
├── flang                       # Fortran 编译器前端,将 Fortran 代码编译为 LLVM IR
├── libc                        # LLVM 实现的标准 C 库 (libc),专为高性能场景设计
├── libclc                      # OpenCL C 标准库实现,主要用于 GPU 计算
├── libcxx                      # LLVM 的 C++ 标准库实现(如 `<iostream>`、`<vector>`)
├── libcxxabi                   # C++ ABI 支持库,用于异常处理和 RTTI(运行时类型识别)
├── libunwind                   # 轻量级栈展开库,用于实现异常处理时的栈展开功能
├── lld                         # LLVM 项目的高效链接器,替代 GNU ld
├── lldb                        # LLVM 调试器,类似于 GDB,支持调试 C、C++、Swift 等语言
├── llvm                        # LLVM 核心库,包括 IR 生成、优化和代码生成
├── llvm-libgcc                 # 提供 GCC 兼容的库(如 `__builtin` 函数的实现)
├── mlir                        # 多层次中间表示(MLIR),用于 DSL 和机器学习编译器开发
├── openmp                      # OpenMP 运行时库,支持并行编程
├── polly                       # LLVM 的循环优化器,用于自动并行化和矢量化
├── pstl                        # 并行 STL(C++ 标准模板库)实现,提升算法性能
├── runtimes                    # 各种运行时库的集合(如 libc、libc++、compiler-rt)
├── third-party                 # 第三方依赖库,如 googletest(用于单元测试)
├── utils                       # 辅助工具和脚本(如更新文档、构建脚本等)

├── .arcconfig                  # Phabricator 配置文件,用于项目代码审查
├── .arclint                    # Phabricator Lint 配置文件,用于代码风格检查
├── .clang-format              # Clang-Format 配置文件,用于统一代码风格

5. 编译 LLVM

Getting Started with the LLVM System:https://llvm.org/docs/GettingStarted.html

5.1 下载并安装必需的软件

word/media/image3.png
比如,我这里是 Windows 11,先安装 Visual Studio

5.2 安装 Python 依赖项

pip install pygments pyyaml

5.3 创建构建目录

搜索 “x64 Native Tools Command Prompt for VS” (这个工具默认配置 64 位环境)

word/media/image4.png

创建构建目录

cd D:\Projects\llvm-project

mkdir build

进入 build 目录,并检测 cmake 和 ninja 是否能正常运行

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.12.0
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

D:\App\VisualStudio\IDE>cd D:\Projects\llvm-project\build

D:\Projects\llvm-project\build>cmake --version
cmake version 3.29.5-msvc4

CMake suite maintained and supported by Kitware (kitware.com/cmake).

D:\Projects\llvm-project\build>ninja --version
1.12.1

5.4 生成编译配置

运行 CMake 生成编译配置

cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="/utf-8" -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_PROJECTS="llvm;clang;lld" ../llvm

命令参数说明

1. CMAKE_BUILD_TYPE(构建类型)

  • Release: 生成优化后的构建,无断言和调试信息。适合用于发布。

  • Debug: 生成未优化的构建,包含断言和调试信息。适合用于调试。

  • RelWithDebInfo: 生成优化后的构建,无断言,但包含调试信息。适合需要调试符号但仍然希望性能接近 Release 的情况。

  • MinSizeRel: 生成针对最小尺寸优化的构建,而非速度优化。适合用于空间受限的环境。

2. LLVM_ENABLE_RTTI / L

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值