C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

Rust で cdylib/wasm を吐く crate を分割したら依存先の機能を呼べなくなり、なんとなく extern crate を明示してみたら can't find されて5分くらい悩んだメモ

だいじな事:

  • crate を分割したら、お呼ばれされる側の Cargo.toml で [lib]crate-type が明示的に rlib を吐かない定義になっていないか確認しよう!

期待動作する例

# crate aaa に依存される側の crate bbb の Cargo.toml
# ☆ ↓ src/lib.rs ありの crate では書かなくても同義扱いなのだけど、今回のメモの本質的な部分なのであえて明示しました。
[lib]
crate-type = [ "rlib" ]
# crate bbb をに依存する側の crate A の Cargo.toml
[dependencies]
bbb = { path = "../bbb" }
// crate bbb に依存する crate aaa の main.rs
// ◎ Rust を edition = "2018" で使う場合は extern carate は不要です; あっても問題ないけど
extern crate bbb;
// ◎ use しなくてもシンボルへの完全なパスを書けば使えます
use bbb::some_module::some_sub_module::awesome_feature;
// ◎ crate bbb に分割した何かを使う的な模擬コード
let my_hoge = awesome_feature::hoge();

5分くらい悩んだダメな例

# crate aaa に依存される側の crate bbb の Cargo.toml
[lib]
crate-type = [ "cdylib" ] # ☆ rlib 出力が無いと依存してくれる側の .rs から extern して密結合できないのです。うっかり

解説

分割前の crate が .wasm を吐くとか、 .so/.dll/.dylib 的なそれを吐くのがプロジェクト単位での出力の場合、 [lib]crate-type = [ "cdylib" ] とか定義しているはずです。そのような aaa から bbb を分割する際に、 Cargo.tml の内容を aaa の複製を元に書き出し、 cdylib しか出力しない crate bbb を定義してしまうと、 crate aaa から [dependencies] で依存する事はできますが、rlib が無い状態では rust のソースコードから extern して密結合的に使う事はできません。 crate bbb が cdylib を出力する定義では crate aaa のビルドでも .wasm あるいは .so/.dll/.dylib 的なそれはビルドされます。その出力「も」欲しい場合もあるかとは思いますが、今回は crate aaa を整理のために crate bbb と分割し、 crate aaa から crate bbb へ依存するのが目的のため rlib 出力を追加定義または rlib 出力のみに変更するのが期待動作する分割に必要です。