一个底层构建系统。
llbuild 是一组用于构建构建系统的库。与大多数专注于描述构建语法的构建系统项目不同,llbuild 围绕一个可重用、灵活且可扩展的通用构建引擎设计,能够解决许多类似“构建系统”的问题。该项目还包括该引擎之上的其他库,这些库提供对构建定制构建系统(例如 swift build
)或从 Ninja 清单构建的支持。
llbuild 目前包括:
一个灵活的核心引擎,能够在运行时发现新的工作。
可扩展性,适用于达到数百万节点的依赖关系图。
支持构建 Ninja 清单(例如,用于构建 LLVM、Clang 和 Swift)。
一种专为可扩展性而设计的 llbuild 原生构建描述格式。
基于库的设计,旨在支持嵌入和重用。
该项目目前产生三个顶级产品:llbuild
、swift-build-tool
和 libllbuild
/ llbuild.framework
。
llbuild
工具为 llbuild 库的各种功能提供命令行界面。它有几个可用的子工具,有关更多信息,请参阅 llbuild --help
。最重要的子工具是 Ninja 构建支持。
您可以使用 llbuild
构建基于 Ninja 的项目,使用:
$ llbuild ninja build
该工具支持 Ninja 本身支持的命令行参数的一个子集,使其可以作为兼容的替代品使用,即使是像 CMake 这样的工具,它们在配置过程中依赖于特定的 Ninja 命令行标志。
为了方便起见,如果您通过名为 ninja
的符号链接调用 llbuild
,它将自动使用此子工具。这支持将 llbuild 作为 ninja
安装到您的 PATH
中,然后将其用作 Ninja 的替代方案来构建任意项目(例如 LLVM、Clang 和 Swift)。这也是我们自托管 llbuild
的方式(通过 CMake Ninja 生成器)。
llbuild ninja
子工具还提供额外的命令,这些命令主要仅对有兴趣使用 Ninja 支持的开发人员有用。这些命令允许独立测试词法分析器、解析器和清单加载组件,并用作测试套件的一部分。
如果您想公开展示您对 llbuild 的使用,您可以自豪地利用我们方便提供的贴纸(PSD 版本也在旁边)。😁
受 Buck 的启发,llbuild ninja
支持 --profile PATH
选项来生成一个 Chromium 跟踪,用于可视化构建期间的时间花费情况。例如,以下图表是 llbuild 自身的构建情况:
swift-build-tool
产品是 Swift 包管理器使用的构建系统的命令行界面。它作为 Swift 项目构建的一部分构建,并集成到 Swift 语言快照中。
此工具构建于 BuildSystem 库之上。
libllbuild
库为 llbuild 库公开了一个 C API,第三方可以直接使用它,或者构建额外的语言绑定。 有关使用此库的 Swift 和 Python 绑定的示例,请参见 bindings。
例如,Xcode 9 中引入的新构建系统就是以这个 API 为基础的。
llbuild 的设计是 LLVM 理念的延续,即将基于库的设计应用于传统的开发者工具。Clang 遵循这种方法,提供了一个高性能的编译器和汇编器,同时也支持诸如 clang-format 或用于代码完成和索引的 libclang 接口等新工具。但是,传统构建系统和编译器之间僵硬的命令行接口仍然限制了可以在 Clang 中实现的优化和功能。
llbuild 旨在允许构建更丰富的功能构建环境,这些环境使用 API 而不是命令行界面来集成外部工具(如编译器)。通过允许构建系统和工具直接通信并进行协同设计,我们相信我们可以释放更多的优化机会,并创建更健壮、易于使用的构建系统。
有关更多信息,请参见 2016 年 LLVM 开发者大会上的 构建软件的新架构。
从抽象意义上讲,构建系统用于执行任务,同时也必须:
增量式:通过利用保存先前构建的部分输出的能力,应该能够有效地重建输出,即使输入只发生了很小的变化。
一致性:等效的输入应该始终产生与从头构建相同的结果。
持久性:结果应该被存储,以便在失败后可以中断和恢复构建,而无需重做整个计算。
并行且高效:必须能够并行执行计算的独立元素,以便尽可能高效地计算结果。
从这个角度来看,很明显,构建系统的核心技术适用于任何复杂的、长时间运行的计算,其中用户通常只需修改输入的一小部分,然后就希望重新计算结果。例如,电影编辑器应用程序通常需要重新渲染整体电影的一小部分,以响应交互式编辑,从而支持预览最终结果。但是,由于正确管理计算各部分之间依赖关系的复杂性,此类应用程序通常无法充分利用存储和部分重新计算结果的能力。
围绕通用构建引擎设计 llbuild 的部分目标是允许其用于传统上不认为需要“构建系统”的上下文中。
技术文档可在 llbuild.readthedocs.io 上找到。
欢迎并鼓励向 /swift-llbuild 贡献!请参见 向 Swift 贡献指南。
在提交拉取请求之前,请确保您已经 测试了您的更改,并且它们符合 Swift 项目的 代码贡献准则。Bug 报告应提交到 GitHub 上 swift-llbuild
存储库的 问题跟踪器中。
为了成为一个真正伟大的社区,Swift.org 需要欢迎来自各行各业、具有不同背景和广泛经验的开发人员。一个多样化且友好的社区将拥有更多的好主意、更独特的视角,并产生更多的好代码。我们将努力使 Swift 社区欢迎所有人。
为了明确我们对成员的期望,Swift 采用了贡献者公约定义的行为准则。该文档被许多开源社区使用,我们认为它很好地阐明了我们的价值观。有关更多信息,请参见 行为准则。
llbuild 正在开发中。我们希望解决的一些更重要的开放项目是:
支持使用文件签名而不是时间戳进行更改检测。
支持更丰富的数据类型,用于任务之间的通信。
任务目前仅计算单个标量值作为其结果。我们希望支持更丰富的数据类型作为任务结果,例如,任务应该能够计算结果集,并让引擎自动将集合中单个项目的添加或删除传达给下游消费者。
支持更复杂的数据库实现。
当前的实现使用 SQLite3 数据库来存储构建结果。这是一个实用的选择,但它可能是某些应用程序的性能瓶颈,而且我们不需要完整 SQL 数据库的灵活性。我们希望评估为 llbuild 设计定制解决方案的权衡。
支持透明的分布式构建。
我们希望 llbuild 具有透明地将构建分发到一系列工作机器上的功能。
支持自动审核构建一致性。
很少有构建系统能有效地诊断问题。通常,未声明的输入或行为不当的工具会导致不一致的构建结果。我们希望 llbuild 自动诊断这些问题,例如,通过定期或推测性地重建预计不会发生更改的项目并比较结果。
核心引擎队列的性能调整。
核心构建引擎使用多个工作项队列来完成其工作,并锁定支持并发操作的子集。我们希望研究将共享队列移动到使用无锁数据结构,并对队列进行微优化,以支持非常细粒度的任务细分,而不会对性能产生负面影响。
问:为什么 llbuild 包含 LLVM 的某些部分?
答:作为一个底层的、可嵌入的组件,我们希望 llbuild 本身具有一个简单的构建过程,而没有任何重要的构建时依赖项。但是,我们也希望利用为 LLVM 开发的一些数据结构和支持设施。目前,我们的解决方案是将 LLVM 支持库的某些部分纳入到存储库中,希望随着时间的推移,LLVM 将以一种更容易重用的方式分解出这些库,或者我们将开发自己独有的支持数据结构和实用程序集,并停止使用 LLVM 的数据结构和实用程序。
问:为什么 llbuild 包含 Ninja 支持?
答:llbuild 包含一个 Ninja 兼容层,该层允许使用 llbuild 核心引擎构建使用 Ninja 清单的项目。我们开发此支持作为核心引擎的概念验证,并作为引导我们自己的方式(我们使用 CMake Ninja 生成器和 llbuild 来构建 llbuild 自身)。此支持对于允许直接对 llbuild 进行基准测试比较也很有价值。
我们对 Ninja 支持的实现还包括一个单独的库,用于以编程方式加载 Ninja 清单,这可能对希望使用或操作 Ninja 文件的其他项目有用。
我们打算继续维护 Ninja 支持,以保持与主项目的兼容性。
llbuild 受到现代构建系统(如 Shake、Buck 和 Ninja)的深刻影响。我们特别感谢 Neil Mitchell 描述 Shake 算法的工作,该算法为 llbuild 用于允许在运行时发现额外工作的机制提供了灵感。
有关许可信息,请参见 https://swiftlang.cn/LICENSE.txt。