3.1.4 添加对系统库的依赖

原文链接: https://docs.swift.org/latest/documentation/packagemanagerdocs/addingsystemlibrarydependency/

3.1.4 添加对系统库的依赖

定义库的位置,并提供模块映射,把 C 头文件暴露给 Swift。

概述

你可以借助包管理器链接系统库,把它们当作代码中的依赖使用。为此,添加一个 systemLibrary 类型的 target,并为你使用的每个系统库提供一个 module.modulemap。

使用 pkg-config 提供头文件和链接器搜索路径

在类 Unix 系统上,Swift Package Manager 可以使用 pkgConfig 为编译器提供包含库头文件和链接二进制文件所需的路径。如果你的系统不提供 pkgConfig,或者该库不包含包配置文件,你也可以直接把选项提供给 Swift 编译器。

pkgConfig 按名称查找库,这个名称就是你传给 systemLibrary 目标的参数。下面两个例子展示了用 libgit2 手动查找该库路径的做法:

1
2
$ pkg-config --cflags libgit2
-I/opt/homebrew/Cellar/libgit2/1.9.0/include

要手动提供头文件搜索路径,把 -Xcc -I/path/to/include/ 作为额外参数传给 swift build。要与上面 pkgConfig 的例子匹配,额外的命令行选项应当是:-Xcc -I/opt/homebrew/Cellar/libgit2/1.9.0/include

1
2
$ pkg-config --libs-only-L libgit2
-L/opt/homebrew/Cellar/libgit2/1.9.0/lib

要手动提供链接二进制文件的搜索路径,把 -Xlinker -L/path/to/include/ 作为额外参数传给 swift build。要与上面 pkgConfig 的例子匹配,额外的命令行选项应当是:-Xlinker -L/opt/homebrew/Cellar/libgit2/1.9.0/lib。

声明系统库

systemLibrary 定义会告诉 Swift 编译器在哪里找到该 C 库。在类 Unix 系统上构建时,包管理器可以用 pkg-config 查找库的安装位置。在 pkgConfig 参数中指定你要查找的 C 库名称。如果你希望用 Swift Package Manager 在本地安装该包(如果尚未安装),可以指定一个或多个 provider。

下面的例子给出了 libgit2 库的声明,在 macOS 上用 homebrew 安装该库,在基于 Debian 的 Linux 系统上用 apt 安装:

1
2
3
4
5
6
7
8
.systemLibrary(
    name: "Clibgit",
    pkgConfig: "libgit2",
    providers: [
        .brew(["libgit2"]),
        .apt(["libgit2-dev"])
    ]
)

编写模块映射

module.modulemap 文件声明要暴露哪些 C 库头文件、暴露其中的哪些部分,作为一个或多个可以在 Swift 代码中导入的 clang 模块。每个模块都定义了:

  • 要暴露的模块名称
  • 一个或多个要引用的头文件
  • 对 C 库名称的引用
  • 一行或多行 export,指明要向 Swift 暴露什么

例如,下面的模块映射使用头文件 git2.h,链接到 libgit2,并把 git2.h 中定义的所有函数导出给 Swift:

module Clibgit [system] {
  header "git2.h"
  link "git2"
  export *
}

请尽量引用位于同一目录中的头文件,或者使用本地路径,以获得最大的灵活性。你也可以使用绝对路径,不过那会让声明更脆弱,因为不同系统会把系统库安装在各式各样的路径下。

注意:并非所有库都能轻易地变成模块。你可能需要创建额外的垫片(shim)头文件,为 Swift 编译器提供完整编译和链接该库所需的引用。

关于模块映射结构的更多信息,参见 LLVM 文档的模块映射语言。

系统库模块的版本命名

创建模块映射时,请遵循系统打包者的约定,在模块名中带上版本信息。例如,python3 在 Debian 中的包名就叫 python3。在 Debian 中并没有一个统一的 python 包;系统打包者将其设计为可以与其他版本并存安装。基于这一点,在 Debian 系统上为 python3 创建模块映射时,推荐的名称是 CPython3。

带可选依赖的系统库

要引用一个带可选依赖的系统库,你需要再做一个包来表示那个可选库。

例如,库 libarchive 可选地依赖 xz,这意味着它可以在启用 xz 支持的情况下编译,但并不强制要求。要提供一个使用带 xz 支持的 libarchive 的包,请做一个 CArchive+CXz 包,它依赖 CXz 并提供 CArchive。