📦

cargo-componentから脱却するには

2024/12/26に公開

Rust 1.82.0からwasm32-wasip2tier 2のターゲットとなり、rustup target addコマンドでビルドターゲットに追加できるようになりました。

これによりcargo-componentを利用しなくても、Wasmコンポーネントを作成できるようになりました。この記事では、cargo-componentを利用してビルドしていたライブラリークレートを、cargoコマンドだけでビルドできるようにするための変更点を述べます。

cargo-componentがビルド時にやっていたことの置き換え

cargo-componentがビルド時にやっていたのは、次の作業です:

  • 必要なWITファイルの取得
  • WITファイルからのコード生成
  • cargo buildの実行

cargo-componentから脱却するためには、最初の2つを手動で行う必要があります。

必要なWITファイルの取得

プロジェクトがwasi:http/proxyのようにWargレジストリーに登録されているインターフェース定義を参照している場合、参照しているインターフェース定義を全てダウンロードする必要があります。これは、コード生成に利用するwit-bindgenwitフォルダー内のWITファイルからのみコード生成を行うためです。

そのプロジェクトが参照しているインターフェース定義は、Cargo.tomlpackage.metadata.componentセクションのtarget属性に記述されています。次の例では、wasi:http/proxy@0.2.0を参照しています。

https://github.com/chikoski/wasm-component-rust-snippets/blob/e6035c475cdfb103753e57f0985654b20687014f/wasi-http/hello-world-http/Cargo.toml#L19-L21

この定義をwkgコマンドを利用してダウンロードします:

# プロジェクトフォルダー直下にwitフォルダーを作成します
% mkdir wit
# WITファイルをダウンロードします
% wkg get wasi:http@0.2.0 -o wit/
# -o オプションで出力するフォルダーを指定します
# フォルダーであることを示すため、末尾に必ず/をつけます

wasi:http@0.2.0はさまざまなWITパッケージに依存しています。コード生成には依存しているパッケージも必要なため、これらも全てwitフォルダーにダウンロードします。

ダウンロードにはwkg wit fetchコマンドを利用します。このコマンドはwitフォルダーにあるWITファイルを読み、それらが依存するWITパッケージをまとめてダウンロードします:

% wkg wit fetch

wit-bindgenを利用したコード生成

WITファイルが用意できたので、wit-bindgenを利用してコード生成を行います。まずは依存関係にwit-bindgenを追加します。wit-bindgen-rtは必要なので、残しておきます:

https://github.com/chikoski/wasm-component-rust-snippets/blob/main/wasi-http/hello-world-http/Cargo.toml#L6-L8

次にsrc/lib.rsの先頭にコード生成のためのマクロ呼び出しを追加します:

https://github.com/chikoski/wasm-component-rust-snippets/blob/main/wasi-http/hello-world-http/src/lib.rs#L1-L4

world属性で実装するワールドを指定します。上記の例ではwasi:http/proxy@0.2.0を指定しています。また、指定したワールドが依存する他のインターフェースのコードも併せて生成するために、generate_allフラグを追加しています。

bindings::exportマクロの置き換え

コード生成をwit_bindgen::generateマクロで行うように変更したため、bindingsモジュールが生成されなくなりました。その結果、コンポーネントの実装を指定してたbindings::exportマクロが利用できなくなりました。

これを置き換えるのが、exportマクロです。これはwit_bindgen::generateマクロによって生成されるため、use句でネームスペースにシンボルを追加しなくても利用できます。コンポーネントの実装の指定は、次のように行います:

https://github.com/chikoski/wasm-component-rust-snippets/blob/main/wasi-http/hello-world-http/src/lib.rs#L30

ビルド

次のようにcargo buildコマンドでビルドできます:

% cargo component build --target wasm32-wasip2
# 依存するクレートをビルドするメッセージが表示されますが、省略します
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 20.36s

ビルドにはwasm32-wasip2がビルドターゲットに追加されている必要があります。rustup target addコマンドで追加できます:

% rustup target add wasm32-wasip2

Cargo.tomlから不要な記述を削除

cargo-componentCargo.tomlにいくつかの記述を追加します。前述した実装するワールドの指定もそのひとつです。これらの記述を残したままでも問題はありませんが、わかりやすさのため削除しても良いでしょう。

package.metadata.compoentセクションを削除することで、Cargo.tomlからcargo-component特有の記述を削除できます。

https://github.com/chikoski/wasm-component-rust-snippets/blob/main/wasi-http/hello-world-http/Cargo.toml

まとめと感想

cargo-componentの脱却には、次の2つの作業とそれに伴う細かな修正が必要でした:

  • 必要なWITファイルの取得
  • wit_bindgen::generateマクロへの置き換え

WITファイルの取得を自動化しているcargo-component便利だなというのが、実際にやってみての感想です。上記は1度やってしまえば、インターフェースの変更がない限りする必要のない作業です。インターフェースが固まっている場合は、手動でやったとしても手間が少ないように感じました。

一方で、インターフェースが固まっていない時は手間が多いかもしれません。また作業自体を忘れてしまった結果、インターフェース定義と実装が食い違うといったことも起きそうです。

またWASIのバージョンアップに追随するときにも、作業忘れによる問題もおきるように思いました。インターフェースの変更は頻繁に起こるものではありません。だからこそ、より一層自動化が必要なようにも思いました。

Discussion