使用 CMake 构建 LLVM¶
简介¶
CMake 是一个跨平台的构建生成工具。CMake 不会构建项目,它会为你的构建工具(GNU make、Visual Studio 等)生成构建 LLVM 所需的文件。
如果你是新的贡献者,请从 LLVM 系统入门 页面开始。此页面是为从旧的 configure/make 系统迁移过来的现有贡献者准备的。
如果你真的急于获得一个可用的 LLVM 构建版本,请转到快速入门部分。如果你是 CMake 新手,请从 CMake 基本用法 开始,然后在了解自己在做什么之后回到 快速入门 部分。选项和变量 部分是自定义构建的参考。如果你已经有 CMake 使用经验,那么这是推荐的起点。
本页面向 LLVM CMake 构建的用户。如果你正在寻找有关修改 LLVM CMake 构建系统的信息,你可能需要查看 CMake Primer 页面。它对 CMake 语言有一个基本的概述。
快速入门¶
我们在这里使用命令行、非交互式的 CMake 界面。
下载并安装 CMake。最低要求版本为 3.20.0。
打开一个 shell。你的开发工具必须可以通过 PATH 环境变量从这个 shell 访问。
创建一个构建目录。不支持在源代码目录中构建 LLVM。cd 到这个目录
$ mkdir mybuilddir $ cd mybuilddir
在 shell 中执行此命令,将 path/to/llvm/source/root 替换为你的 LLVM 源代码树的根路径
$ cmake path/to/llvm/source/root
CMake 将检测你的开发环境,执行一系列测试,并生成构建 LLVM 所需的文件。CMake 将对所有构建参数使用默认值。有关你可以修改的构建参数列表,请参阅选项和变量部分。
如果 CMake 无法检测到你的工具集,或者如果它认为环境不够健全,则可能会失败。在这种情况下,请确保你打算使用的工具集是唯一可以从 shell 访问的工具集,并且 shell 本身是适合你的开发环境的正确 shell。例如,如果你通过 PATH 环境变量可以访问 POSIX shell,CMake 将拒绝构建 MinGW makefile。你可以强制 CMake 使用给定的构建工具;有关说明,请参阅下面的用法部分。你可能还希望控制 LLVM 启用的目标或构建的 LLVM 组件;请参阅下面的常用 LLVM 相关变量。
CMake 运行完成后,继续使用 IDE 项目文件,或从构建目录开始构建
$ cmake --build .
--build
选项告诉cmake
调用底层构建工具(make
,ninja
,xcodebuild
,msbuild
等)当然,可以直接调用底层构建工具,但
--build
选项是可移植的。LLVM 构建完成后,从构建目录安装它
$ cmake --build . --target install
除了
--build
选项之外,带有install
参数的--target
选项告诉cmake
构建install
目标。可以通过调用构建目录中生成的
cmake_install.cmake
脚本在安装时设置不同的安装前缀$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/llvm -P cmake_install.cmake
CMake 基本用法¶
本节介绍 CMake 的基本方面,你可能在日常使用中需要用到它们。
CMake 带有丰富的文档,以 html 文件形式提供,也可以通过 cmake
可执行文件本身访问在线帮助。执行 cmake --help
获取更多帮助选项。
CMake 允许你指定构建工具(例如,GNU make、Visual Studio 或 Xcode)。如果在命令行上未指定,CMake 会尝试根据你的环境猜测要使用的构建工具。一旦它识别出你的构建工具,CMake 将使用相应的生成器为你的构建工具创建文件(例如,Makefile 或 Visual Studio 或 Xcode 项目文件)。你可以使用命令行选项 -G "生成器的名称"
显式指定生成器。要查看系统上可用的生成器列表,请执行
$ cmake --help
这将在帮助文本的末尾列出生成器名称。
生成器的名称区分大小写,并且可能包含空格。因此,你应该完全按照 cmake --help
输出中列出的那样输入它们,并用引号括起来。例如,要专门为 Visual Studio 12 生成项目文件,你可以执行
$ cmake -G "Visual Studio 12" path/to/llvm/source/root
对于给定的开发平台,可能有一个以上合适的生成器。如果你使用 Visual Studio,“NMake Makefiles” 是你可以用于使用 NMake 构建的生成器。默认情况下,CMake 选择你的开发环境支持的最具体的生成器。如果你想要其他生成器,你必须使用 -G
选项告诉 CMake。
选项和变量¶
变量自定义构建的生成方式。选项是布尔变量,可能的值为 ON/OFF。选项和变量在 CMake 命令行上定义,如下所示
$ cmake -DVARIABLE=value path/to/llvm/source
你可以在初始 CMake 调用后设置变量以更改其值。你也可以取消定义变量
$ cmake -UVARIABLE path/to/llvm/source
变量存储在 CMake 缓存中。这是一个名为 CMakeCache.txt
的文件,存储在你的构建目录的根目录中,由 cmake
生成。不建议你自己编辑它。
变量在 CMake 缓存中列出,并在本文档后面列出,变量名和类型用冒号分隔。你也可以在 CMake 命令行上指定变量和类型
$ cmake -DVARIABLE:TYPE=value path/to/llvm/source
常用 CMake 变量¶
这里列出了一些常用的 CMake 变量,以及简要说明。有关完整文档,请查阅 CMake 手册,或执行 cmake --help-variable VARIABLE_NAME
。有关控制 LLVM 功能和启用的子项目的常用变量的信息,请参阅下面的常用 LLVM 相关变量。
- CMAKE_BUILD_TYPE:STRING
这配置了
make
或ninja
构建的优化级别。可能的值
构建类型
优化
调试信息
断言
最适合用于
Release
为了速度
否
否
LLVM 和 Clang 的用户
Debug
无
是
是
LLVM 的开发者
RelWithDebInfo
为了速度
是
否
也需要调试的用户
MinSizeRel
为了大小
否
否
当磁盘空间很重要时
优化使 LLVM/Clang 运行更快,但可能会成为逐步调试的障碍。
带有调试信息的构建可能会占用大量 RAM 和磁盘空间,并且通常运行速度较慢。你可以通过使用
lld
来改善 RAM 使用情况,请参阅 LLVM_USE_LINKER 选项。断言是帮助你查找错误的内部检查。启用时,它们通常会减慢 LLVM 和 Clang 的速度,但在开发期间可能很有用。你可以手动设置 LLVM_ENABLE_ASSERTIONS 以覆盖 CMAKE_BUILD_TYPE 的默认值。
如果你正在使用 IDE(例如 Visual Studio 或 Xcode),则应使用 IDE 设置来设置构建类型。
注意:在 Windows 上(使用 MSVC 或 clang-cl 构建),CMake 的 RelWithDebInfo 设置不会启用与 Release 相同的优化。使用 Release 构建类型并设置 LLVM_ENABLE_PDB 可能是更好的选择。
- CMAKE_INSTALL_PREFIX:PATH
构建 “install” 目标时 LLVM 的安装路径。
- CMAKE_{C,CXX}_FLAGS:STRING
分别编译 C 和 C++ 源代码文件时要使用的额外标志。
- CMAKE_{C,CXX}_COMPILER:STRING
指定要使用的 C 和 C++ 编译器。如果你安装了多个编译器,CMake 可能不会默认使用你希望使用的编译器。
不常用 CMake 变量¶
这里列出了一些不常用的 CMake 变量,以及简要说明和 LLVM 相关注释。有关完整文档,请查阅 CMake 手册,或执行 cmake --help-variable VARIABLE_NAME
。
- CMAKE_CXX_STANDARD:STRING
设置构建 LLVM 时要符合的 C++ 标准。可能的值为 17 和 20。LLVM 要求 C++17 或更高版本。默认值为 17。
- CMAKE_INSTALL_BINDIR:PATH
安装可执行文件的路径,相对于 CMAKE_INSTALL_PREFIX。默认为 “bin”。
- CMAKE_INSTALL_DOCDIR:PATH
安装文档的路径,相对于 CMAKE_INSTALL_PREFIX。默认为 “share/doc”。
- CMAKE_INSTALL_INCLUDEDIR:PATH
安装头文件的路径,相对于 CMAKE_INSTALL_PREFIX。默认为 “include”。
- CMAKE_INSTALL_MANDIR:PATH
安装 manpage 文件的路径,相对于 CMAKE_INSTALL_PREFIX。默认为 “share/man”。
CMake 缓存¶
最近,LLVM 和 Clang 添加了一些更复杂的构建系统功能。利用这些新功能通常涉及在命令行上传递的复杂的 CMake 变量链。Clang 提供了一系列 CMake 缓存脚本,使这些功能更易于使用。
CMake 缓存文件使用 CMake 的 -C 标志来使用
$ cmake -C <path to cache file> <path to sources>
CMake 缓存脚本在隔离的作用域中处理,只有缓存的变量在主配置运行时保持设置。CMake 缓存变量不会重置已设置的变量,除非指定 FORCE 选项。
关于 CMake 缓存的一些注意事项
命令行参数的顺序很重要
在 -C 之前指定的 -D 参数在处理缓存之前设置,并且可以在缓存文件中读取
在 -C 之后指定的 -D 参数在处理缓存之后设置,并且在缓存文件中未设置
所有 -D 参数都将覆盖缓存文件设置
CMAKE_TOOLCHAIN_FILE 在缓存文件和命令行参数之后进行评估
建议所有 -D 选项都应在 -C 之前指定
有关通过缓存文件支持的一些高级构建配置的更多信息,请参阅 高级构建配置。
执行测试¶
测试在构建 check-all 目标时执行。例如,如果你正在使用 Makefiles,请在你的构建目录的根目录中执行此命令
$ make check-all
在 Visual Studio 上,你可以通过构建 “check-all” 项目来运行测试。有关测试的更多信息,请参阅 LLVM 测试基础设施指南。
交叉编译¶
请参阅 此 wiki 页面,了解有关如何使用 CMake 进行交叉编译的通用说明。它深入详细的解释,可能看起来令人生畏,但并非如此。在 wiki 页面上有几个示例,包括工具链文件。直接转到 “Information how to set up various cross compiling toolchains
” 部分以获得快速解决方案。
另请参阅 LLVM 相关变量部分,了解交叉编译时使用的变量。
在你的项目中嵌入 LLVM¶
从 LLVM 3.5 开始,CMake 构建系统将 LLVM 库导出为可导入的 CMake 目标。这意味着 LLVM 的客户端现在可以可靠地使用 CMake 来针对已安装的 LLVM 版本开发自己的基于 LLVM 的项目,而无需考虑它是如何构建的。
这是一个简单的 CMakeLists.txt 文件的示例,它导入 LLVM 库并使用它们来构建一个简单的应用程序 simple-tool
。
cmake_minimum_required(VERSION 3.20.0)
project(SimpleProject)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
# Set your project compile flags.
# E.g. if using the C++ header files
# you will need to enable C++11 support
# for your compiler.
include_directories(${LLVM_INCLUDE_DIRS})
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
# Now build our tools
add_executable(simple-tool tool.cpp)
# Find the libraries that correspond to the LLVM components
# that we wish to use
llvm_map_components_to_libnames(llvm_libs support core irreader)
# Link against LLVM libraries
target_link_libraries(simple-tool ${llvm_libs})
当在 CONFIG 模式下使用 find_package(...)
指令时(如上面的示例中所示),它将在各种位置查找 LLVMConfig.cmake
文件(有关详细信息,请参阅 cmake 手册)。它创建一个 LLVM_DIR
缓存条目来保存找到 LLVMConfig.cmake
的目录,或者允许用户指定目录(例如,通过将 -DLLVM_DIR=/usr/lib/cmake/llvm
传递给 cmake
命令,或者直接在 ccmake
或 cmake-gui
中设置它)。
此文件在两个不同的位置可用。
<LLVM_INSTALL_PACKAGE_DIR>/LLVMConfig.cmake
,其中<LLVM_INSTALL_PACKAGE_DIR>
是安装 LLVM CMake 模块的位置,作为已安装的 LLVM 版本的一部分。这通常是 lib 目录中的cmake/llvm/
。在 Linux 上,这通常是/usr/lib/cmake/llvm/LLVMConfig.cmake
。<LLVM_BUILD_ROOT>/lib/cmake/llvm/LLVMConfig.cmake
,其中<LLVM_BUILD_ROOT>
是 LLVM 构建树的根目录。注意:这仅在使用 CMake 构建 LLVM 时可用。
如果 LLVM 安装在你的操作系统的正常安装前缀中(例如,在 Linux 上,这通常是 /usr/
),如果 LLVM 安装正确,find_package(LLVM ...)
将自动找到 LLVM。如果 LLVM 未安装,或者你希望直接针对 LLVM 构建树进行构建,你可以使用前面提到的 LLVM_DIR
。
LLVMConfig.cmake
文件设置了各种有用的变量。值得注意的变量包括
LLVM_CMAKE_DIR
LLVM CMake 目录的路径(即,包含 LLVMConfig.cmake 的目录)。
LLVM_DEFINITIONS
在针对 LLVM 构建时应使用的预处理器定义的列表。
LLVM_ENABLE_ASSERTIONS
如果 LLVM 是使用断言构建的,则设置为 ON,否则设置为 OFF。
LLVM_ENABLE_EH
如果 LLVM 是使用异常处理 (EH) 启用的,则设置为 ON,否则设置为 OFF。
LLVM_ENABLE_RTTI
如果 LLVM 是使用运行时类型信息 (RTTI) 构建的,则设置为 ON,否则设置为 OFF。
LLVM_INCLUDE_DIRS
包含 LLVM 头文件的目录的包含路径列表。
LLVM_PACKAGE_VERSION
LLVM 版本。此字符串可以与 CMake 条件一起使用,例如,
if (${LLVM_PACKAGE_VERSION} VERSION_LESS "3.5")
。LLVM_TOOLS_BINARY_DIR
包含 LLVM 工具的目录的路径(例如
llvm-as
)。
请注意,在上面的示例中,我们将 simple-tool
与多个 LLVM 库链接。库列表是通过使用 llvm_map_components_to_libnames()
CMake 函数确定的。有关可用组件的列表,请查看运行 llvm-config --components
的输出。
请注意,对于 LLVM < 3.5,使用 llvm_map_components_to_libraries()
而不是 llvm_map_components_to_libnames()
。这现在已弃用,将在 LLVM 的未来版本中删除。
在源代码外部开发 LLVM passes¶
可以从 LLVM 的源代码树外部开发 LLVM passes(即,针对已安装或构建的 LLVM)。下面提供了一个项目布局的示例。
<project dir>/
|
CMakeLists.txt
<pass name>/
|
CMakeLists.txt
Pass.cpp
...
<project dir>/CMakeLists.txt
的内容
find_package(LLVM REQUIRED CONFIG)
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})
add_subdirectory(<pass name>)
<project dir>/<pass name>/CMakeLists.txt
的内容
add_library(LLVMPassname MODULE Pass.cpp)
请注意,如果你打算在未来的某个时候将此 pass 合并到 LLVM 源代码树中,那么使用带有 MODULE 参数的 LLVM 内部 add_llvm_library
函数可能会更有意义,方法是...
将以下内容添加到 <project dir>/CMakeLists.txt
中(在 find_package(LLVM ...)
之后)
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
include(AddLLVM)
然后将 <project dir>/<pass name>/CMakeLists.txt
更改为
add_llvm_library(LLVMPassname MODULE
Pass.cpp
)
当你完成 pass 的开发后,你可能希望将其集成到 LLVM 源代码树中。你可以通过两个简单的步骤实现它
将
<pass name>
文件夹复制到<LLVM root>/lib/Transforms
目录中。将
add_subdirectory(<pass name>)
行添加到<LLVM root>/lib/Transforms/CMakeLists.txt
中。
编译器/平台特定主题¶
特定编译器和/或平台的注意事项。
Windows¶
- LLVM_COMPILER_JOBS:STRING
指定在使用 msbuild 或 Visual Studio 构建时,每个项目要使用的最大并行编译器作业数。仅支持 Visual Studio 2010 CMake 生成器。0 表示使用所有处理器。默认为 0。
- CMAKE_MT:STRING
当使用 clang-cl 编译时,最近的 CMake 版本将默认选择 llvm-mt 作为 Manifest 工具,而不是 Microsoft 的 mt.exe。这通常会导致如下错误
-- Check for working C compiler: [...]clang-cl.exe - broken [...] MT: command [...] failed (exit code 0x1) with the following output: llvm-mt: error: no libxml2 ninja: build stopped: subcommand failed.
要解决此错误,请设置 CMAKE_MT=mt。