You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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"

遇到的问题

  1. 首次编译成功但前端运行报错
    执行wasm-pack build --target web编译成功,但在HTML页面运行时控制台报错:
Uncaught TypeError: Failed to resolve module specifier "env"

检查WAT文件发现存在未绑定的模块导入,例如:

(import "env" "botan_mp_init" (func (;4;) (type 6)))
  1. 修改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标准

内容的提问来源于stack exchange,提问作者Antonio Umberto Aramini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:33:13