创建 LLVM 项目

概述

LLVM 构建系统旨在方便构建使用 LLVM 头文件、库和工具的第三方项目。为了使用这些功能,项目的 Makefile 必须执行以下操作

  • 设置 make 变量。 Makefile 需要设置几个变量才能使用 LLVM 构建系统

    • PROJECT_NAME - 项目的名称。

    • LLVM_SRC_ROOT - LLVM 源代码树的根目录。

    • LLVM_OBJ_ROOT - LLVM 对象树的根目录。

    • PROJ_SRC_ROOT - 项目源代码树的根目录。

    • PROJ_OBJ_ROOT - 项目对象树的根目录。

    • PROJ_INSTALL_ROOT - 根安装目录。

    • LEVEL - 从当前目录到项目根目录 ($PROJ_OBJ_ROOT) 的相对路径。

  • 包含来自 $(LLVM_OBJ_ROOT)Makefile.config

  • 包含来自 $(LLVM_SRC_ROOT)Makefile.rules

您可以通过两种方式设置所有这些变量

  • 您可以编写自己的 Makefile,并在其中硬编码这些值。

  • 您可以使用预制的 LLVM 示例项目。此示例项目包含 Makefile、一个可用于配置 LLVM 位置的配置脚本,以及支持从单个源目录生成多个对象目录的功能。

如果您想设计自己的构建系统,研究其他项目和 LLVM Makefile 可能会提供足够的信息来编写您自己的 Makefile

源代码树布局

为了使用 LLVM 构建系统,您需要组织您的源代码,以便它能够从构建系统的功能中受益。主要的是,您希望您的源代码树布局看起来类似于 LLVM 源代码树布局。

在您的顶级目录下,您应该有以下目录

lib

此子目录应包含所有库源代码。对于您构建的每个库,您将在 **lib** 中有一个目录,其中包含该库的源代码。

库可以是目标文件、归档文件或动态库。 **lib** 目录只是一个方便的库放置位置,因为它将所有库都放在一个以后可以从中链接的目录中。

include

此子目录应包含项目中任何全局的头文件。全局是指这些头文件被项目中的多个库或可执行文件使用。

通过将您的头文件放在 **include** 中,LLVM 构建系统将自动找到它们。例如,如果您有一个名为 **include/jazz/note.h** 的文件,那么您的源文件只需使用 **#include “jazz/note.h”** 即可包含它。

tools

此子目录应包含所有可执行文件的源代码。对于您构建的每个程序,您将在 **tools** 中有一个目录,其中包含该程序的源代码。

test

此子目录应包含验证代码是否正常工作的测试。自动化测试尤其有用。

目前,LLVM 构建系统提供了对测试的基本支持。LLVM 系统提供了以下内容

  • LLVM 在 llvm/test 中包含回归测试。这些测试由 Lit 测试工具运行。此测试过程使用实际测试用例中的 RUN 行来确定如何运行测试。有关更多详细信息,请参阅 LLVM 测试基础设施指南

  • LLVM 包含一个名为 llvm-test 的可选软件包,该软件包提供已知可以使用 Clang 前端编译的基准测试和程序。您可以使用这些程序来测试您的代码,收集统计信息,并将其与当前的 LLVM 性能统计信息进行比较。

    目前,无法将您的测试直接挂接到 llvm/test 测试工具中。您只需要找到一种方法来自己使用该目录中提供的源代码。

通常,您需要先构建 **lib** 目录,然后构建 **tools** 目录。

编写 LLVM 风格的 Makefile

LLVM 构建系统提供了一种方便的方式来构建库和可执行文件。大多数项目的 Makefile 只需要定义几个变量。下面列出了可以设置的变量及其功能

必需变量

LEVEL

此变量是从此 Makefile 到项目源代码顶级目录的相对路径。例如,如果您的源代码位于 /tmp/src 中,那么 /tmp/src/jump/high 中的 MakefileLEVEL 设置为 "../.."

构建子目录的变量

DIRS

这是一个空格分隔的子目录列表,这些子目录应该被构建。它们将按照指定的顺序依次构建。

PARALLEL_DIRS

这是一个可以并行构建的目录列表。在构建 DIRS 中的目录之后,将构建这些目录。

OPTIONAL_DIRS

这是一个目录列表,如果它们存在,则可以构建,但如果它们不存在,则不会导致错误。它们按照列出的顺序依次构建。

构建库的变量

LIBRARYNAME

此变量包含将要构建的库的基本名称。例如,要构建名为 libsample.a 的库,则应将 LIBRARYNAME 设置为 sample

BUILD_ARCHIVE

默认情况下,库是一个 .o 文件,该文件直接链接到程序中。要构建归档文件(也称为静态库),请设置 BUILD_ARCHIVE 变量。

SHARED_LIBRARY

如果在您的 Makefile 中定义了 SHARED_LIBRARY,则将构建共享(或动态)库。

构建程序的变量

TOOLNAME

此变量包含将要构建的程序的名称。例如,要构建名为 sample 的可执行文件,则应将 TOOLNAME 设置为 sample

USEDLIBS

此变量包含一个空格分隔的库列表,这些库应链接到程序中。这些库必须是来自您的 **lib** 目录的库。库必须在没有其 lib 前缀的情况下指定。例如,要链接 libsample.a,您将 USEDLIBS 设置为 sample.a

请注意,这仅适用于静态链接库。

LLVMLIBS

此变量包含一个空格分隔的库列表,这些库应链接到程序中。这些库必须是 LLVM 库。库必须在没有其 lib 前缀的情况下指定。例如,要链接执行 IR 变换的驱动程序,您可以将 LLVMLIBS 设置为以下最小的库集:LLVMSupport.a LLVMCore.a LLVMBitReader.a LLVMAsmParser.a LLVMAnalysis.a LLVMTransformUtils.a LLVMScalarOpts.a LLVMTarget.a

请注意,这仅适用于静态链接库。LLVM 分为大量静态库,您需要的库列表可能比上面列出的库列表长得多。要查看完整的库列表,请使用:llvm-config --libs all。如以下所述,使用 LINK_COMPONENTS 可以避免设置 LLVMLIBS

LINK_COMPONENTS

此变量包含一个空格分隔的组件列表,LLVM Makefile 将这些组件传递给 llvm-config 工具以生成程序的链接行。例如,要链接所有 LLVM 库,请使用 LINK_COMPONENTS = all

LIBS

要链接动态库,请将 -l<library base name> 添加到 LIBS 变量中。LLVM 构建系统将在与静态库相同的位置查找动态库。

例如,要链接 libsample.so,您将在您的 Makefile 中添加以下行

LIBS += -lsample

请注意,LIBS 必须在包含 Makefile.common 之后出现在 Makefile 中。

其他变量

CFLAGS & CPPFLAGS

此变量可用于分别向 C 和 C++ 编译器添加选项。它通常用于添加告知编译器搜索头文件的其他目录位置的选项。

强烈建议您追加到 CFLAGSCPPFLAGS,而不是覆盖它们。LLVM 的 Makefiles 中可能已经包含了一些有用的选项,您可能不想覆盖它们。

目标代码的放置位置

构建的库和可执行文件的最终位置将取决于您是进行 DebugRelease 还是 Profile 构建。

所有库(静态和动态)都将存储在 PROJ_OBJ_ROOT/<type>/lib 中,其中 type 分别为 DebugReleaseProfile,用于调试、优化或概要分析构建。

可执行文件

所有可执行文件都将存储在 PROJ_OBJ_ROOT/<type>/bin 中,其中 type 分别为 DebugReleaseProfile,用于调试、优化或概要分析构建。

更多帮助

如果您有任何疑问或需要任何帮助来创建 LLVM 项目,LLVM 团队将非常乐意提供帮助。您始终可以在 Discourse 论坛 上发布您的问题。