为HAT(带有TOML注解的标题)包提供工具
项目描述
HAT文件格式
HAT 是一种用于打包 C 编程语言编译库的格式。HAT 代表 “Head Annnotated with TOML”,意味着标准的 C 头文件被 TML 标记语言中的有用元数据所装饰。
一个 HAT 包包含一个库文件和一个或多个 .hat
文件。库文件可以是静态库(在 POSIX 系统上的 .a
文件或在 Windows 系统上的 .lib
文件)或动态库(在 POSIX 系统上的 .so
文件或在 Windows 系统上的 .dll
文件及其伴随的 .lib
导入库文件)。为了文档的简洁性,当讨论 HAT 包中的“库文件”作为一个单元时,我们指的是单个静态库文件(.a
或 .lib
),在 POSIX 上的单个动态库文件(.so
),或在 Windows 上构成动态库的文件对(.dll
和 .lib
导入库文件)。请注意,由于 HAT 包只包含一个“库文件”,因此它不能同时包含静态和动态库,因此如果 HAT 包包含 Windows 动态库,则包中的 .lib
文件始终是导入库,并且没有关于“库文件”(或文件对)的歧义。
库文件包含实现 HAT 包中函数的所有编译后的目标代码。每个 .hat
文件包含标准 C 函数声明(如典型的 .h
文件)和 TML 标记语言中的元数据。伴随每个函数声明的元数据描述了如何调用该函数以及它是如何实现的。元数据旨在易于人类阅读和机器读取,提供结构化和系统化的文档,并允许下游工具检查包内容。
每个 .hat
文件都有这样一个便利的特性,即它同时是有效的 h 文件和有效的 TOML 文件。换句话说,文件的结构是这样的,C 编译器会忽略 TOML 元数据,而 TOML 解析器会将整个文件理解为一个有效的 TOML 文件。我们使用一种称为 “帽技巧” 的技术来实现这一点,下面将进行解释。
HAT 格式解决了什么问题?
C 是最受欢迎的编程语言之一,但它也存在严重的不足。特别是,C 库通常是不可见的,缺乏系统化的文档和内省机制。这最好用一个例子来说明
假设我们使用 C 实现一个 10x10 矩阵的就地列归一化。换句话说,这个函数接受一个 10x10 矩阵 A
,并将每一列除以该列的欧几里得范数。该函数的高度优化实现将针对目标计算机的特定硬件属性进行定制,例如其缓存大小、CPU 核心数量,甚至可能包括 GPU 的存在。在 h 文件中声明此函数可能如下所示
void normalize(float* A);
伴随的库文件将包含此函数的编译后的机器代码。库/头文件对是透明的,因为它提供的信息很少,关于如何使用该函数、其依赖项以及其实现方式。具体来说
- 指针
float* A
指的是什么?根据惯例,可以合理地假设A
指向包含 100 个矩阵元素的数组的第一个元素,但这并没有明确说明。 - 函数期望矩阵元素以行主序、列主序、Z 序还是其他方式出现?
- 数组
A
的大小是多少?我们可能知道数组是 100 个元素长,但这个信息并没有明确说明。 - 我们可以看到
A
不是const
,因此我们知道其元素可以被函数更改,但它是一个“只输出”数组(其初始值被覆盖)还是一个“输入/输出”数组?我们有一些辅助知识,即A
既是输入也是输出,但这一点并没有明确说明。 - 这个函数是为Windows还是Linux编译的?
- 它需要链接到C运行时库或其他库吗?
- 函数是为哪个指令集编译的?它依赖于SSE扩展?AVX?AVX512?
- 这是一个多线程实现吗?实现假设了固定的CPU核心数吗?
- 实现依赖于GPU硬件吗?
- 谁创建了这个库?它有版本号吗?它是开源许可证下分发的吗?
上述一些问题可以通过阅读h文件注释中提供的人类可读文档、README.txt
或LICENSE.txt
文件中的文档或描述库的网页来回答。一些信息可能隐含在库名称或函数名称中(例如,假设函数被命名为“normalize_10x10_singlecore”)或通过常识(例如,如果任何地方都没有提到GPU,则函数可能不需要GPU)。尽管如此,C没有一种规范化的系统化方式来表示所有这些重要信息。此外,人类可读的文档不会将这些信息暴露给下游编程工具。例如,想象一个下游工具检查库并自动创建测试,以测量每个函数的性能。
HAT包格式试图通过在TOML中为每个声明的函数添加描述性元数据来用透明度取代这种不透明性。
HAT技巧
如上所述,.hat
文件同时是一个有效的h文件和一个有效的TOML文件。它通过以下文件结构欺骗C解析器只看到文件的有效C部分,同时保持有效TOML文件的结构。
#ifdef TOML
// Add TOML here
[declaration]
code = '''
#endif // TOML
// Add C declarations here
#ifdef TOML
'''
#endif // TOML
C编译器能看到什么?假设TOML
宏没有定义,解析器忽略#ifdef TOML
和#endif
之间的所有内容。这留下了在// Add C declarations here
处代替的内容。
TOML解析器能看到什么?首先请注意,在TOML中,#
是一个注释转义字符,因此#ifdef
和#endif
行被忽略为注释。任何在// Add TOML here
处代替的TOML代码将被正常解析。最后,定义了一个名为[declaration]
的特殊TOML表,其中包含一个名为code
的键,其值为所有C声明的多行字符串。
为什么将TOML和C声明放在同一文件中很重要?为什么不将TOML元数据放在单独的文件中?由于C已经将包代码分为库文件和h文件,因此这是一个问题,因为用户必须担心与库文件的错误版本一起分发.h
文件。我们不希望通过添加另一个单独的文件来使事情变得更糟。将元数据保留在函数声明相同的文件中确保每个声明永远不会与其元数据分离。
多个.hat
文件
HAT 格式定义了不同类型的元数据。某些类型的元数据(如目标操作系统和许可证)适用于打包库文件中的所有功能,而其他类型的元数据(如输入和输出参数的指定)则按每个功能定义。因此,如果两个功能需要不同的元数据,并且该类型元数据在文件范围内定义,则这些功能必须在单独的 .hat
文件中声明。例如,如果一个功能使用 AVX512 指令编译,而第二个功能只能使用 SSE 指令,那么这些功能必须在单独的 .hat
文件中定义。另一方面,这两个功能可以共存于单个库文件中(请记住,HAT 包有一个单独的库文件)。
上述限制会影响包中 .hat
文件的数量。此外,包的作者可能决定将功能拆分成单独的 .hat
文件以提高可读性或组织结构。
HAT 架构
每个 .hat
文件中的 TOML 元数据遵循由 TOML 架构 定义,该架构位于 schema/hat.tosd
。可以在 samples 目录 中找到 .hat
文件示例。
HAT 工具
用于处理 HAT 包的工具可以作为 Python 轮子 提供。
要求:Python 3.7 及以上。
pip install hatlib
您也可以克隆此存储库并在本地构建包
cd <path_to_repo>
pip install build
python -m build
pip install dist/hatlib-<version>-py3-none-any.whl
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源分发
构建发行版
hatlib-0.0.41.tar.gz的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | 77bd8f85aaf3669a35b05dafff255cedd018b9d3c7b99e77017aa9bbdcb1d87e |
|
MD5 | 53ca5c2f4a344cc40ca927780dc4dace |
|
BLAKE2b-256 | 8b38112c2de2cc3c1ce0c02e5b200749370243f43e7ee1e5b948274d88e6c06c |
hatlib-0.0.41-py3-none-any.whl的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | 347f3b4f7ebb2920c36826ca424b378b0e6366f8324260fadc61b78b9e954c88 |
|
MD5 | 986151a5656f344b4b9b2d2f026ae7a7 |
|
BLAKE2b-256 | fdf8cc59870ef4a7d06ebadcdeb67a14aef41b85c8630727264fbaccdfcc372d |