2017-07-25 7 views
6

Czy mogę w jakiś sposób utworzyć plik wasm, który będzie działał sam zgodnie z opisem in MDN here (przez instatiację obiektów i wywoływanie na nich funkcji)?Czy mogę w jakiś sposób zbudować kod zespołu do budowy * bez * emscripten "kleju"?

Wszystkie przewodniki, które mogę znaleźć (such as this one on MDN) zaleca się używać emscripten; będzie to jednak również ~ 70kB "kod kleju" (z opcjonalną emulacją systemu plików ~ 50 kB), który ma dodatkową logikę (jak węzeł detekcji/środowisko przeglądarki i automatyczne pobieranie itp.) i prawdopodobnie inne emulacje.

Co zrobić, jeśli nie chcę tego "kodu kleju" i chcę po prostu bezpośrednio utworzyć WASM (prawdopodobnie z kodu C, ale może z czegoś innego)? Czy to możliwe w tej chwili?

+0

prawdopodobnie związane pytanie z odpowiedzią - https://stackoverflow.com/questions/45146099/how-do-i-compile-ac-file-to -webassembly –

Odpowiedz

4

Możesz użyć emscripten do wygenerowania dość minimalnego wyniku kodu.

Rozważmy następujący Trivial File adder.c:

int adder (int a, int b) { 
    return a + b; 
} 

skompilować tak (wymaga dość niedawno emscripten):

emcc -O2 -s WASM=1 -s SIDE_MODULE=1 -o adder.wasm 

aby zobaczyć co to generowany, rozbierać go do postaci tekstowej wast korzystania binaryen's wasm-dis (możesz również użyć wasm2wast od wabt):

wasm-dis adder.wasm -o adder.wast 

zdemontowanego źródłowy powinien wyglądać mniej więcej tak:

(module 
(type $0 (func (param i32 i32) (result i32))) 
(type $1 (func)) 
(import "env" "memoryBase" (global $import$0 i32)) 
(import "env" "memory" (memory $0 256)) 
(import "env" "table" (table 0 anyfunc)) 
(import "env" "tableBase" (global $import$3 i32)) 
(global $global$0 (mut i32) (i32.const 0)) 
(global $global$1 (mut i32) (i32.const 0)) 
(export "__post_instantiate" (func $2)) 
(export "runPostSets" (func $1)) 
(export "_adder" (func $0)) 
(func $0 (type $0) (param $var$0 i32) (param $var$1 i32) (result i32) 
    (i32.add 
    (get_local $var$1) 
    (get_local $var$0) 
) 
) 
(func $1 (type $1) 
    (nop) 
) 
(func $2 (type $1) 
    (block $label$0 
    (set_global $global$0 
    (get_global $import$0) 
    ) 
    (set_global $global$1 
    (i32.add 
    (get_global $global$0) 
    (i32.const 5242880) 
    ) 
    ) 
    (call $1) 
) 
) 
;; custom section "dylink", size 5 
) 

Następnie można uruchomić w tym węźle (lub nowszym) v8.X takiego:

const WA = WebAssembly, 
     env = {memoryBase: 0, 
      tableBase: 0, 
      memory: new WA.Memory({initial: 256}), 
      table: new WA.Table({initial: 0, element: 'anyfunc'})}, 
     code = new Uint8Array(require('fs').readFileSync('adder.wasm')) 
WA.compile(code).then(m => { 
    return new WA.Instance(m, {env: env}) 
}).then(i => { 
    console.log(i.exports._adder(7, 8)) 
}) 

pamiętać, że jeśli chcą wspierać kod który używa stosu i/lub pamięci sterty rzeczy stają się bardziej skomplikowane. To znaczy.musisz przynajmniej ustawić bazę pamięci i zadzwonić pod numer __post_instantiate ze swojego środowiska hosta, zanim zadzwonisz do dowolnego innego eksportu.

Jeśli chcesz zinterpretować kod WebAssembly bez środowiska JavaScript, możesz uruchomić go używając wac/wace (pełne ujawnienie: Stworzyłem ten projekt). Zauważ, że wace zakłada, że ​​masz zdefiniowaną "_ główną" lub "główną" funkcję.

+0

+1 dla wac! Próbowałem zbudować coś podobnego za pomocą interpretera wabt, ale okazało się, że brakuje tego dla mojego celu. Wygląda na to, że uratowałeś mi sporo pracy :) – kazemakase

+0

Akceptuję twoją wersję, * ale * jest ten problem, którego nie lubię. Mam nadzieję, że wkrótce to naprawią! https://github.com/kripken/emscripten/issues/5419 –

2

Możesz, i staje się to łatwiejsze z biegiem czasu!

Jeśli chcesz całkowicie uniknąć C++, możesz utworzyć moduły WebAssembly, na przykład tak jak w przypadku spec tests lub WebKit test suite.

Nawet z C++ możesz, bez Emscriptena. wasm-stat.us robi to dla np. testy tortur GCC. Sprawdź jego wynik kompilacji lub look at its source.

Na przykład, będzie to wykonać następujące czynności dla kompilacji/link/montaż:

# Get a .o file: 
src/work/wasm-install/bin/clang src/work/gcc/gcc/testsuite/gcc.c-torture/execute/20020227-1.c -o src/work/torture-o/20020227-1.c.o --std=gnu89 -DSTACK_SIZE=1044480 -w -Wno-implicit-function-declaration --target=wasm32-unknown-unknown-wasm -c -O2 --sysroot=src/work/wasm-install/sysroot 
# Link with libc: 
src/work/wasm-install/bin/lld -flavor wasm -entry=main --allow-undefined-file=src/work/wasm-install/sysroot/lib/wasm.syms -o src/work/torture-lld-musl/20020510-1.c.o.wasm src/work/torture-o/20020510-1.c.o src/work/wasm-install/sysroot/lib/libc.a 
# Or without a libc (you need to provide one somehow): 
src/work/wasm-install/bin/lld -flavor wasm -entry=main --allow-undefined-file=src/work/wasm-install/sysroot/lib/wasm.syms -o src/work/torture-lld/20020510-1.c.o.wasm src/work/torture-o/20020510-1.c.o 

# Or, if you want an assembly file instead: 
src/work/wasm-install/bin/clang src/work/gcc/gcc/testsuite/gcc.c-torture/execute/20020227-1.c -o src/work/torture-s/20020227-1.c.s --std=gnu89 -DSTACK_SIZE=1044480 -w -Wno-implicit-function-declaration --target=wasm32-unknown-unknown -S -O2 --sysroot=src/work/wasm-install/sysroot 
# And get the binary file: 
src/work/wasm-install/bin/wast2wasm src/work/torture-s2wasm/loop-6.c.s.wast -o src/work/torture-wast2wasm/loop-6.c.s.wast.wasm 

Można nawet pobrać wszystkie produkcji artefaktów wodospadu, w tym pełnych toolchains. Wystarczy kliknąć zielone pole i znaleźć pobrany plik.

Jeśli czujesz się śmiały można nawet write your libc in JavaScript zamiast łączyć istniejący realizacji napisany w C.

Kiedy mówisz „na własną rękę”, pamiętaj niż WebAssembly obecnie nie może zrobić nic bez linkami do jego embedder (np. JavaScript). Model Emscripten śledzi (i spodziewam się, że inni robią to samo), że JavaScript jest mikrojądrem i zapewnia syscalls.

+0

Dzięki za odpowiedź! Również pomocna, chociaż zaakceptowałem drugą (ale przynajmniej przegłosowałem twoją) –

2

Możesz użyć flagi ONLY_MY_CODE, spowoduje to wygenerowanie tylko modułu wasm bez glue.js np.

emcc -O1 ./src/foo.cpp -o release/foo.wasm -s WASM=1 -s ONLY_MY_CODE=1 

Od Settings.js https://github.com/kripken/emscripten/blob/master/src/settings.js#L583:

var ONLY_MY_CODE = 0; // This disables linking and other causes of adding extra code 
         // automatically, and as a result, your output compiled code 
         // (in the .asm.js file, if you emit with --separate-asm) will 
         // contain only the functions you provide. 
+0

Dzięki! Spróbuję, że –

+0

Nice. Czy to różni się od '-s SIDE_MODULE = 1'? – kazemakase

+0

https://github.com/kripken/emscripten/wiki/Linking O ile rozumiem, zarówno wyeliminować kod kleju używany do łączenia modułu z systemowymi bibliotekami itp., Ale 'only_my_code = 1' idzie o krok dalej zapewniając, że tylko Twój kod zostanie przetłumaczony na wasm –

Powiązane problemy