Как скомпилировать файл C с помощью импорта библиотеки в файл веб-сборки (Emscripten) - PullRequest
1 голос
/ 25 февраля 2020

У меня есть простая 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)

Кто-нибудь может указать, что я здесь не так делаю? Любая помощь приветствуется

1 Ответ

1 голос
/ 05 марта 2020

Объяснение

Если внимательно прочитать ошибку и стек вызовов, вы можете заметить, что проблема возникла в функции fclose(). Модуль WebAssembly , созданный с использованием emscripten , имеет виртуальную файловую систему , которая не понимает локальную файловую систему на вашем компьютере. Следовательно, любой доступ к локальным файлам завершится неудачно, как и fp = fopen("test.json","r");, и он возвращает NULL. Указатель NULL -значения fp является причиной ошибки fclose(fp).

Из-за невозможности работы с вашим кодом (извините) я повторил ошибку в несколько ином параметре , но после быстрого решения!

Быстрое решение

Сопоставьте виртуальную файловую систему WebAssembly / emscripten с локальной файловой системой, используя, например, NODEFS . Вы можете найти больше информации об этом решении в моем другом ответе { ссылка }.

#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)
    ...
...