LLVM - 支持库

支持库(Support Library)

摘要

本文件介绍了 LLVM 的支持库(Support Library),其源码位于 lib/Supportinclude/llvm/Support 目录下。该库的目标是为 LLVM 屏蔽操作系统之间的差异,为 LLVM 所需的少量操作系统服务提供统一接口。LLVM 的大部分代码都利用了标准 C++ 的可移植性特性编写,但在某些场合需要依赖系统相关的功能,这些功能就由支持库包装。

通过将 LLVM 对操作系统接口的使用集中在一起,使 LLVM 工具链和运行时对新平台的移植变得更加容易——理论上只需移植 lib/Support 即可。该库还能避免 LLVM 代码中充斥大量 #ifdef 和对特定操作系统的特殊处理,这些都用 include/llvm/Support 提供的接口替代。

请注意,支持库并不打算成为一个完整的操作系统抽象层(比如 ACE 或 APR 之类的库),它只实现 LLVM 运行所需的能力。

支持库最初被称作 System Library,由 Reid Spencer 编写,其设计思路源自 eXtensible Programming System (XPS) 项目的类似经验。Jeff Cohen 和 Henrik Bach 等人尤其在 Win32 移植方面做出了贡献。

保持 LLVM 的可移植性

为了保障 LLVM 的可移植性,开发者需要遵循一套与支持库相关的移植规范。遵守这些规范有助于支持库高效地完成其对操作系统变异的屏蔽目标。如下章节详细说明了这些规范。

禁止引入系统头文件

除了 lib/Support 本身,LLVM 的其他源码不应直接 #include 系统头文件。开发支持库时已经尽量移除了所有这样的 #include。具体来说,包括诸如 unistd.hwindows.hstdio.hstring.h 等系统头文件,除非在 lib/Support 的实现里,其他地方都不准包含。

如果需要用到系统相关的功能,应优先使用 include/llvm/Support 下已经有的接口。如果没有合适的接口,需要补充到 include/llvm/Support 并在 lib/Support 里为所有支持的平台实现。

不暴露系统头文件

支持库必须完全屏蔽系统头文件。要获取系统级能力,LLVM 代码只能 #include "llvm/Support/Thing.h",不能引入任何系统头。即 Thing.h 也不能间接暴露任何系统头文件。这保证了 LLVM 只能通过支持库接口使用系统相关功能。

只使用标准C头文件

标准的 C 头文件(即以 “c” 开头的头文件),可以通过支持库接口暴露,这些头及其声明被认为是平台无关的。LLVM 代码可以直接包含它们,也可以通过支持库自动包含。

只使用标准C++头文件

标准的 C++ 头文件(来自 C++ 标准库和 STL)也可以通过支持库暴露,被认为平台无关。LLVM 源码可以自由包含,或通过支持库接口获得。

高层接口

lib/Support 的接口应以完成 LLVM 需求的某个“高层”功能为目标。我们不希望简单地一一包装每个系统调用。应尽量将 LLVM 会一起用到的多个系统调用打包为一个高层任务接口。

举例:要运行一个程序、等待其结束并获取返回码,在 Unix 上需要 getenvforkexecvewait 等多个调用。支持库应直接提供如 ExecuteProgramAndWait 这样的方法,实现整个过程,而不仅仅是分别包装这些操作系统调用。

总之,不能让支持库的接口直接和操作系统调用一一对应,这种设计会被视为可疑。

不要加入未使用功能

lib/Support 的接口中不能有 LLVM 实际不用的功能。我们不是在写通用的操作系统适配层,只需满足 LLVM 本身的需求即可。这有助于保持接口简单易用和被广泛采用。

不重复实现

针对某个平台的某个接口函数实现,只能写一次。如果多个平台可以共用同一实现,则务必只写一遍。对于某一类操作系统(如 Unix、Win32),这一规则都约束适用。

不使用虚拟方法

支持库的接口可能被 LLVM 频繁调用。为避免调用开销,强烈不建议用虚函数。不同平台的差异用 include 机制处理即可,无需用继承。

不暴露系统函数

系统库定义(而非 lib/Support 定义)的函数,即使不直接暴露头文件,也不能作为 lib/Support 接口暴露。这避免误用系统依赖能力。

比如典型的 stat 系统调用,其结构体内容各平台差异很大。lib/Support 不应声明或暴露 stat,而应该自定义一套文件/目录查询接口,内部可用 stat 实现,但外部看不到该名字,并保证所有平台都能实现。

不暴露系统数据

同样地,系统库定义的数据(而非 lib/Support 定义),即使不暴露头文件,也不能通过接口暴露,防止各平台差异引发的问题。

避免软错误上抛

操作系统接口通常会抛出大量的错误,其中有些是“正常/可预期的/软错误”,比如“文件不存在”“权限不够”,这些一般不算重大异常;而另一些“硬错误”,如“磁盘空间不足”“磁盘坏道”,则非常严重。
支持库要求:最大可能地内部消化软错误
如果你发现接口需要抛软错误,说明接口层次太低,应上升接口抽象等级。

比如,不要写 OpenFileForWriting,要写 OpenOrCreateFileForWriting,前者遇到“文件不存在”就抛错,而后者能解决这个“错误”。

总则如下:

  1. 只允许抛硬错误,不允许抛软错误。
  2. 抛软错误需反思接口设计。
  3. 常见的“正常/软错误”处理应封装在支持库内部,让调用者无感。

不加 throw 规范

lib/Support 的接口函数不能声明 throw(),可避免编译器插入异常处理相关代码,提高效率。实践中,系统库代码也不该抛异常。

代码组织

支持库接口的实现应按操作系统类型分文件。目前仅定义了 Unix 和 Win32 两类。以 lib/Support 下代码为例,文件应这样包含:

#if defined(LLVM_ON_UNIX)
#include "Unix/Path.inc"
#endif
#if defined(_WIN32)
#include "Windows/Path.inc"
#endif

其中 Unix/Path.inc 负责所有 Unix 变体,Windows/Path.inc 负责全部 Windows 平台。通过 #if defined(LLVM_ON_XYZ) 快速选定实现大类,具体细节再用 #ifdef 处理。

语义一致性

虽然 lib/Support 的接口实现可因平台变化极大,但只要对外表现一致即可。比如 “创建目录” 所有操作系统都好办;而 System V IPC 某些平台根本不支持,这时可以统一暴露“进程间通信”的接口,底层按能力用 System V IPC、命名管道等来实现即可,各平台语义效果一致即可,无需实现细节完全一致。

原文地址:https://llvm.org/docs/SupportLibrary.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdddn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值