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

使用Wasmex在Elixir中调用Go库Pdfcpu时遇导出函数未找到问题

问题描述

我在Elixir模块中尝试调用由Go编写的Pdfcpu库来修改现有PDF,该库提供CLI和API,我使用的是API。借助Wasmex运行WASM代码以实现与Elixir的交互。

编写的Go模块如下:

package main

import (
    "log"

    "github.com/pdfcpu/pdfcpu/pkg/api"
)

func main() {
}

func RotateFile(inFile, outFile string, rotation int, selectedPages []string) {
    if err := api.RotateFile(inFile, outFile, rotation, []string{"1"}, nil); err != nil {
        log.Fatal(err)
    }
}

执行编译命令:

go mod init proj/pdfcpu
go get github.com/pdfcpu/pdfcpu@latest
go mod tidy
GOOS=wasip1 GOARCH=wasm go build -o main.go

测试用的Elixir脚本:

api_binary = File.read!("main.wasm")
{:ok, api_pid} = Wasmex.start_link(%{bytes: api_binary, wasi: true})

Wasmex.call_function(api_pid, "RotateFile", ["input.pdf", "output.pdf", 180, [], nil])

运行后收到错误:{:error, "exported function RotateFile not found"},尝试调用api.RotateFile也无效。

错误原因与修正方案

1. Go函数未导出为WASM可调用接口

Go编译为WASM时,普通函数不会自动被导出到WASM的外部函数表中,必须通过特殊注释标记导出,同时要适配WASM的类型限制(仅支持基础数值类型,字符串、切片等复杂类型需通过syscall/js包处理)。

修正后的Go代码:

package main

import (
    "log"
    "syscall/js"

    "github.com/pdfcpu/pdfcpu/pkg/api"
)

func main() {
    // 阻塞主线程,防止WASM实例启动后立即退出
    <-make(chan bool)
}

//go:wasm-module pdfcpu
//export RotateFile
func RotateFile(this js.Value, args []js.Value) interface{} {
    // 参数校验
    if len(args) < 4 {
        return "参数数量不足"
    }
    
    // 从JS参数中提取值
    inFile := args[0].String()
    outFile := args[1].String()
    rotation := args[2].Int()
    
    // 转换页面列表参数
    selectedPages := make([]string, args[3].Length())
    for i := 0; i < args[3].Length(); i++ {
        selectedPages[i] = args[3].Index(i).String()
    }

    // 调用pdfcpu API
    if err := api.RotateFile(inFile, outFile, rotation, selectedPages, nil); err != nil {
        log.Println(err)
        return err.Error()
    }
    return nil
}

2. 编译命令输出文件错误

原编译命令中-o main.go会覆盖Go源码文件,正确应该输出为.wasm格式文件:

GOOS=wasip1 GOARCH=wasm go build -o main.wasm

3. Elixir调用参数不符合绑定要求

Wasmex调用Go导出的WASM函数时,不能直接传递Elixir原生列表和nil,需要将复杂类型转换为WASM内存中的数组。修正后的Elixir脚本:

api_binary = File.read!("main.wasm")
{:ok, api_pid} = Wasmex.start_link(%{bytes: api_binary, wasi: true})

# 将页面列表转换为WASM可识别的数组
selected_pages = Wasmex.Memory.create_array(api_pid, ["1"])
result = Wasmex.call_function(api_pid, "RotateFile", ["input.pdf", "output.pdf", 180, selected_pages])

IO.inspect(result)

内容的提问来源于stack exchange,提问作者Paul B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 23:34:51