内省¶
GObject 内省(缩写为 G-I)是一种从 C 代码中提取 API 并生成二进制类型库的系统。这些类型库可供非 C 语言绑定和其他工具内省或封装原始 C 库。它使用 C 代码中文档注释中的注释系统来暴露关于 API 的额外信息,这些信息无法从代码本身读取。
使用内省¶
使用内省的第一步是在构建系统中添加它。这应该在项目开发的早期完成,因为可内省性会影响 API 设计。在使用 Meson 构建系统时,可以使用 gnome 模块 提供的 generate_gir() 函数
lib = library(...)
gir_files = gnome.generate_gir(lib,
# The list of files to be parsed
sources: [public_headers, sources],
# The namespace of the library
namespace: ns,
# The version of the API
nsversion: ns_version,
# The pkg-config file exported by the library
export_packages: 'your-library-1',
# The GIR files of the dependencies of the library
includes: gir_dependencies,
# The public header of the library
header: 'your-library.h',
extra_args: ['--quiet', '--warn-all'],
install: true,
)
这应该会生成项目的 .gir 和 .typelib 文件。
GIR 文件是人类可读的,可以手动检查以查看 API 是否已正确内省(尽管 GIR 编译过程会为任何缺失的注释或其他问题打印错误消息和警告)。GIR 文件通常由生成代码的绑定或生成项目的 API 参考文档使用。 typelib 文件是 GIR 数据的有效二进制表示形式,可以在运行时由动态语言打开。
重要提示
API 中具有 introspectable=”0” 的 API 将不会暴露给语言绑定,因为它们缺少注释或以其他方式无法在 GIR 文件中表示。
注释¶
下一步是为每个公共 API 的文档注释添加注释。如果某个特定的 API 不应在 GIR 文件中暴露,请使用 (skip) 注释。有关可用注释的文档,请参见 G-I 网站。
如果为程序编写注释,一种好的方法是将大部分代码分解为内部、私有的便利库。可以从其文档注释构建内部 API 参考手册。然后不安装该库,而是将其链接到程序中,程序本身会被安装。这种生成内部 API 文档的方法对于大型项目特别有用,因为内部代码可能很大且难以导航。
注释不必详尽添加:GIR 具有一组默认注释,它会根据各种约定应用这些注释。例如,const char* 参数或返回值不需要显式的 (transfer none) 注释,因为 const 修饰符已经暗示了这一点。学习注释的默认值需要实践。
API 设计¶
为了能够以不多的注释进行内省,API 必须遵循某些约定,例如标准的 GObject 命名约定以及可绑定 API 的约定。这是必要的,因为 C 的灵活性:代码可以编写成以任何可想象的方式运行,但高级语言不允许这种自由。因此,为了使 C API 能够表示在高级语言中,它必须符合该语言支持的行为。
此外,相同的 C API 将由多种语言访问,每种语言可能具有不同的行为;遵守 GObject 的约定和最佳实践将确保 API 在不同语言之间保持一致。
要遵循的约定快速列表
- 不要完全依赖 C 预处理器宏
内省扫描器仅理解评估为常量值的宏;如果您有复杂的功能,请始终使用真实的函数。
- 为每个变长参数函数公开基于向量的函数
并非每种语言都支持变长参数,因此您应该确保为任何变长参数或基于
va_list的函数提供基于向量的变体。- 构造函数应仅调用
g_object_new() 您不应该有设置实例内部细节的构造函数,因为大多数动态语言将直接调用
g_object_new()。例外情况是返回单例或充当工厂构造器的函数,但这些通常被归类为静态类型函数。- 不要为属性和方法使用相同的名称
各种编程语言的绑定以相同的方式公开属性和方法,并会导致冲突。
有关要遵循的完整约定列表,请参见 G-I 网站。
g-ir-scanner 工具会在遇到无法理解的代码时发出警告。您应该确保传递 --warn-all 以查看所有潜在警告的完整列表。
提示
您可能需要在 generate_gir() 参数中设置 fatal_warnings: get_option('werror'),以确保任何内省警告都会停止您的持续集成管道中的构建,就像任何编译器警告一样;这对于确保所有新添加的 API 都是可内省的很有用。