gir2swift

一个简单的 Swift GIR 解析器,用于为 .gir 文件创建 Swift 类型

macOS 11 build macOS 10.15 build Ubuntu 20.04 build Ubuntu 18.04 build gtk macOS gtk Ubuntu

入门指南

要启动一个项目,该项目使用围绕利用 gobject-introspection 的底层库的 Swift 包装器,您需要创建一些脚本,这些脚本使用 gir2swift 将 gobject-introspection XML (.gir) 文件中的信息转换为 Swift。以下是基本步骤的简要概述

  1. 在您的系统上安装先决条件(请参阅下面的 先决条件
  2. 编译 gir2swift(请参阅下面的 构建
  3. 创建一个 Swift Package Manager 模块,该模块包含您的底层库的系统目标和您想要构建的 Swift 包装器库的库目标
  4. 创建必要的模块文件(请参阅下面的 模块文件
  5. gir2swift 作为插件添加到您的 Package.swift 文件中(请参阅下面的 用法
  6. 使用 swift build 构建您的项目
  7. 如果构建阶段失败(很可能发生),请添加代码来修补生成的 Swift 源文件(例如,使用 awksed 模块文件 -- 见下文),以纠正编译器抱怨的错误

新功能?

版本 16 提供了元数据属性和集合类型的类型化泛型,例如列表和数组。

版本 15 提供了 Package Manager 插件。这需要 Swift 5.6 或更高版本(旧版本可以通过 swift52 分支使用)。

用法

通常,您不会直接构建此软件包(但为了测试,您可以 - 请参阅下面的“构建”)。相反,您可以使用 Swift Package Managergir2swift 嵌入到您自己的项目中。在安装先决条件(请参阅下面的“先决条件”)后,将 gir2swift 作为依赖项和插件添加到您的 Package.swift 文件中。这是一个例子。

Swift Package Manager 插件

// swift-tools-version:5.6

import PackageDescription

let package = Package(name: "MyPackage",
    dependencies: [
        .package(url: "https://github.com/rhx/gir2swift.git", branch: "main"),
    ],    
    targets: [
        .target(
            name: "MyPackage",
            dependencies: [
                .product(name: "gir2swift", package: "gir2swift"),
            ],
            swiftSettings: [
                .unsafeFlags(["-suppress-warnings"], .when(configuration: .release)),
                .unsafeFlags(["-suppress-warnings", "-Xfrontend", "-serialize-debugging-options"], .when(configuration: .debug)),
            ],
            plugins: [
                .plugin(name: "gir2swift-plugin", package: "gir2swift")
            ]
        )
    ]
)

为了使此插件工作,您的软件包需要一个 gir2swift-manifest.yaml 文件(位于包含 Package.swift 的同一目录中,或相关目标的 Sources 子目录中)。清单需要包含要使用的 .girpkg-config 文件的名称(不带扩展名),例如:

version: 1
gir-name: GLib-2.0
pkg-config: glib-2.0
output-directory: Sources/GLib
alpha-names: true

概要

gir2-swift [<options>] [<gir-files> ...]

参数

  <gir-files>             The .gir metadata files to process. Gir files
                          specified in CLI are merged with those specified in
                          the manifest.

选项

  -v                      Produce verbose output.
  -a                      Disables all filters. Wrappers for all C types will
                          be generated.
  --alpha-names           Create a fixed set of output files ending in A-Z.
  -e, --extension-namespace <extension-namespace>
                          Add a namespace extension with the given name.
  -n, --namespace <namespace>
                          Add a namespace with the given name.
  -s                      Create a single .swift file per class.
  --post-process <post-process>
                          Additional files to post-process.
  -p <p>                  Add pre-requisite .gir files to ensure the types in
                          file.gir are known. Prerequisities specified in CLI
                          are merged with the prerequisites found by gir2swift.
  -o <o>                  Specify the output directory to put the generated
                          files into.
  -t, --target-directory <target-directory>
                          Specify the target source directory to read the
                          manifest and configurations from.
  -w, --working-directory <working-directory>
                          Specify the working directory (package directory of
                          the target) to change into.
  --pkg-config-name <pkg-config-name>
                          Library name to pass to pkg-config. Pkg config name
                          specified in CLI trumps the one found in manifest.
  -m <m>                  Add the given .swift file as the main (hand-crafted)
                          Swift file for your library target.
  --manifest <manifest>   Custom path to manifest. (default:
                          gir2swift-manifest.yaml)
  --opaque-declarations   Skips all other generation steps and prints opaque
                          struct stylized declarations for each record and
                          class to stdout.
  -h, --help              Show help information.

描述

gir2swift 从 gobject-introspection XML (file.gir) 文件中获取信息,并创建相应的 Swift 包装器。在读取 .gir 文件时,gir2swift 还会读取您创建的许多包含附加信息的 模块文件

以下选项可用

-m Module.swift 添加 Module.swift 作为您的库目标的主要(手工制作的)Swift 文件。

-o directory 指定将生成的文件放入的输出目录。

-p pre.gir 添加 pre.gir 作为先决条件 .gir 文件,以确保 file.gir 中的类型是已知的

-s 为每个类创建一个单独的 .swift 文件

-v 生成详细输出。

示例

以下命令从 /usr/share/gir-1.0/Gio-2.0.gir 中的信息生成 Sources/GIO 中的 Swift 包装器,复制 Gio-2.0.module 中的内容,并考虑 GLib-2.0.girGObject-2.0.gir 中的信息

	gir2swift -o Sources/GIO -m Gio-2.0.module -p /usr/share/gir-1.0/GLib-2.0.gir -p /usr/share/gir-1.0/GObject-2.0.gir /usr/share/gir-1.0/Gio-2.0.gir

Gio-2.0.module 文件需要包含您想要手动添加到您的 Swift 模块的代码,例如

import CGLib
import GLib
import GLibObject

public struct GDatagramBased {}
public struct GUnixConnectionPrivate {}
public struct GUnixCredentialsMessagePrivate {}
public struct GUnixFDListPrivate {}
public struct GUnixFDMessagePrivate {}
public struct GUnixInputStreamPrivate {}
public struct GUnixOutputStreamPrivate {}
public struct GUnixSocketAddressPrivate {}

func g_io_module_load(_ module: UnsafeMutablePointer<GIOModule>) {
    fatalError("private g_io_module_load called")
}

func g_io_module_unload(_ module: UnsafeMutablePointer<GIOModule>) {
    fatalError("private g_io_module_unload called")
}

此外,您还需要一个相应的序言文件 Gio-2.0.preamble,用于导入必要的底层库,例如

import CGLib
import GLib
import GLibObject

模块文件

除了读取给定的 Module.gir 文件外,gir2swift 还会从当前工作目录读取许多模块文件,这些文件包含附加信息。这些模块文件需要与 .gir 文件具有相同的名称,但具有不同的文件扩展名

Module.preamble

此文件包含您需要作为每个生成的 .swift 文件的序言的 Swift 代码(例如,您想要导入的所有模块的 import 语句)。

Module.module

此文件包含 Swift 代码(除了 Module.preamble 之外)会进入生成的 Module.swift 文件(例如,额外的 import 语句或定义)。

Module.exclude

此文件包含您想要在输出中抑制的符号(以换行符分隔)。在此处,您应该包含 .gir 文件中 Swift 编译器无法从相关的 C 语言头文件导入的所有符号。

Module.include

此文件包含否则将被抑制的符号(以换行符分隔)(例如,因为 gir2swift 认为它们是重复的),但您希望包含在 gir2swift 输出中。

Module.verbatim

通常,gir2swift 尝试按照 .gir 文件中的定义将常量从 C 转换为 Swift。在此文件中列出的常量名称(并以换行符分隔)将不会被转换。

Module.callbackSuffixes

此文件包含被视为 C 回调的类型后缀,并将被 gir2swift 注释为 @escaping。如果未指定,则默认为 ["Notify", "Func", "Marshaller", "Callback"]

Module.namespaceReplacements

此文件包含以 \t 分隔的行,其中包含命名空间及其替换项。这可以用于解决 Swift 编译器的限制,例如区分具有相同名称的模块和类型。

Module.sed

用于后处理生成文件的 sed 脚本。

Module.awk

用于后处理生成文件的 awk 脚本。

先决条件

Swift

要构建,您至少需要 Swift 5.6;从 https://swiftlang.cn/download/ 下载 -- 如果您使用的是 macOS,请确保您也安装了命令行工具)。使用 swift --version 测试您的编译器是否工作,这应该为您提供类似以下内容的结果

$ swift --version
swift-driver version: 1.75.2 Apple Swift version 5.8 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
Target: arm64-apple-macosx13.0

在 macOS 上,或者在 Linux 上,您应该得到类似以下内容的结果

$ swift --version
Swift version 5.8.1 (swift-5.8.1-RELEASE)
Target: x86_64-unknown-linux-gnu

LibXML 2.9.4 或更高版本

这些 Swift 包装器已经过 libxml-2.9.4 和 2.9.9 的测试。它们应该适用于更高版本,但 YMMV。另请确保您已安装 gobject-introspection 及其 .gir 文件。

macOS

在当前版本的 macOS 上,您需要使用 HomeBrew 安装 libxml2(系统自带的版本不包含必要的开发头文件 -- 有关 HomeBrew 设置说明,请参阅 https://brew.sh.cn

brew update
brew install libxml2 gobject-introspection

Linux

Ubuntu

在 Ubuntu 16.04、18.04 和 20.04 上,您可以使用发行版自带的 gtk。只需使用 apt 包管理器安装即可

sudo apt update
sudo apt install libxml2-dev gobject-introspection libgirepository1.0-dev jq
Fedora

在 Fedora 上,您可以使用发行版自带的 gtk。只需使用 dnf 包管理器安装即可

sudo dnf install libxml2-devel gobject-introspection-devel jq

构建

通常,您不会直接构建此软件包,而是将其嵌入到您自己的项目中(请参阅下面的“嵌入”)。但是,您可以单独构建和测试此模块,以确保一切正常。确保您已安装所有先决条件(请参阅上文)。之后,您可以简单地克隆此存储库并使用以下命令构建命令行可执行文件(请耐心等待,这将下载所有必需的依赖项并花费一段时间进行编译)

git clone https://github.com/rhx/gir2swift.git
cd gir2swift
swift build

Xcode

在 macOS 上,您可以改用 Xcode 构建项目。为此,只需在 Xcode IDE 中打开软件包

cd gir2swift
open Package.swift

之后,使用(通常的)“构建”和“测试”按钮来构建/测试此软件包。

故障排除

以下是您可能遇到的一些常见错误以及如何修复它们。

缺少 .gir 文件

如果您收到如下错误

Girs located at
Cannot open '/GLib-2.0.gir': No such file or directory

请确保您已安装相关的 gobject-introspection 软件包(按照“先决条件”部分),包括它们的 .gir.pc 文件。

旧的 Swift 工具链或 Xcode

如果您在运行 swift build 时收到 Segmentation fault (core dumped) 或循环依赖错误,例如

warning: circular dependency detected while parsing pangocairo: harfbuzz -> freetype2 -> harfbuzz

这可能意味着您的 Swift 工具链太旧了。请确保最新的工具链是您运行 Swift 编译器时找到的工具链(请参阅上文)。

如果您得到一个旧版本,请确保在您的 PATH 中首先找到正确版本的 swift 编译器。在 macOS 上,使用 xcode-select 选择并安装最新版本,例如

sudo xcode-select -s /Applications/Xcode.app
xcode-select --install