2017-07-25 129 views
6

我可以以某種方式創建一個wasm文件,它可以自己工作,如描述in MDN here(通過安裝對象和調用它們的函數)?我可以以某種方式構建webassembly代碼*而不使用emscripten「glue」嗎?

我能找到的所有指南(such as this one on MDN)推薦使用emscripten;但是,它也會包含~70kB的「膠水代碼」(約50kB可選文件系統仿真),它還有其他邏輯(如檢測節點/瀏覽器環境和自動獲取等)以及其他仿真。

如果我不想要那個「膠水代碼」並且想直接創建WASM(可能來自C代碼,但可能是其他的東西),該怎麼辦?現在可能嗎?

+0

與答案可能相關的問題 - https://stackoverflow.com/questions/45146099/how-do-i-compile-ac-file-to -webassembly –

回答

4

您可以使用emscripten生成相當簡單的代碼輸出。

考慮以下瑣碎文件adder.c

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

編譯它像這樣(需要一個相當新的emscripten):

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

要看到它產生的東西,用它拆開來一夥的文本形式binaryen的wasm-dis(您也可以使用來自wabt的wasm2wast):

wasm-dis adder.wasm -o adder.wast 

反彙編源應該是這個樣子:

(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 
) 

然後,您可以在節點(V8.x中或更高版本)運行該是這樣的:

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)) 
}) 

注意,如果你想支持代碼使用堆棧和/或堆內存的事情變得更加複雜。即在調用任何其他導出之前,至少需要設置memoryBase並從主機環境中調用__post_instantiate

如果您想在沒有JavaScript環境的情況下解釋WebAssembly代碼,您可以使用wac/wace(完全公開:我創建此項目)來運行它。請注意,wace假定您定義了「_main」或「main」函數。

+0

wac!我一直試圖用wabt解釋器來構建類似的東西,但是發現它缺乏我的目的。看起來像你救了我一堆工作:) – kazemakase

+0

我接受你的版本,*但*有這個問題,我不喜歡。希望他們能很快解決它! https://github.com/kripken/emscripten/issues/5419 –

2

您可以隨着時間的推移變得更加輕鬆!

如果您想完全避免使用C++,可以創建WebAssembly模塊,例如在spec testsWebKit test suite中所做的那樣。

即使使用C++,也可以不使用Emscripten。 wasm-stat.us是否適用於例如海合會酷刑測試。看看它的構建輸出,或者look at its source

例如,它會做的編譯/鏈接以下/組合:

# 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 

你甚至可以下載所有的瀑布的構建文物,包括完整工具鏈。只需點擊一個綠色框並找到您要找的下載。

如果你感覺大膽你甚至可以write your libc in JavaScript,而不是聯用C寫的

當你說「在自己的」現有的實現,記得比WebAssembly目前沒有鏈接到什麼都做不了其嵌入器(即JavaScript)。模型Emscripten遵循(我希望其他人也這樣做)是JavaScript是微內核並提供系統調用。

+0

感謝您的回答!也很有幫助,雖然我接受了另一個(但至少已投票支持你的) –

2

您可以使用ONLY_MY_CODE標誌,這將只生成沒有glue.js的wasm模塊,例如,

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

從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

謝謝!將嘗試 –

+0

好。這與'-s SIDE_MODULE = 1'不同嗎? – kazemakase

+0

https://github.com/kripken/emscripten/wiki/Linking 據我所知,兩者都消除了用於將模塊鏈接到系統庫文件等的膠水代碼,但'only_my_code = 1'進一步確保只有你的代碼被翻譯成wasm –

相關問題