在上一章中,我们看到LLVM的构建系统是一个庞然大物:它包含数百个构建文件和数千个相互交错的构建依赖关系。更不用说,它还包含需要为异构源文件提供自定义构建指令的目标。这些复杂性促使LLVM采用了一些先进的构建系统特性,更重要的是,一个更结构化的构建系统设计。在本章中,我们的目标将是了解一些重要的指令,以便在进行树内和树外LLVM开发时编写更简洁和表达性更强的构建文件。
在本章中,我们将涵盖以下主要主题:
- 探索LLVM重要CMake指令的词汇表
- 通过CMake在树外项目中集成LLVM
技术要求
与第1章构建LLVM时节约资源类似,您可能希望从源代码构建LLVM的副本。可选的是,由于本章将涉及大量的CMake构建文件,您可能希望为CMakeLists.txt
准备一个语法高亮插件(例如VSCode的CMake Tools插件)。所有主要的IDE和编辑器应该都有现成的。此外,熟悉基本的CMakeLists.txt
语法是可取的。
探索LLVM重要CMake指令的词汇表
由于选择底层构建系统的灵活性更高,LLVM已经从GNU autoconf切换到CMake。自那以后,LLVM提出了许多自定义的CMake函数、宏和规则来优化自身的使用。本节将向您概述其中最重要和最常用的一些。我们将学习如何以及何时使用它们。
使用CMake函数添加新库
库是LLVM框架的构建块。然而,在为新库编写CMakeLists.txt
时,您不应该使用普通CMakeLists.txt
文件中出现的普通add_library
指令,如下所示:
# 在树内CMakeLists.txt文件中...
add_library(MyLLVMPass SHARED
MyPass.cpp) # 添加新LLVM库时不要这样做
在这里使用普通的add_library
有几个缺点,如下所示:
- 如第1章构建LLVM时节约资源*中所示,LLVM更倾向于使用全局CMake参数(即
BUILD_SHARED_LIBS
)来控制是否所有组件库应该静态或动态构建。使用内置指令很难做到这一点。 - 与前一点类似,LLVM更倾向于使用全局CMake参数来控制一些编译标志,例如是否在代码库中启用运行时类型信息(RTTI)和C++异常处理。
- 通过使用自定义的CMake函数/宏,LLVM可以创建自己的组件系统,为开发人员提供更高层次的抽象,以便以更简单的方式指定构建目标依赖关系。
因此,您应该始终使用下面显示的add_llvm_component_library
CMake函数:
# 在CMakeLists.txt中
add_llvm_component_library(LLVMFancyOpt
FancyOpt.cpp)
这里,LLVMFancyOpt
是最终的库名称,而FancyOpt.cpp
是源文件。
在常规CMake脚本中,您可以使用target_link_libraries
来指定给定目标的库依赖关系,然后使用add_dependencies
来分配不同构建目标之间的依赖关系,以创建明确