編譯 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 在建置目標中遇到 Vala 原始碼檔案時,會使用 dependency()
函式來尋找相關的 VAPI、C 標頭和連結器旗標。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 編譯器。
當搭配 Vala 的 [GtkTemplate]
、[GtkChild]
和 [GtkCallback]
屬性使用 GTK+ 的使用者介面定義檔案時,需要執行此操作。這需要將 --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 繫結。因為 POSIX 包含 Unix 系統上的標準 C 函式庫,所以沒有 pkg-config 檔案。只需要 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 自省和語言繫結
「繫結」允許另一種程式設計語言使用以 Vala 編寫的函式庫。因為 Vala 使用 GObject 類型系統作為其執行時期類型系統,所以很容易使用自省來產生繫結。Vala 函式庫的 Meson 建置可以產生 GObject 自省中繼資料。然後,中繼資料會在具有 語言特定工具的獨立專案中使用,以產生繫結。
中繼資料的主要形式是 GObject 自省儲存庫 (GIR) XML 檔案。GIR 主要由在編譯時產生繫結的語言使用。在執行階段產生繫結的語言大多使用從 GIR 產生的 typelib 檔案。
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')
搜尋結果為