删除“-s ONLY_MY_CODE=1”编译参数会导致 WebAssembly 程序中断
removing "-s ONLY_MY_CODE=1" compilation argument causes WebAssembly program to break
我有一个小的 WebAssembly 程序,通过以下 bash 脚本编译时可以正常工作:
source_list="../../src/cpp/main/main.cc"
emcc -std=c++11 $source_list -o out/index.html -O1 -s WASM=1 -s ONLY_MY_CODE=1 -s EXPORTED_FUNCTIONS="['_go']"
cp ../../src/html/index.html out/
当我在浏览器中加载程序时,我看到 hi there
打印到 JS 控制台。
但是,为了准备使用更高级的代码,我通过删除 -s ONLY_MY_CODE=1
条目更改了我的编译脚本。
在不对任何文件做任何进一步更改的情况下,当我随后编译 运行 程序时,我在浏览器中看到以下错误消息:
index.html:1 Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #0 module="env" function="DYNAMICTOP_PTR" error: global import must be a number
at <anonymous>
Promise rejected (async)
(anonymous) @ index.html:35
我该如何解决这个问题?
main.cc
extern "C"
{
extern void print(char *message);
void go()
{
print("hi there");
}
}
index.html
<script>
var webSocket;
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 });
const buffer = new Uint8Array(memory.buffer);
var exports;
function toJsStr(offset){
var s="";
for(;;){
var b = buffer[offset++];
if( b == 0 )
return s;
s += String.fromCharCode(b);
}
}
function print(offset){
console.log(toJsStr(offset));
}
fetch('index.wasm').then(response =>
response.arrayBuffer()
).then(bytes => {
var imports = {};
imports.env = {};
imports.env.memory = memory;
imports.env.memoryBase = 0;
imports.env.table = new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' });
imports.env.tableBase = 0;
imports.env._print = print;
return WebAssembly.instantiate(bytes, imports);
}
).then(module => {
exports = module.instance.exports;
exports._go();
}
);
</script>
Emscripten 在生成的 WASM 代码中包含一个运行时。这个生成的运行时允许它支持广泛的 C/C++ 特性,使得移植复杂代码库变得更加容易。这个运行时也有一个 JavaScript 对应物,所以当你编译 C / C++ 代码库时,你会看到它输出一个 wasm 文件,一个 JavaScript 文件和一个 HTML 文件。 HTML 文件是您的代码的模板化测试工具。
当使用 ONLY_MY_CODE
编译时,您将消除大部分运行时间,因此也不再生成 JavaScript 和 HTML 文件。使用 ONLY_MY_CODE
时,您可以使用的功能确实非常有限,例如,您不能使用字符串,或者 return 除了导出函数中的数字类型之外的任何其他内容。
因此,在您的示例中,当删除 ONLY_MY_CODE
时,您需要通过生成的 JavaScript 文件加载您的 wasm 文件。这将加载 wasm 代码并处理导出/导入/内存,以便 'marry up' 生成的运行时代码。您的错误消息中出现的函数 DYNAMICTOP_PTR
是此运行时的组成部分之一。
我有一个小的 WebAssembly 程序,通过以下 bash 脚本编译时可以正常工作:
source_list="../../src/cpp/main/main.cc"
emcc -std=c++11 $source_list -o out/index.html -O1 -s WASM=1 -s ONLY_MY_CODE=1 -s EXPORTED_FUNCTIONS="['_go']"
cp ../../src/html/index.html out/
当我在浏览器中加载程序时,我看到 hi there
打印到 JS 控制台。
但是,为了准备使用更高级的代码,我通过删除 -s ONLY_MY_CODE=1
条目更改了我的编译脚本。
在不对任何文件做任何进一步更改的情况下,当我随后编译 运行 程序时,我在浏览器中看到以下错误消息:
index.html:1 Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #0 module="env" function="DYNAMICTOP_PTR" error: global import must be a number
at <anonymous>
Promise rejected (async)
(anonymous) @ index.html:35
我该如何解决这个问题?
main.cc
extern "C"
{
extern void print(char *message);
void go()
{
print("hi there");
}
}
index.html
<script>
var webSocket;
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 });
const buffer = new Uint8Array(memory.buffer);
var exports;
function toJsStr(offset){
var s="";
for(;;){
var b = buffer[offset++];
if( b == 0 )
return s;
s += String.fromCharCode(b);
}
}
function print(offset){
console.log(toJsStr(offset));
}
fetch('index.wasm').then(response =>
response.arrayBuffer()
).then(bytes => {
var imports = {};
imports.env = {};
imports.env.memory = memory;
imports.env.memoryBase = 0;
imports.env.table = new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' });
imports.env.tableBase = 0;
imports.env._print = print;
return WebAssembly.instantiate(bytes, imports);
}
).then(module => {
exports = module.instance.exports;
exports._go();
}
);
</script>
Emscripten 在生成的 WASM 代码中包含一个运行时。这个生成的运行时允许它支持广泛的 C/C++ 特性,使得移植复杂代码库变得更加容易。这个运行时也有一个 JavaScript 对应物,所以当你编译 C / C++ 代码库时,你会看到它输出一个 wasm 文件,一个 JavaScript 文件和一个 HTML 文件。 HTML 文件是您的代码的模板化测试工具。
当使用 ONLY_MY_CODE
编译时,您将消除大部分运行时间,因此也不再生成 JavaScript 和 HTML 文件。使用 ONLY_MY_CODE
时,您可以使用的功能确实非常有限,例如,您不能使用字符串,或者 return 除了导出函数中的数字类型之外的任何其他内容。
因此,在您的示例中,当删除 ONLY_MY_CODE
时,您需要通过生成的 JavaScript 文件加载您的 wasm 文件。这将加载 wasm 代码并处理导出/导入/内存,以便 'marry up' 生成的运行时代码。您的错误消息中出现的函数 DYNAMICTOP_PTR
是此运行时的组成部分之一。