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 起 以逗號分隔的本地差異檔案清單(請參閱下方的 差異檔案)。
  • method - 自 1.3.0 起 此子專案使用的建構系統。預設為 meson。支援的方法

特定於 wrap-file

  • source_url - 下載 URL 以檢索 wrap-file 原始碼封存檔
  • source_fallback_url - 從 source_url 下載失敗時使用的備用 URL 自:0.55.0
  • source_filename - 已下載原始碼封存檔的檔案名稱
  • source_hash - 已下載原始碼封存檔的 sha256 總和檢查碼
  • lead_directory_missing - 對於 wrap-file,建立前置目錄名稱。當原始碼檔案沒有前置目錄時需要此項。

0.55.0 版起,可以在 .wrap 檔案中僅使用 source_filenamepatch_filename 值(沒有 source_urlpatch_url)來指定 subprojects/packagefiles 目錄中的本機封存檔。使用此方法時,*_hash 條目是選用的。此方法應優先於以下描述的舊版 packagecache 方法。

0.49.0 版起,如果在專案的 subprojects/packagecache 目錄中找到 source_filenamepatch_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 個 commit。這可以節省頻寬和磁碟空間,通常應該始終指定,除非需要 commit 歷史記錄。請注意,git 始終允許淺層複製分支,但是為了淺層複製 commit id,伺服器必須支援 uploadpack.allowReachableSHA1InWant=true(自 0.52.0 起)
  • push-url - 設定為 git 推送 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 起,任何 wrap 模式(包括 wrap-git)都支援 Meson 建構修補程式。

差異檔案

自:0.63.0

你也可以提供 diff 格式的本機修補程式檔案。由於歷史原因,它們被稱為「差異檔案」,因為「修補程式」名稱已用於覆蓋封存檔。

差異檔案由 diff_files 屬性(以逗號分隔的清單)描述,並且必須在本機的 subprojects/packagefiles 目錄中可用。

Meson 將在解壓縮或複製專案後,以及在應用覆蓋封存檔 (patch_*) 後,應用差異檔案。對於此功能,必須提供 patchgit 命令列工具。

將以 -p1 應用差異檔案,也就是說,將第一個路徑元件視為要剝離的前置詞。這是 Git 產生的差異的預設值。

[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 時,即使未給出 fallback 關鍵字引數,任何對 dependency('foo-1.0') 的呼叫都會自動回復到該子專案。即使缺少 [provide] 區段,名為 foo.wrap 的 wrap 檔案也會隱式提供依賴項名稱 foo

選用依賴項,例如 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
  • 有時,當使用者未明確要求該功能時,找不到依賴項比回復更好。在這種情況下,只有在使用者將 foo_opt 設定為 enabled 而不是 auto 時,dependency('foo-1.0', required: get_option('foo_opt')) 才會回復。自 0.58.0 起,如果 wrap_mode 設定為 forcefallbackforce_fallback_for 包含子專案,則如上所示的選用依賴項將回復到 wrap 檔案中定義的子專案。

如果希望回復選用依賴項,則必須明確傳遞 fallbackallow_fallback 關鍵字引數。自 0.56.0 起,即使 foo_opt 設定為 autodependency('foo-1.0', required: get_option('foo_opt'), allow_fallback: true) 也會使用回復。在 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.0gobject-2.0gio-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-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-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)。

搜尋結果如下