使用Botan后端的Sequoia OpenPGP编译Wasm绑定失败问题
问题:将Sequoia OpenPGP(Botan后端)Rust应用编译为WebAssembly的问题
我尝试把基于Sequoia OpenPGP(以crypto-botan为后端)的Rust应用编译为WebAssembly供前端使用,遇到了编译和运行的双重问题,以下是相关代码和问题详情:
代码实现
lib.rs
仅暴露生成公钥的函数:
use sequoia_openpgp::{cert::{CertBuilder, CipherSuite}, serialize::MarshalInto}; use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen] pub fn generate_certificate(email: &str) -> String { let certificate = CertBuilder::general_purpose(CipherSuite::RSA4k, Some(email)) .generate() .unwrap() .0; let armored = &certificate.armored(); String::from_utf8(armored.to_vec().unwrap()).unwrap() }
Cargo.toml
[package] name = "wasmtest" version = "0.1.0" edition = "2021" resolver = "2" [dependencies] sequoia-openpgp = { version = "1.21", default-features = false, features = [ "crypto-botan", ] } wasm-bindgen = "0.2.92" [lib] crate-type = ["cdylib", "rlib"] [build-dependencies] num_cpus = "1.16.0" pkg-config = "0.3.30"
build.rs
手动编译Botan子模块(版本3.5.0):
use core::panic; use std::{cmp::max, env, path::Path, process::Command}; fn main() { env::set_var("RUST_BACKTRACE", "full"); build_botan(); } fn build_botan() { println!("cargo:rerun-if-changed=./botan/src/"); println!("cargo:rerun-if-changed=./botan/configure.py"); let out_dir = env::var("OUT_DIR").unwrap(); let botan_path = Path::new(&out_dir).join("botan_output"); let lib_path = botan_path.join("lib"); println!( "cargo:rustc-link-search=native={}", lib_path.to_string_lossy() ); configure_botan(&botan_path); let num_jobs = max(num_cpus::get() - 2, 1); make_botan(num_jobs); make_install_botan(); } fn configure_botan(botan_path: &Path) { let mut command = Command::new("python3"); let botan_prefix = botan_path.to_string_lossy().into_owned(); // 最初的配置参数 let mut config_args = vec![ "configure.py".to_string(), "--cpu=wasm".to_string(), "--os=emscripten".to_string(), "--prefix".to_string(), botan_prefix, ]; command.args(&config_args); let status = command.current_dir("./botan").status().unwrap(); if !status.success() { panic!(); } } fn make_botan(num_jobs: usize) { #[cfg(unix)] let status = Command::new("make") .args(["--directory", "./botan", "-j", &num_jobs.to_string()]) .status() .unwrap(); if !status.success() { panic!(); } } fn make_install_botan() { #[cfg(unix)] let status = Command::new("make") .args(["--directory", "./botan", "install"]) .status() .unwrap(); if !status.success() { panic!(); } }
.cargo/config.toml
[build] target = "wasm32-unknown-unknown"
遇到的问题
- 首次编译成功但前端运行报错
执行wasm-pack build --target web编译成功,但在HTML页面运行时控制台报错:
Uncaught TypeError: Failed to resolve module specifier "env"
检查WAT文件发现存在未绑定的模块导入,例如:
(import "env" "botan_mp_init" (func (;4;) (type 6)))
- 修改Botan配置后编译失败
调整Botan的configure参数后,再次执行编译时出现错误:
thread 'main' panicked at /Users/antonioumbertoaramini/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasm-bindgen-wasm-interpreter-0.2.92/src/lib.rs:266:22: non-i32 constant note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Error: Running the wasm-bindgen CLI Caused by: Running the wasm-bindgen CLI Caused by: failed to execute `wasm-bindgen`: exited with exit status: 101 full command: "/Users/antonioumbertoaramini/.cargo/bin/wasm-bindgen" "/Users/antonioumbertoaramini/Documents/Projects/wasmtest/target/wasm32-unknown-unknown/release/wasmtest.wasm" "--out-dir" "/Users/antonioumbertoaramini/Documents/Projects/wasmtest/pkg" "--typescript" "--target" "web"
解决思路与线索
- 调整Botan的编译目标适配性
当前使用的--os=emscripten是针对Emscripten环境的,和wasm32-unknown-unknown纯Wasm目标不匹配。尝试移除--os=emscripten,改用--os=none,同时确认Botan 3.5.0是否支持纯Wasm编译,必要时升级到Botan最新版本。 - 替换后端简化流程
放弃手动编译Botan的复杂流程,改用sequoia-openpgp的crypto-rust纯Rust后端,完全避开C++代码编译到Wasm的兼容性问题。 - 处理
env模块依赖wasm32-unknown-unknown目标下,C/C++编译的代码会依赖env模块的系统调用,纯Wasm环境没有这些绑定。可以尝试:- 使用
wee_alloc替代默认内存分配器 - 手动实现缺失的
env模块函数,或者通过js-sys/web-sys调用Web API模拟
- 使用
- 排查
non-i32 constant错误
该错误通常是Wasm代码中出现非i32类型常量导致的,尝试:- 在Botan configure时添加
--disable-modules排除非必要模块,降低编译复杂度 - 启用Botan的Wasm特定优化选项(如
--enable-wasm,如果存在) - 升级Rust编译器到1.70+版本,确保支持最新Wasm标准
- 在Botan configure时添加
内容的提问来源于stack exchange,提问作者Antonio Umberto Aramini
相关产品推荐
相关产品推荐

