LLVM 0: 构建步骤及目录结构

概述

   LLVM 项目包括多个组件,并以核心组件 LLVM 的名字作为项目名。这些组件包括了处理 IR 和生成目标代码的工具、库和头文件。其中 clang 作为C/C++/Object-C的前端,其本质上是使用 LLVM 核心库的驱动程序,这得益于 LLVM 优秀的模块化特性。

参考 《Getting Started with the LLVM System》 From LLVM Document.
参考 《Learn LLVM 12》 by Kai Nacke.

构建

环境准备

a. 工具包:
  编译 LLVM 需要的软件包包括 cmake, GCC, python 等, 如果在通用的 Linux 系统上,大部分软件包已经预先安装。编译工具链可以不使用 GCC,也可以使用 clang 等。

b. 克隆仓库:
$ git clone https://github.com/llvm/llvm-project.git

或者直接下载压缩包并解压后获得源代码。

开始构建

$ cd llvm-project

可先构建库及部分工具:
$ cd llvm

切换到目标分支(可选,以 llvmorg-12.0.0 为例)
$ git checkout -b llvmorg-12.0.0

执行 cmake 并创建构建目录:
$ cmake -B build -DCMAKE_BUILD_TYPE=Release

如果要使用 clang 工具链,可执行下面的命令:
$ CC=clang CXX=clang++ cmake -B build -DCMAKE_BUILD_TYPE=Release

编译:
$ cd build && make -j2

注意:上述cmake命令默认使用Makefile生成器, 使用 Ninja 生成器 可增加命令选项 -G Ninja

配置选项

  • CMAKE_INSTALL_PREFIX : 如果要将编译好的 llvm 安装到 /opt/llvm 目录, 则需要在cmake命令选项中指定 -DCMAKE_INSTALL_PREFIX=/opt/llvm,这样当执行 make install 后库、工具和头文件将分别安装到 /opt/llvm/lib 、/opt/llvm/bin 和 /opt/llvm/include。

  • CMAKE_BUILD_TYPE:

    • DEBUG: 使用调试符号构建;
    • RELEASE: 以速度优化为主的构建;
    • RELWITHDEBINFO: 使用调试符号的发布构建;
    • MINSIZEREL: 以优化生成文件大小为主的构建;默认的构建类型是 DEBUG (会占用相当大的磁盘空间)。
      要构建为发布版本,必须指定-DCMAKE_BUILD_TYPE=RELEASE
  • CMAKE_C_FLAGS: 指定 C 编译器的编译选项,初始值为 CFLAGS 环境变量。

  • CMAKE_FLAGS:指定 C++ 编译器的编译选项,初始值为 CXXFLAGS 环境变量。

  • LLVM_ENABLE_PROJECTS: 指定额外构建的子项目列表(以分号分隔),例如 clang、clang-tools-extra、lldb、compiler-rt、lld、polly、cross-project-tests 或用户自定义项目。

  • LLVM_ENABLE_RUNTIMES:指定需要构建的运行时库,例如 libcxx;libcxxabi。

  • LLVM_TARGETS_TO_BUILD:指定目标机器,默认为 LLVM_ALL_TARGETS,也可以单独指定某种目标机器,例如 AArch64AMDGPUARMAVRBPFHexagonLanaiMipsMSP430NVPTXPowerPCRISCVSparcSystemZWebAssemblyX86XCore等。

  • 其他

可以使用下面的帮助命令查询某个配置选项:
$ cmake --help-variable CMAKE_BUILD_TYPE

目录结构

llvm 核心库

  • llvm/cmake : 主要分为 modulesplatforms两个文件夹,当用户基于 LLVM 开发自己的项目时,可以引入这些 cmake 模块,达到复用和快速构建的目的。这些 cmake 模块也会随库一起安装和发布,位于<安装目录的PREFIX>/lib/cmake/llvm 目录。
  • llvm/example:示例项目
  • llvm/include: 公共头文件
  • llvm/lib:包含大部分源代码,每个子模块都会生成对应的库。这些子模块包括 IRAsmParserBitcodeAnalysisTransformsTargetCodeGenMCExecutionEngineSupport
  • llvm/bindings:对非C/C++语言的绑定,包括 go, pythonocaml
  • llvm/projects:该目录不是 LLVM 本身的一部分,但可以放置用户的二次开发项目,并可以直接使用 LLVM 现有的构建系统,达到快速开发部署的目的。
  • llvm/test
  • llvm/tools:基于 lib 中的库开发的工具,主要的包括 llvm-arllvm-asllvm-linkllillcllvm-disopt等。
  • llvm/utils

Polly

MLIR

  MLIR 是一种新型的用于构建可复用、可扩展的编译器框架。

clang

   C/C++/Object-C 前端。

flang

   Fortran前端。

lld

lldb

运行时库

  • compiler-rt:提供独立于编程语言的支持库,它包括泛型函数,例如:可在 32 位 (i386) 机上使用的 64 位除法、各种 sanitizer、模糊库和分析库。
  • libunwind:提供了基于 DWARF 标准的堆栈展开帮助函数。这通常用于 C++ 等语言的异常处理。该库用 C 编写,函数没有绑定到特定的异常处理模型上。
  • libcxxabi: 在 libunwind 上实现了 C++ 的异常处理,并为其提供了标准的 C++ 函数。
  • libclc:OpenCL 的运行时库。
  • libcxx: C++ 标准库实现。
  • libc:C 库支持。
  • OpenMP:对 OpenMP API 的支持。

clang 简单使用

预处理

cland -E main.c

词法分析

clang -fmodules -fsyntax-only -Xclang -dump-tokens main.c

其中-fmodules,指启动模块语言功能;-fsyntax-only 运行预处理器;-Xclang <arg> 将参数传递给clang-dump-tokens 转储 tokens 内部表示。

语法分析和语义分析

clang -fmodules -fsyntax-only -Xclang -ast-dump main.c

代码生成和优化

clang -emit-llvm -S main.c -o main.ll
llvm-as main.ll -o main.bc
llvm-dis main.bc -o main.ll