使用Emscripten编译代码库时JavaScript调用出现未知函数错误求助
这个错误我碰到过好几次,本质上都是Emscripten的死代码消除(DCE)把你要调用的InitHOG给当成无用代码删掉了,或者函数没有正确暴露给JavaScript环境。下面是几个一步步排查解决的方向:
第一步:给函数加上EMSCRIPTEN_KEEPALIVE标记
首先要在C/C++代码里明确告诉Emscripten:这个函数不能被优化掉。用EMSCRIPTEN_KEEPALIVE宏标记函数的声明和定义,记得要先包含emscripten的头文件:#include <emscripten.h> // 如果是C++代码,一定要用extern "C"避免名字混淆 extern "C" { EMSCRIPTEN_KEEPALIVE void InitHOG() { // 你的函数逻辑 } }要是
InitHOG是在guihtml库里面,要确保这个库编译时已经正确加上了这个宏,并且头文件里的声明也带了标记。第二步:链接时显式导出函数
有时候光加宏还不够,链接阶段的优化可能还是会"误删"函数,这时候直接在emcc命令里用-s EXPORTED_FUNCTIONS参数指定要导出的函数:emcc -o ../your_output.js guihtml.a your_other_libraries.a -s EXPORTED_FUNCTIONS='["_InitHOG"]'注意这里函数名前面要加下划线
_——这是C语言编译后的默认名字修饰;如果是C++代码,extern "C"会让函数名保持原样,不会被mangle,所以用_InitHOG就对了。第三步:检查优化级别和DCE设置
如果你用了-O3这类高级优化,DCE会更激进,可能把一些它认为"没被使用"的函数删掉。可以先暂时换成-O1或者-O0测试,如果问题消失了,说明是优化导致的,这时候结合前两步的导出设置,就能让优化器保留这个函数了。
另外也可以临时用-s NO_DCE=1禁用死代码消除,不过这个选项会让生成的文件变大,只适合用来排查问题,别长期用。第四步:确认链接顺序是否正确
Emscripten的链接器和GCC一样,依赖顺序很关键:要把调用InitHOG的库(也就是guihtml库)放在定义这个函数的库前面。比如如果InitHOG是在libhog.a里,链接命令应该写成:emcc -o ../output.js guihtml.a libhog.a ...这样链接器在处理guihtml库的调用时,后面的libhog.a里能找到函数定义,不会把它当成未使用代码删掉。
第五步:验证导出是否成功
可以用--print-generated-functions参数查看最终导出的函数列表,确认_InitHOG在里面:emcc -o ../output.js ... --print-generated-functions或者生成文件后,在浏览器控制台里输入
Module._InitHOG,如果能看到函数对象,说明导出成功了;要是显示undefined,就回到前面几步检查。
内容的提问来源于stack exchange,提问作者Nathan S.

