Wrap 依赖系统手册
多平台开发的主要问题之一是管理所有依赖项。这在许多平台上都很麻烦,尤其是在没有内置包管理器的平台上。后一个问题已通过第三方包管理器来解决。它们并不是针对最终用户部署的解决方案,因为你无法告诉他们安装一个包管理器来使用你的应用程序。在这些平台上,你必须生成自包含应用程序。同样适用于目标平台缺少(最新版本的)应用程序的依赖项的情况。
传统的方法是将依赖项捆绑在自己的项目中。要么作为预构建的库和头文件,要么将源代码嵌入到源代码树中,并重写构建系统,将其作为项目的一部分进行构建。
这既繁琐又容易出错,因为始终都是手动完成的。Meson 的 Wrap 依赖系统旨在提供一种自动化的方式来完成此操作。
工作原理
Meson 有一个名为子项目的概念。它们是将一个 Meson 项目嵌套在另一个项目中的方式。任何使用 Meson 构建的项目都可以检测到它被构建为子项目,并以一种易于使用的方式构建自身(通常这意味着作为静态库)。
要将此类项目用作依赖项,你只需将它复制并提取到项目subprojects
目录中即可。
但是,有一个更简单的方法。你可以指定一个 Wrap 文件,它会告诉 Meson 如何为你下载它。如果你在构建中使用这个子项目,Meson 会在构建期间自动下载并提取它。这使得子项目嵌入变得非常容易。
所有 wrap 文件都必须具有<project_name>.wrap
形式的名称,并且必须位于subprojects
目录中。
目前 Meson 有四种类型的 wrap
- wrap-file
- wrap-git
- wrap-hg
- wrap-svn
wrap 格式
Wrap 文件以 ini 格式编写,单个标题包含 wrap 的类型,后跟描述如何获取源代码、验证它们以及在需要时修改它们的属性。名为libfoobar
的 wrap 的示例 wrap-file 将具有文件名libfoobar.wrap
,并且看起来像这样
[wrap-file]
directory = libfoobar-1.0
source_url = https://example.com/foobar-1.0.tar.gz
source_filename = foobar-1.0.tar.gz
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
wrap-git 的示例将如下所示
[wrap-git]
url = https://github.com/libfoobar/libfoobar.git
revision = head
depth = 1
wrap 接受的配置属性
-
directory
- 子项目根目录的名称,默认为 wrap 的名称。
从 0.55.0 开始,这些可以在所有 wrap 类型中使用,之前它们被保留给 wrap-file
-
patch_url
- 用于检索可选覆盖存档的下载 URL -
patch_fallback_url
- 从patch_url
下载失败时使用的备用 URL 自:0.55.0 -
patch_filename
- 下载的覆盖存档的文件名 -
patch_hash
- 下载的覆盖存档的 sha256 校验和 -
patch_directory
- 自 0.55.0 覆盖目录,当文件是本地的而不是下载的存档时,它是patch_filename
的替代方案。该目录必须放在subprojects/packagefiles
中。 -
diff_files
- 自 0.63.0 本地 diff 文件的逗号分隔列表(参见下面的Diff 文件)。 -
method
- 自 1.3.0 此子项目使用的构建系统。默认为meson
。支持的方法
特定于 wrap-file
-
source_url
- 用于检索 wrap-file 源代码存档的下载 URL -
source_fallback_url
- 从source_url
下载失败时使用的备用 URL 自:0.55.0 -
source_filename
- 下载的源代码存档的文件名 -
source_hash
- 下载的源代码存档的 sha256 校验和 -
lead_directory_missing
- 对于wrap-file
,创建前导目录名称。当源文件没有前导目录时需要。
从 0.55.0 开始,可以只在 .wrap 文件中使用 source_filename
和 patch_filename
值(不使用 source_url
和 patch_url
)来指定 subprojects/packagefiles
目录中的本地存档。当使用这种方法时,*_hash
条目是可选的。此方法应优先于下面描述的旧的 packagecache
方法。
从 0.49.0 开始,如果在项目的 subprojects/packagecache
目录中找到了 source_filename
或 patch_filename
,即使 --wrap-mode
选项设置为 nodownload
,它也会被使用,而不是下载文件。将检查文件的哈希值。
从 1.3.0 开始,如果设置了 MESON_PACKAGE_CACHE_DIR
环境变量,则使用它代替项目的 subprojects/packagecache
。这允许在多个项目之间共享缓存。此外,它可以包含一个已经解压的源代码树,只要它具有与 wrap 文件中的 directory
字段相同的目录名称。在这种情况下,该目录将在应用补丁之前复制到 subprojects/
中。
特定于基于 VCS 的 wrap
-
url
- 要克隆的 wrap-git 存储库的名称。必需的。 -
revision
- 要签出的修订版的名称。必须是:VCS 的checkout
命令的有效值(例如 git 标签),或者(对于 git)head
以跟踪上游的默认分支。必需的。
特定于 wrap-git
-
depth
- 浅层克隆存储库到 X 个提交次数。这可以节省带宽和磁盘空间,并且通常应始终指定,除非需要提交历史记录。请注意,git 始终允许浅层克隆分支,但为了浅层克隆提交 ID,服务器必须支持uploadpack.allowReachableSHA1InWant=true
。(自 0.52.0) -
push-url
- 作为 git push-url 配置的备用 URL。如果子项目将被开发并更改推送到上游,这将很有用。(自 0.37.0) -
clone-recursive
- 也克隆存储库的子模块 (自 0.48.0)
带有 Meson 构建补丁的 wrap-file
不幸的是,世界上大多数软件项目都没有使用 Meson 构建。因此,Meson 允许你指定一个补丁 URL。
出于历史原因,这被称为“补丁”,但它用作覆盖层来添加或替换文件,而不是修改它们。该文件必须是存档;它将被下载并自动提取到子项目中。提取的文件将包括给定子项目的 Meson 构建定义。
这种方法使嵌入需要构建系统更改的依赖项变得非常简单。你可以在完全隔离的情况下为依赖项编写 Meson 构建定义。这比在自己的源代码树中进行操作要好得多,尤其是在它包含数十万行代码的情况下。一旦你拥有了一个有效的构建定义,只需将 Meson 构建文件(以及你更改的其他文件)压缩并将其放到你可以下载它们的地方。
在 0.55.0 之前,Meson 构建补丁只支持 wrap-file 模式。当使用 wrap-git 时,存储库必须包含所有 Meson 构建定义。从 0.55.0 开始,Meson 构建补丁支持任何 wrap 模式,包括 wrap-git。
Diff 文件
自:0.63.0
你也可以提供 diff
格式的本地补丁文件。出于历史原因,它们被称为“diff 文件”,因为“patch”名称已经用于覆盖存档。
diff 文件由 diff_files
属性(逗号分隔列表)描述,并且必须在 subprojects/packagefiles
目录中本地可用。
Meson 将在提取或克隆项目后以及应用覆盖存档(patch_*
)后应用 diff 文件。对于此功能,必须可以使用 patch
或 git
命令行工具。
diff 文件将使用 -p1
应用,即,将第一个路径组件视为要剥离的前缀。这是由 Git 生成的 diff 的默认值。
[wrap-file]
directory = libfoobar-1.0
source_url = https://example.com/foobar-1.0.tar.gz
source_filename = foobar-1.0.tar.gz
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
diff_files = libfoobar-1.0/0001.patch, libfoobar-1.0/0002.patch
provide
部分
*自 0.55.0
Wrap 文件可以在 [provide]
部分中定义它提供的依赖项。
[provide]
dependency_names = foo-1.0
当一个 wrap 文件提供依赖项 foo-1.0
时,如上所示,任何对 dependency('foo-1.0')
的调用都会自动回退到该子项目,即使没有提供 fallback
关键字参数。名为 foo.wrap
的 wrap 文件会隐式提供依赖项名称 foo
,即使 [provide]
部分不存在也是如此。
可选依赖项,如 dependency('foo-1.0', required: get_option('foo_opt'))
,其中 foo_opt
是一个设置为 auto
的功能选项,不会回退到 wrap 文件中定义的子项目,原因有两个
- 它允许首先以其他方式查找依赖项,例如使用
cc.find_library('foo')
,只有在失败时才会回退。
# this won't use fallback defined in foo.wrap
foo_dep = dependency('foo-1.0', required: false)
if not foo_dep.found()
foo_dep = cc.find_library('foo', has_headers: 'foo.h', required: false)
if not foo_dep.found()
# This will use the fallback
foo_dep = dependency('foo-1.0')
# or
foo_dep = dependency('foo-1.0', required: false, fallback: 'foo')
endif
endif
- 有时,当未显式请求该功能时,未找到的依赖项比回退更可取。在这种情况下,
dependency('foo-1.0', required: get_option('foo_opt'))
只有在用户将foo_opt
设置为enabled
而不是auto
时才会回退。自 0.58.0 开始,如果wrap_mode
设置为forcefallback
或force_fallback_for
包含子项目,则上述可选依赖项将回退到 wrap 文件中定义的子项目。
如果希望对可选依赖项进行回退,则必须显式传递 fallback
或 allow_fallback
关键字参数。自 0.56.0 开始,dependency('foo-1.0', required: get_option('foo_opt'), allow_fallback: true)
即使 foo_opt
设置为 auto
,也会使用回退。在 0.55.0 版本上,可以使用 dependency('foo-1.0', required: get_option('foo_opt'), fallback: 'foo')
实现相同的效果。
此机制假设子项目调用 meson.override_dependency('foo-1.0', foo_dep)
,以便 Meson 知道应使用哪个依赖项对象作为回退。由于该方法是在 0.54.0 版本中引入的,因此作为对尚未使用该方法的项目的过渡帮助,可以在 wrap 文件中以 foo-1.0 = foo_dep
格式的条目提供变量名称。
例如,当使用足够新的 glib 版本时,它使用 meson.override_dependency()
覆盖 glib-2.0
、gobject-2.0
和 gio-2.0
,wrap 文件将如下所示
[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
depth=1
[provide]
dependency_names = glib-2.0, gobject-2.0, gio-2.0
对于旧版本的 glib,需要指定依赖项变量名
[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
depth=1
[provide]
glib-2.0=glib_dep
gobject-2.0=gobject_dep
gio-2.0=gio_dep
程序也可以由 wrap 文件提供,使用 program_names
键
[provide]
program_names = myprog, otherprog
使用这样的 wrap 文件,find_program('myprog')
会自动回退以使用子项目,假设它使用 meson.override_find_program('myprog')
。
CMake wrap
注意:这是实验性的,没有向后或向前兼容性保证。请参阅Meson 关于混合构建系统的规则。
由于 CMake 模块不知道提供的依赖项的公共名称,因此 CMake .wrap
文件不能使用 dependency_names = foo
语法。相反,应该使用 dep_name = <target_name>_dep
语法,其中 <target_name>
是 CMake 库的名称,所有非字母数字字符都被下划线 _
替换。
例如,一个 CMake 项目,它的 CMakeList.txt
中包含 add_library(foo-bar ...)
,并且应用程序通常使用依赖项名称 foo-bar-1.0
(例如,通过 pkg-config)来找到它,则该项目将拥有一个像这样的 wrap 文件
[wrap-file]
...
method = cmake
[provide]
foo-bar-1.0 = foo_bar_dep
Cargo 包裹
注意:这是实验性的,没有向后或向前兼容性保证。请参阅Meson 关于混合构建系统的规则。
Cargo 子项目会自动覆盖 <package_name>-<version>-rs
依赖项名称
-
package_name
在Cargo.toml
文件的[package] name = ...
部分定义。 -
version
是从[package] version = ...
推断出来的 API 版本,如下所示-
x.y.z
-> 'x' -
0.x.y
-> '0.x' -
0.0.x
-> '0' 这允许为同一 crate 的不兼容版本创建不同的依赖项。
-
-
-rs
后缀用于与常规系统依赖项区分开来,例如gstreamer-1.0
是系统 pkg-config 依赖项,而gstreamer-0.22-rs
是 Cargo 依赖项。
这意味着当 Cargo.toml
中的包名为 foo
,版本为 1.2
时,.wrap
文件的 [provide]
部分应该包含 dependency_names = foo-1-rs
。
请注意,版本组件是在 Meson 1.4 中添加的,以前的版本使用 <package_name>-rs
格式。
Cargo 子项目需要一个 toml 解析器。Python >= 3.11 内置了一个解析器,较旧的 Python 版本需要外部的 tomli
模块或 toml2json
程序。
例如,一个包名为 foo-bar
的 Cargo 项目将拥有这样的 wrap 文件
[wrap-file]
...
method = cargo
[provide]
dependency_names = foo-bar-0.1-rs
此外,如果 meson/meson.build
文件存在,Meson 将调用 subdir('meson')
,该项目可以在其中添加通常属于 build.rs
的手动逻辑。需要遵守一些命名约定
extra_args
变量是预定义的,可以用来添加任何 Rust 参数。通常用作extra_args += ['--cfg', 'foo']
。extra_deps
变量是预定义的,可以用来添加额外的依赖项。通常用作extra_deps += dependency('foo')
。
从 *1.5.0* 开始,Cargo 包裹也可以在 (子)项目源代码树的根目录中提供 Cargo.lock
文件。Meson 将自动加载该文件并将其转换为一系列包裹定义。
使用包裹项目
包裹提供了一种便捷的方式,将项目获取到子项目目录中。然后,您可以像使用常规子项目一样使用它(参见 子项目)。
获取包裹
通常情况下,您不需要手动编写包裹。
有一个名为 WrapDB 的在线仓库,提供许多可供使用的依赖项。您可以在这里阅读有关 WrapDB 的更多信息 这里.
Meson 还提供了一个子命令来获取和管理包裹(参见 使用 wraptool)。
搜索结果是