如何使用库导入将 C 文件编译为 webassembly 文件 (Emscripten)
How to compile C file with Library imports to webassembly file (Emscripten)
我有一个简单的 C 程序需要解析 Json 数据。为此,我导入了 JSON-C 库。我的 C 代码是 -
#include"json.h"
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int addnumbers(int a, int b) {
FILE *fp;
char buffer[1024];
struct json_object *parsed_json;
struct json_object *name;
struct json_object *age;
struct json_object *friends;
struct json_object *friend;
size_t n_friends;
size_t i;
fp = fopen("test.json","r");
fread(buffer, 1024, 1, fp);
fclose(fp);
parsed_json = json_tokener_parse(buffer);
json_object_object_get_ex(parsed_json, "name", &name);
json_object_object_get_ex(parsed_json, "age", &age);
json_object_object_get_ex(parsed_json, "friends", &friends);
printf("Name: %s\n", json_object_get_string(name));
printf("Age: %d\n", json_object_get_int(age));
n_friends = json_object_array_length(friends);
for(i=0;i<n_friends;i++) {
friend = json_object_array_get_idx(friends, i);
// printf("%lu. %s\n",i+1,json_object_get_string(friend));
}
return n_friends;
}
我遵循的过程:-
使用命令-
将库(特别是 json.h 文件)编译成位代码
emcc json.h -o json.bc
然后使用 -
编译我的 C 程序
emcc json.c -o j_plumbing.bc -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
然后我用这个命令编译了这两个文件以获取 wasm 文件:-
emcc json.bc j_plumbing.bc -o js_plumbing.js -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -g4 -s LINKABLE=1 -s EXPORT_ALL=1 -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
这就是我从 Vue 文件中调用它的方式
public draw_outline() {
Module().then(myModule => {
console.log(myModule)
const result = myModule.ccall('addnumbers',
'number',
['number', 'number'],
[4, 6]);
console.log("Value from wasm file", result);
});
}
but this is the error I'm getting-
002210ee:1 Uncaught (in promise) RuntimeError: function signature mismatch
at fclose (wasm-function[524]:0x1a777)
at addnumbers (wasm-function[148]:0x6a45)
at Module._addnumbers (webpack-internal:///./src/components/js_plumbing.js:1098:4989)
at Object.ccall (webpack-internal:///./src/components/js_plumbing.js:199:628)
at eval (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Extraction.vue?vue&type=script&lang=ts&:128:31)
at Object.Module.onRuntimeInitialized (webpack-internal:///./src/components/js_plumbing.js:1109:95)
at doRun (webpack-internal:///./src/components/js_plumbing.js:1117:140)
at run (webpack-internal:///./src/components/js_plumbing.js:1117:436)
at runCaller (webpack-internal:///./src/components/js_plumbing.js:1113:15)
at removeRunDependency (webpack-internal:///./src/components/js_plumbing.js:373:843)
谁能指出我这里做错了什么?感谢任何帮助
说明
如果仔细阅读错误和调用堆栈,您会注意到问题出在 fclose()
函数中。 A WebAssembly module generated using emscripten has its virtual file system 不理解您机器上的本地文件系统。因此,对本地文件的任何访问都将失败,就像 fp = fopen("test.json","r");
和它 returns NULL
一样。 NULL
-fp
指针的值是 fclose(fp)
.
错误的原因
由于我无法使用您的代码(抱歉),我已经在稍微不同的设置中复制了错误,但是在快速解决之后!
快速解决
映射WebAssembly的虚拟文件系统/emscripten to local file system using e.g. NODEFS. You can find more information about this solution in my other answer .
#include <stdio.h>
#include <emscripten.h>
#include <emscripten/bind.h>
void test_fun()
{
FILE *fp;
EM_ASM(
FS.mkdir('/temp');
FS.mount(NODEFS, {root : '.'}, '/temp'););
fp = fopen("temp/test.json", "r");
fclose(fp);
}
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("test_fun", &test_fun);
}
最简单的错误复制
此示例代码尝试关闭指针值为 NULL
的文件。
#include <stdio.h>
#include <emscripten.h>
#include <emscripten/bind.h>
void test_fun()
{
fclose(NULL);
}
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("test_fun", &test_fun);
}
如果你用额外的调试信息编译这个例子-g
:
emcc example.cpp -o example.js --bind -s WASM_ASYNC_COMPILATION=0 -g
然后尝试执行一个测试脚本node test.js
,其中test.js
如下:
var Module = require('./example.js');
Module.test_fun();
然后,你得到的是同样的错误:
RuntimeError: function signature mismatch
at fclose (wasm-function[32]:127)
at test_fun() (wasm-function[17]:9)
...
我有一个简单的 C 程序需要解析 Json 数据。为此,我导入了 JSON-C 库。我的 C 代码是 -
#include"json.h"
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int addnumbers(int a, int b) {
FILE *fp;
char buffer[1024];
struct json_object *parsed_json;
struct json_object *name;
struct json_object *age;
struct json_object *friends;
struct json_object *friend;
size_t n_friends;
size_t i;
fp = fopen("test.json","r");
fread(buffer, 1024, 1, fp);
fclose(fp);
parsed_json = json_tokener_parse(buffer);
json_object_object_get_ex(parsed_json, "name", &name);
json_object_object_get_ex(parsed_json, "age", &age);
json_object_object_get_ex(parsed_json, "friends", &friends);
printf("Name: %s\n", json_object_get_string(name));
printf("Age: %d\n", json_object_get_int(age));
n_friends = json_object_array_length(friends);
for(i=0;i<n_friends;i++) {
friend = json_object_array_get_idx(friends, i);
// printf("%lu. %s\n",i+1,json_object_get_string(friend));
}
return n_friends;
}
我遵循的过程:- 使用命令-
将库(特别是 json.h 文件)编译成位代码emcc json.h -o json.bc
然后使用 -
编译我的 C 程序emcc json.c -o j_plumbing.bc -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
然后我用这个命令编译了这两个文件以获取 wasm 文件:-
emcc json.bc j_plumbing.bc -o js_plumbing.js -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -g4 -s LINKABLE=1 -s EXPORT_ALL=1 -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
这就是我从 Vue 文件中调用它的方式
public draw_outline() {
Module().then(myModule => {
console.log(myModule)
const result = myModule.ccall('addnumbers',
'number',
['number', 'number'],
[4, 6]);
console.log("Value from wasm file", result);
});
}
but this is the error I'm getting-
002210ee:1 Uncaught (in promise) RuntimeError: function signature mismatch
at fclose (wasm-function[524]:0x1a777)
at addnumbers (wasm-function[148]:0x6a45)
at Module._addnumbers (webpack-internal:///./src/components/js_plumbing.js:1098:4989)
at Object.ccall (webpack-internal:///./src/components/js_plumbing.js:199:628)
at eval (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/Extraction.vue?vue&type=script&lang=ts&:128:31)
at Object.Module.onRuntimeInitialized (webpack-internal:///./src/components/js_plumbing.js:1109:95)
at doRun (webpack-internal:///./src/components/js_plumbing.js:1117:140)
at run (webpack-internal:///./src/components/js_plumbing.js:1117:436)
at runCaller (webpack-internal:///./src/components/js_plumbing.js:1113:15)
at removeRunDependency (webpack-internal:///./src/components/js_plumbing.js:373:843)
谁能指出我这里做错了什么?感谢任何帮助
说明
如果仔细阅读错误和调用堆栈,您会注意到问题出在 fclose()
函数中。 A WebAssembly module generated using emscripten has its virtual file system 不理解您机器上的本地文件系统。因此,对本地文件的任何访问都将失败,就像 fp = fopen("test.json","r");
和它 returns NULL
一样。 NULL
-fp
指针的值是 fclose(fp)
.
由于我无法使用您的代码(抱歉),我已经在稍微不同的设置中复制了错误,但是在快速解决之后!
快速解决
映射WebAssembly的虚拟文件系统/emscripten to local file system using e.g. NODEFS. You can find more information about this solution in my other answer .
#include <stdio.h>
#include <emscripten.h>
#include <emscripten/bind.h>
void test_fun()
{
FILE *fp;
EM_ASM(
FS.mkdir('/temp');
FS.mount(NODEFS, {root : '.'}, '/temp'););
fp = fopen("temp/test.json", "r");
fclose(fp);
}
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("test_fun", &test_fun);
}
最简单的错误复制
此示例代码尝试关闭指针值为 NULL
的文件。
#include <stdio.h>
#include <emscripten.h>
#include <emscripten/bind.h>
void test_fun()
{
fclose(NULL);
}
EMSCRIPTEN_BINDINGS(Module)
{
emscripten::function("test_fun", &test_fun);
}
如果你用额外的调试信息编译这个例子-g
:
emcc example.cpp -o example.js --bind -s WASM_ASYNC_COMPILATION=0 -g
然后尝试执行一个测试脚本node test.js
,其中test.js
如下:
var Module = require('./example.js');
Module.test_fun();
然后,你得到的是同样的错误:
RuntimeError: function signature mismatch
at fclose (wasm-function[32]:127)
at test_fun() (wasm-function[17]:9)
...