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

如何实现Rust链接GHC-WASM外部库?

问题背景

近期Rust新增支持Rust+C WASM编译的编译器标志,已有成熟的Rust+C WASM编译示例仓库。由于Haskell与Rust均支持C-FFI且可编译为WASM(当前Haskell仅支持WASI目标),我希望复刻该流程,将C二进制替换为Haskell库进行链接。最终目标是构建一个Rust crate,通过构建脚本调用GHC WASM编译并静态链接指定Haskell库(例如Rust生态缺失的HaTeX),供其他WASM目标的Rust crate依赖,确保最终产物包含Haskell编译生成的WASM代码。

已尝试方案

可执行文件方案

参考Haskell WASM GHC官方仓库,通过Nix-shell搭建基础项目,结构如下:

cbits\
  wizerinit.c    <-- 复刻GHC WASM仓库的Wizer预初始化代码
src\
  Lib.hs         <-- 导出`hs_dummy_init :: IO ()`和`hs_fib :: CInt -> CInt`的FFI模块
  OtherModule.hs <-- 空模块用于验证多模块兼容性
latex-preprocessor.cabal

latex-preprocessor.cabal配置内容:

cabal-version:   3.12
name:            latex-preprocessor
version:         0

executable latex-preprocessor
  main-is:            Lib.hs
  other-modules:      OtherModule
  c-sources:          cbits/wizerinit.c
  hs-source-dirs:     src
  default-language:   GHC2021
  build-depends:       
    , base
  ghc-options:
    -Wall
    -no-hs-main
    -optl-mexec-model=reactor
    "-optl-Wl,--export=hs_dummy_init,--export=hs_fib"

执行以下命令成功生成WASM文件:

wasm32-wasi-cabal build exe:latex-preprocessor
LATEX_PREPROCESSOR_WASM="$(wasm32-wasi-cabal list-bin exe:latex-preprocessor)"
wizer --allow-wasi --wasm-bulk-memory true \
  "$LATEX_PREPROCESSOR_WASM" -o "dist-newstyle/haskell.wasm"

尝试用wasm-ld链接Rust与Haskell产物时,Rust侧使用nightly工具链并启用wasm_c_abi,lib.rs测试函数代码:

#[no_mangle]  
pub extern "C" fn add(left: usize, right: usize) -> usize {  
  left + right  
}

wasm-ld报错:wasm-ld: error: ./build/haskell.wasm: not a relocatable wasm file,推测原因是Haskell产物为可执行文件而非可重定位库。

库方案

将Cabal配置改为library stanza:

library
  exposed-modules:    Lib
  other-modules:      OtherModule
  c-sources:          cbits/wizerinit.c
  hs-source-dirs:     src
  default-language:   GHC2021
  build-depends:       
    , base
  ghc-options:
    -Wall
    -no-hs-main
    -optl-mexec-model=reactor
    "-optl-Wl,--export=hs_dummy_init,--export=hs_fib"

执行wasm32-wasi-cabal build lib:latex-preprocessor生成.a和.so库,对.a执行wizer时出现魔数匹配失败,遂省略该步骤。

修改后构建脚本无报错,但输出的.wat几乎为空;添加--whole-archive标志后,Rust的add函数可正常导出,但链接Haskell库时出现大量未定义符号错误:

wasm-ld: error: ./build/haskell.wasm(Lib.o): undefined symbol: __Sp
...
wasm-ld: error: ./build/haskell.wasm(wizerinit.o): undefined symbol: malloc_inspect_all

这些符号来自Haskell RTS及补丁版libc,推测GHC生成的库未静态链接依赖项。

疑问与求助

  1. Cabal的foreign-library stanza、GHC的shared/static/-fPIC等标志,以及-optl-Wl,--relocatable链接标志如何适配WASM后端?
  2. wizer是否仅适用于WASM可执行文件?是否需要将cbits/wizerinit.c的逻辑暴露到Rust wrapper crate,待最终生成可执行文件后再执行wizer?
  3. GHC的wasm32-wasi与Rust的wasm32-unknown-unknown能否兼容链接?是否需要浏览器WASI polyfill?
  4. WASM多内存模型的linear_memory导入如何处理,才能避免内存布局冲突?

现询问该方案是否可行,以及是否有GHC+WASM+C-FFI相关的实现资源、示例或文档。

内容的提问来源于stack exchange,提问作者the thinker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:05:57