環境
- 記事作成時: 2022/01/27
- Windows10
- WSL2
- rustc 1.58.1 (db9d1b20b 2022-01-20)
- cargo 1.58.0 (f01b232bc 2022-01-19)
can't find library hoge
, rename file to src/lib.rs
or specify lib.path
wasm-pack build
をしたときに以下のようなエラーが発生しました。
$ wasm-pack build
Error: Error during execution of `cargo metadata`: error: failed to parse manifest at `/mnt/c/Users/takeg/Desktop/myspace/workspace/mywasm/Cargo.toml`
Caused by:
can't find library `mywasm`, rename file to `src/lib.rs` or specify lib.path
デフォルトでは wasm-pack build
のターゲットは src/lib.rs
になっているので、そのようにファイル名をリネームするといいです。
lib.rs
にリネームしたくなかったら、ターゲットのファイル名を Cargo.toml
の lib.path
に指定するといいです。
たとえば src/mywasm.rs
というファイルを wasm-pack build
のターゲットにしたかったら、以下のように Cargo.toml
の [lib]
セクションの path
に追加します。
[package]
略
[lib]
path = "src/mywasm.rs"
error: the wasm32-unknown-unknown target is not supported by default
以下のようなエラーが発生しました。
$ wasm-pack build
[INFO]: Checking for the Wasm target...
[INFO]: Compiling to Wasm...
Compiling proc-macro2 v1.0.36
Compiling syn v1.0.86
Compiling wasm-bindgen-shared v0.2.79
Compiling log v0.4.14
Compiling getrandom v0.2.4
Compiling wasm-bindgen v0.2.79
error: the wasm32-unknown-unknown target is not supported by default, you may need to enable the "js" feature. For more information see: https://docs.rs/getrandom/
--> /home/taketakeyyy/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.4/src/lib.rs:225:9
|
225 | / compile_error!("the wasm32-unknown-unknown target is not supported by \
226 | | default, you may need to enable the \"js\" feature. \
227 | | For more information see: \
228 | | https://docs.rs/getrandom/#webassembly-support");
| |________________________________________________________________________^
error[E0433]: failed to resolve: use of undeclared crate or module `imp`
--> /home/taketakeyyy/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.4/src/lib.rs:252:5
|
252 | imp::getrandom_inner(dest)
| ^^^ use of undeclared crate or module `imp`
For more information about this error, try `rustc --explain E0433`.
error: could not compile `getrandom` due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed
Error: Compiling your crate to WebAssembly failed
Caused by: failed to execute `cargo build`: exited with exit status: 101
full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"
エラーメッセージ中の For more information see のリンク先を参照し、Cargo.toml
に getrandom = { version = "0.2", features = ["js"] }
を追加したらエラーは消えました。
[dependencies]
getrandom = { version = "0.2", features = ["js"] }
error: const definitions aren't supported with #[wasm_bindgen]
以下のようなエラーが発生しました。
$ wasm-pack build
[INFO]: Checking for the Wasm target...
[INFO]: Compiling to Wasm...
Compiling mywasm v0.1.0 (/mnt/c/Users/takeg/Desktop/myspace/workspace/mywasm)
error: const definitions aren't supported with #[wasm_bindgen]
--> src/mywasm.rs:10:5
|
10 | pub const WIN: i32 = 10;
| ^^^^^^^^^^^^^^^^^^^^^^^^
#[wasm_bindgen]
は const
には対応していないらしいので、該当の#[wasm_bindgen]
を削除します。
ちなみに以下のようにしていました。
#[wasm_bindgen]
pub struct Eval {}
#[wasm_bindgen]
impl Eval {
pub const WIN: i32 = 10;
pub const LOSE: i32 = -10;
pub const DRAW: i32 = 0;
}
the trait FromWasmAbi
is not implemented for hoge
以下のようなエラーが発生しました。
$ wasm-pack build
[INFO]: Checking for the Wasm target...
[INFO]: Compiling to Wasm...
Compiling mywasm v0.1.0 (/mnt/c/Users/takeg/Desktop/myspace/workspace/wasm-test/)
error[E0277]: the trait bound `Node: FromWasmAbi` is not satisfied
--> src/lib.rs:45:1
|
45 |
| ^^^^^^^^^^^^^^^ the trait `FromWasmAbi` is not implemented for `Node`
|
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
たとえば the trait `FromWasmAbi` is not implemented for `Node`
とあったら、自分で作ったRustコード中の Node
に #[wasm_bindgen]
をつけ忘れています。
#[wasm_bindgen]
pub struct Node {
pub eval: i32,
pub h: usize,
pub w: usize,
}
Rust で JavaScript の alert
や console.log
を使いたい
を参考にして使えるようにしておくと、デバッグが楽になります。
以下では、Rustで console.log
を以下のようにして呼び出しています。
console_log!("aiueo");
Vec<T>
に対応していない(?)
wasmのRustではVec型をreturnできない や Allow returning Vec の議論を見るとわかるように、Vec<T>
をwasmで扱うにはコツがいります。というか、Rust <-> JavaScript間で型をやりとりすることにコツがいります。
とりあえず Supported Types | The wasm-bindgen
Guide を見るといいかもしれません。
色々調べた感じ、主な解決方法としては JSON形式でRust <-> JavaScrit間をやりとりすることっぽいです。これぞ JavaScript って感じがしますね。この方法は後述する"serde-serialize" Feature を使うことで簡単に実現できます。
このあたりの型のやりとりに関しては The wasm-bindgen
Guide のチュートリアルを進めつつ、自分のやりたいことに寄せて改造していくと勘所をつかむことができると思います。
Vec<i32>
を返すには?
普通に返すことができます。ただ、引数に &Vec<i32>
や &mut Vec<i32>
は使うことはできません。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn return_vec_i32() -> Vec<i32> {
let v = vec![11,22,33];
v
}
#[wasm_bindgen]
pub fn print_vec_i32(v: Vec<i32>) {
for i in 0..v.len() {
console_log!("v[{}]: {}", i, v[i]);
}
}
JavaScript側のコードは以下になります。
import * as wasm from "mywasm";
{
let v = wasm.return_vec_i32();
wasm.print_vec_i32(v);
wasm.print_vec_i32(v);
}
console.log
で、以下のように表示されます。
v[0]: 11
v[1]: 22
v[2]: 33
v[0]: 11
v[1]: 22
v[2]: 33
Vec<String>
を返すには?
たとえば以下のような Vec<String>
を返すような関数 return_vec_string
を作成したとします。
#[wasm_bindgen]
pub fn return_vec_string() -> Vec<String> {
let v = vec!["aaa", "bbb"];
v
}
これをコンパイルしようとしても、エラーが発生します。
$ wasm-pack build
[INFO]: Checking for the Wasm target...
[INFO]: Compiling to Wasm...
Compiling mywasm v0.1.0 (/mnt/c/Users/takeg/Desktop/myspace/workspace/mywasm/)
error[E0277]: the trait bound `std::string::String: JsObject` is not satisfied
--> src/lib.rs:92:1
|
92 |
| ^^^^^^^^^^^^^^^ the trait `JsObject` is not implemented for `std::string::String`
|
= note: required because of the requirements on the impl of `IntoWasmAbi` for `Box<[std::string::String]>`
= note: 1 redundant requirement hidden
= note: required because of the requirements on the impl of `IntoWasmAbi` for `Vec<std::string::String>`
= note: required because of the requirements on the impl of `ReturnWasmAbi` for `Vec<std::string::String>`
= note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
...
こういうときは、Box<[JsValue]> を使うのが一つの手です。これを使えば、以下のように書くことができます。
#[wasm_bindgen]
pub fn return_vec_string() -> Box<[JsValue]> {
let v = vec![JsValue::from_str("aaa"), JsValue::from_str("bbb")];
v.into_boxed_slice()
}
#[wasm_bindgen]
pub fn print_vec_string(v: Box<[JsValue]>) {
for i in 0..v.len() {
let s = format!("v[{}]: {:?}", i, JsValue::as_string(&v[i]));
console_log!("{}", &s);
}
}
JavaScript 側では以下のように呼び出します。
import * as wasm from "mywasm";
{
let v = wasm.return_vec_string();
wasm.print_vec_string(v);
}
すると、以下のように表示されます。
v[0]: Some("aaa")
v[1]: Some("bbb")
余計な Some
が入ってしまっています。これは JsValue::as_string(&v[i])
の返り値が Option<T>
だからでしょう。
Rustのコード側で Some
をとるには、以下のようにやります。
#[wasm_bindgen]
pub fn print_vec_string(v: Box<[JsValue]>) {
for i in 0..v.len() {
match JsValue::as_string(&v[i]) {
None => {},
Some(s) => {
console_log!("v[{}]: {}", i, &s);
}
}
}
}
すると以下のように表示されます。
v[0]: aaa
v[1]: bbb
Vec<Vec<i32>>
を返すには?
複雑な型になると考えるのがしんどくなります。そこで "serde-serialize" Feature を使うとほとんどの型で解決できます。
Cargo.toml
に serde-serialize
を使うための設定を追加します。
[dependencies]
wasm-bindgen = { version = "0.2.63", features = ["serde-serialize"] }
serde_json = "1.0"
serde_derive = "1.0"
serde = { version = "1.0", features = ["derive"] }
Rustのコードは以下になります。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn return_vec_vec_i32() -> JsValue{
let mut res_v: Vec<Vec<i32>> = vec![];
for _ in 0..3 {
let v = vec![1,2,3];
res_v.push(v);
}
return JsValue::from_serde(&res_v).unwrap();
}
#[wasm_bindgen]
pub fn print_vec_vec_i32(val: &JsValue) {
let v: Vec<Vec<i32>> = val.into_serde().unwrap();
for i in 0..v.len() {
for j in 0..v[i].len() {
console_log!("v[{}][{}]: {}", i, j, v[i][j]);
}
}
}
JavaScript側では以下のようにして呼び出します。
import * as wasm from "mywasm";
{
let v = wasm.return_vec_vec_i32();
wasm.print_vec_vec_i32(v);
}
すると、以下のように表示されます。
v[0][0]: 1
v[0][1]: 2
v[0][2]: 3
v[1][0]: 1
v[1][1]: 2
v[1][2]: 3
v[2][0]: 1
v[2][1]: 2
v[2][2]: 3
自作のstructを返すには?
これも serde-serialize
を使えばOKです。
Rustのコード側では以下のようにします。
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
#[derive(Default)]
#[derive(Serialize, Deserialize)]
#[wasm_bindgen]
pub struct Node {
pub eval: i32,
pub h: usize,
pub w: usize,
}
#[wasm_bindgen]
pub fn return_node() -> JsValue {
let node: Node = Node{eval: 100, h: 1, w: 2};
return JsValue::from_serde(&node).unwrap();
}
#[wasm_bindgen]
pub fn print_node(val: &JsValue) {
let node: Node = val.into_serde().unwrap();
let mut s = format!("node.eval: {}", node.eval);
alert(&s);
s = format!("node.h: {}", node.h);
alert(&s);
s = format!("node.w: {}", node.w);
alert(&s);
}
JavaScript側では以下のようにして呼び出します。
import * as wasm from "mywasm";
{
let node = wasm.return_node();
wasm.print_node(node);
}
すると以下のようにalert()が呼び出されます。