编译 Vala 应用程序和库
Meson 支持编译使用 Vala 和 Genie 编写的应用程序和库。一个简单的 meson.build
文件
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
您必须始终指定 glib-2.0
和 gobject-2.0
库作为依赖项,因为所有当前的 Vala 应用程序都使用它们。 GLib 用于基本数据类型,而 GObject 用于运行时类型系统。
使用库
Meson 使用 dependency()
函数来查找相关 VAPI、C 头文件和链接器标志,当它在构建目标中遇到 Vala 源文件时。Vala 需要一个 VAPI 文件和一个或多个 C 头文件来使用库。VAPI 文件有助于将 Vala 代码映射到库的 C 编程接口。正是 pkg-config
工具在幕后使查找这些已安装的文件变得无缝。当库不存在 pkg-config
文件时,需要使用 compiler
对象的 find_library()
方法。稍后将给出示例。
注意 Vala 使用遵循 C 应用程序二进制接口 (C ABI) 的库。但是,库可以用 C、Vala、Rust、Go、C++ 或任何其他可以生成与 C ABI 兼容的二进制文件的语言编写,从而提供 C 头文件。
最简单的案例
第一个示例是对 meson.build
文件的简单添加,因为
- 库有一个
pkg-config
文件,gtk+-3.0.pc
- VAPI 与 Vala 一起分发,因此与 Vala 编译器一起安装
- VAPI 安装在 Vala 的标准搜索路径中
- VAPI,
gtk+-3.0.vapi
,与pkg-config
文件具有相同的名称
一切都在后台无缝地工作,只需要添加一行代码
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
dependency('gtk+-3.0'),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
GTK+ 是 GNOME、elementary OS 和其他桌面环境使用的图形工具包。该库的绑定,即 VAPI 文件,与 Vala 一起分发。
其他库可能具有与库本身一起分发的 VAPI。此类库将将其 VAPI 文件与其其他开发文件一起安装。VAPI 安装在 Vala 的标准搜索路径中,因此使用 dependency()
函数可以同样无缝地工作。
定位 GLib 的版本
Meson 的 dependency()
函数允许对库进行版本检查。这通常用于检查是否安装了最低版本。当设置 GLib 的最低版本时,Meson 也会使用 --target-glib
选项将此传递给 Vala 编译器。
当使用 GTK+ 的用户界面定义文件与 Vala 的 [GtkTemplate]
、[GtkChild]
和 [GtkCallback]
属性一起使用时,需要这样做。这要求将 --target-glib 2.38
或更高版本传递给 Vala。使用 Meson,这只需通过以下操作即可完成
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0', version: '>=2.38'),
dependency('gobject-2.0'),
dependency('gtk+-3.0'),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
使用 [GtkTemplate]
还要求将 GTK+ 用户界面定义文件作为 GResources 构建到二进制文件中。为了完整性,下一个示例展示了这一点
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0', version: '>=2.38'),
dependency('gobject-2.0'),
dependency('gtk+-3.0'),
]
sources = files('app.vala')
sources += import( 'gnome' ).compile_resources(
'project-resources',
'src/resources/resources.gresource.xml',
source_dir: 'src/resources',
)
executable('app_name', sources, dependencies: dependencies)
添加到 Vala 的搜索路径
到目前为止,我们已经介绍了 VAPI 文件与 Vala 或库一起分发的情况。VAPI 也可以包含在项目的源文件中。惯例是将其放在项目的 vapi
目录中。
当库没有 VAPI 或您的项目需要链接到使用 C ABI 的项目的另一个组件时,需要这样做。例如,如果项目的一部分是用 C 编写的。
Vala 编译器的 --vapidir
选项用于将项目目录添加到 VAPI 搜索路径。在 Meson 中,这使用 add_project_arguments()
函数完成
project('vala app', 'vala', 'c')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
dependency('foo'), # 'foo.vapi' will be resolved as './vapi/foo.vapi'
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
如果 VAPI 是针对外部库的,则确保 VAPI 名称与 pkg-config 文件名相对应。
vala-extra-vapis
存储库 是一个社区维护的 VAPI 存储库,这些 VAPI 没有分发。开发人员使用该存储库来共享新绑定的早期工作和对现有绑定的改进。因此,VAPI 可能会频繁更改。建议将该存储库中的 VAPI 复制到项目的源文件中。
这对于在与 vala-extra-vapis
存储库共享之前开始编写新绑定也很有用。
没有 pkg-config 文件的库
没有对应 pkg-config 文件的库可能意味着 dependency()
不适合查找 C 和 Vala 接口文件。在这种情况下,需要使用编译器对象的 find_library()
方法。
第一个示例使用 Vala 的 POSIX 绑定。没有 pkg-config 文件,因为 POSIX 在 Unix 系统上包含标准 C 库。所需要的只是 VAPI 文件,posix.vapi
。它与 Vala 一起提供,并安装在 Vala 的标准搜索路径中。Meson 只需要被告知仅为 Vala 编译器查找库
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
meson.get_compiler('vala').find_library('posix'),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
下一个示例展示了如何链接到不需要额外 VAPI 的 C 库。标准数学函数已经在 glib-2.0.vapi
中绑定,但 GNU C 库需要单独链接到数学库。在本例中,Meson 被告知仅为 C 编译器查找库
project('vala app', 'vala', 'c')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
meson.get_compiler('c').find_library('m', required: false),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
required: false
表示当使用不分离数学库的另一个 C 库时,构建将继续。见 可移植地添加数学库 (-lm)。
最后一个示例展示了如何使用没有 pkg-config 文件的库,而 VAPI 位于项目的 vapi
目录中
project('vala app', 'vala', 'c')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
dependencies = [
dependency('glib-2.0'),
dependency('gobject-2.0'),
meson.get_compiler('c').find_library('foo'),
meson.get_compiler('vala').find_library('foo', dirs: vapi_dir),
]
sources = files('app.vala')
executable('app_name', sources, dependencies: dependencies)
C 编译器对象的 find_library()
方法将尝试查找 C 头文件和要链接的库。
Vala 编译器对象的 find_library()
方法需要添加 dir
关键字以包含项目 VAPI 目录。这不会由 add_project_arguments()
自动添加。
使用 Vala 预处理器
将参数传递给 Vala 的预处理器 需要将语言指定为 vala
。例如,以下语句设置预处理器符号 USE_FUSE
add_project_arguments('-D', 'USE_FUSE', language: 'vala')
如果您需要将参数传递给 C 预处理器,则将语言指定为 c。例如,要将 FUSE_USE_VERSION 设置为 26,请使用
add_project_arguments('-DFUSE_USE_VERSION=26', language: 'c')
构建库
更改 C 头文件和 VAPI 名称
Meson 的 library()
目标会自动输出 C 头文件和 VAPI。可以通过分别设置 vala_header
和 vala_vapi
参数来重命名它们
foo_lib = shared_library('foo', 'foo.vala',
vala_header: 'foo.h',
vala_vapi: 'foo-1.0.vapi',
dependencies: [glib_dep, gobject_dep],
install: true,
install_dir: [true, true, true])
在此示例中,install_dir
数组的第二个和第三个元素表示目标,true
表示使用默认目录(即 include
和 share/vala/vapi
)。
GObject Introspection 和语言绑定
“绑定”允许其他编程语言使用用 Vala 编写的库。因为 Vala 使用 GObject 类型系统作为其运行时类型系统,所以使用内省生成绑定非常容易。Vala 库的 Meson 构建可以生成 GObject 内省元数据。然后,元数据将在单独的项目中与 特定语言的工具 一起使用以生成绑定。
元数据的主要形式是 GObject Introspection 存储库 (GIR) XML 文件。GIR 主要用于在编译时生成绑定的语言。在运行时生成绑定的语言主要使用 typelib 文件,该文件是从 GIR 生成的。
Meson 可以将 GIR 作为构建的一部分生成。对于 Vala 库,必须为 library
设置 vala_gir
选项
foo_lib = shared_library('foo', 'foo.vala',
vala_gir: 'Foo-1.0.gir',
dependencies: [glib_dep, gobject_dep],
install: true,
install_dir: [true, true, true, true])
install_dir
中的 true
值告诉 Meson 使用默认目录(即 GIR 的 share/gir-1.0
)。install_dir
数组中的第四个元素指示 GIR 文件将安装的位置。
然后,要生成 typelib 文件,请使用具有 g-ir-compiler
程序和对库的依赖关系的自定义目标
g_ir_compiler = find_program('g-ir-compiler')
custom_target('foo typelib', command: [g_ir_compiler, '--output', '@OUTPUT@', '@INPUT@'],
input: meson.current_build_dir() / 'Foo-1.0.gir',
output: 'Foo-1.0.typelib',
depends: foo_lib,
install: true,
install_dir: get_option('libdir') / 'girepository-1.0')
搜索结果为