如何打开大于 4KB 的侧模块?

How to dlopen a side module larger than 4KB?

我正在尝试使用 dlopen() 从主模块动态加载辅助模块。

只要小于 4KB 的侧模块就可以正常加载,但我需要加载大尺寸的侧模块。

这是您可以测试的简单代码:

side.c:

#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 library\n");
        return 0;
    }
    func_t func = (func_t)dlsym(handle, "side");

    if (!func) {
        printf("failed to find the method\n");
        dlclose(handle);
        return 0;
    }
    printf("side module size: %d byte\n", 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 浏览器中得到的结果:

Error in loading dynamic library side.wasm: RangeError: WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.compile, or compile on a worker thread.

有人可以指导我如何动态加载大于 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("before\n");
    doLoadLibrary();
    printf("after\n");
}

int main()
{
}

side.c:

#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

在您的浏览器中,单击“选择文件”和select side/side.wasm 文件,然后单击“加载库”按钮。 您将在控制台中看到以下结果:

before
side module size: 5000
after