我正在尝试使用dlopen()
从主模块动态加载一个侧模块。
只要尺寸小于4KB,侧面模块就可以加载,但我需要加载大尺寸的侧面模块。
下面是一个可以测试的简单代码:
侧:
#define SIZE 4000
char dummy[SIZE] = {};
int side(int a)
{
return SIZE;
}
main.c:
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void *handle;
typedef int (*func_t)(int);
handle = dlopen("side.wasm", RTLD_NOW);
if (!handle) {
printf("failed to open the libraryn");
return 0;
}
func_t func = (func_t)dlsym(handle, "side");
if (!func) {
printf("failed to find the methodn");
dlclose(handle);
return 0;
}
printf("side module size: %d byten", func(1));
}
index.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script async src="main.js"></script>
</body>
</html>
命令:
emcc side.c -s SIDE_MODULE=1 -o side.wasm
emcc main.c -s MAIN_MODULE=1 -o main.html --preload-file side.wasm
python3 -m http.server 8080
这是我在Chrome浏览器中得到的结果:
加载动态库时出错。asm:RangeError:WebAssembly。如果缓冲区大小大于4KB,则不允许在主线程上进行编译。使用WebAssembly.compile,或在工作线程上进行编译。
有人能指导我如何动态加载大于4KB的侧模块吗?
我找到了一个替代解决方案,它使用loadDynamicLibrary()
和Asyncify
而不是dlopen()
。
以下是完整的工作示例代码:
main.c:
#include <stdio.h>
#include <emscripten.h>
EM_JS(void, doLoadLibrary, (), {
Asyncify.handleAsync(async() => {
try {
await loadDynamicLibrary('side.wasm', { loadAsync: true, global: true, nodelete: true, fs: FS });
console.log('side module size: ' + Module['_side']());
}
catch (error) {
console.log(error);
}
});
});
EMSCRIPTEN_KEEPALIVE
void loadLibrary() {
printf("beforen");
doLoadLibrary();
printf("aftern");
}
int main()
{
}
侧:
#define SIZE 5000
char dummy[SIZE] = {};
int side(void)
{
return SIZE;
}
index.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input id="uploadLibrary" type="file" />
<button id="loadLibrary">loadLibrary</button>
<script>
function uploadLibrary() {
var files = this.files;
if (files.length === 0) {
console.log("No file is selected");
return;
}
var file = files[0];
var reader = new FileReader();
reader.onload = function () {
var data = new Uint8Array(reader.result);
Module["FS_createDataFile"]("/", file.name, data, true, true, true);
};
reader.readAsArrayBuffer(file);
}
function loadLibrary() {
Module._loadLibrary();
}
document.getElementById("uploadLibrary").addEventListener("change", uploadLibrary, false);
document.getElementById("loadLibrary").addEventListener("click", loadLibrary, false);
</script>
<script async src="main.js"></script>
</body>
</html>
生成文件:
all: clean
mkdir -p side
emcc side.c -s SIDE_MODULE=1 -o side/side.wasm
emcc main.c -s MAIN_MODULE=1 -s ASYNCIFY -s "ASYNCIFY_IMPORTS=['doLoadLibrary']" -s FORCE_FILESYSTEM=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['FS']" -o main.html
python3 -m http.server 8080
clean:
rm -rf side main.html main.js main.wasm main.data
在浏览器中,单击";选择"文件";并选择side/side.wasm
文件;loadLibrary";按钮您将在控制台中看到以下结果:
before
side module size: 5000
after