WebAssembly报错:Import对象字段'add'不是函数 求助排查
WebAssembly调用JS函数报错:导入对象字段 'add' 不是函数
问题场景
首次尝试WebAssembly,编写了调用C语言subtract函数的程序,该C函数会调用JavaScript中的add函数,但运行时出现以下错误:
Uncaught (in promise) LinkError: 导入对象字段 'add' 不是函数
相关代码如下:
Index.js
const add = (one, two) => { return one + two; }; const importObject = { imports: { add, }, env: { abort(msg, file, line, column) { console.error(`${msg} in ${file} at ${line}:${column}`); } } }; const loadWASM = fileName => { return fetch(fileName) .then(res => res.arrayBuffer()) .then(buffer => new WebAssembly.Module(buffer)) .then(module => { return new WebAssembly.Instance(module, importObject); }); }; loadWASM("./math.wasm").then(module => { console.log(module.exports.square(5)); console.log(module.exports.subtract(7, 5)); });
math.c
int square(int num) { return num * num; } int subtract(int one, int two) { return add(one, -two); }
问题原因
WebAssembly导入函数的命名空间必须与编译C代码时指定的一致。默认情况下,用clang编译C到WASM时,会将外部依赖的函数(比如这里的add)归到env命名空间下,但你的代码里把add放在了自定义的imports命名空间中,导致WASM实例无法找到对应的函数,触发LinkError。
解决方法
方法1:调整导入对象结构(推荐,无需修改编译命令)
将add函数移到env命名空间下,与默认编译规则匹配:
const importObject = { env: { add, // 移到env命名空间下 abort(msg, file, line, column) { console.error(`${msg} in ${file} at ${line}:${column}`); } } };
方法2:自定义命名空间(需修改编译命令)
如果想保留imports命名空间,编译C代码时需要通过参数指定导入模块名:
clang --target=wasm32 -nostdlib -Wl,--export-all -Wl,--no-entry -Wl,--import-module=imports -o math.wasm math.c
此命令会告诉编译器,将外部依赖的add函数标记为从imports模块导入,此时你的原importObject结构可以正常使用。
验证结果
修改后运行代码,module.exports.square(5)会输出25,module.exports.subtract(7,5)会调用JS的add(7,-5),输出2,程序正常执行。
内容的提问来源于stack exchange,提问作者CrossScar
相关产品推荐
相关产品推荐

