web-dev-qa-db-fra.com

Puis-je en quelque sorte créer du code d'assemblage Web * sans * la "colle" emscripten?

Puis-je en quelque sorte créer un fichier wasm, qui fonctionnera de lui-même comme décrit dans MDN ici (en instanciant les objets et en appelant des fonctions dessus)?

Tous les guides que je peux trouver ( comme celui-ci sur MDN ) recommandent d'utiliser emscripten; cela comprendra également ~ 70 ko de "code de colle" (avec ~ 50 ko d'émulation de système de fichiers en option), qui a une logique supplémentaire (comme l'environnement de noeud de détection/navigateur et la récupération automatique, etc.), et probablement une autre émulation.

Que se passe-t-il si je ne veux pas ce "code de colle" et que je veux simplement créer WASM directement (probablement à partir du code C, mais peut-être autre chose)? Est-ce possible en ce moment?

21
Karel Bílek

Vous pouvez utiliser emscripten pour générer une sortie de code assez minimale.

Considérez le fichier trivial suivant adder.c:

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

Compilez-le comme ceci (nécessite un emscripten assez récent):

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

Pour voir ce qu'il a généré, démontez-le sous forme textuelle en utilisant wasm-dis De binaryen (vous pouvez également utiliser wasm2wast de wabt):

wasm-dis adder.wasm -o adder.wast

La source démontée devrait ressembler à ceci:

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

Vous pouvez ensuite l'exécuter dans le nœud (v8.X ou version ultérieure) comme ceci:

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

Notez que si vous voulez prendre en charge du code qui utilise la pile et/ou la mémoire de tas, les choses deviennent plus compliquées. C'est à dire. vous devrez au moins définir memoryBase et appeler __post_instantiate à partir de votre environnement hôte avant d'appeler toute autre exportation.

Si vous souhaitez interpréter le code WebAssembly sans environnement JavaScript, vous pouvez l'exécuter en utilisant wac/wace (divulgation complète: j'ai créé ce projet). Notez que wace suppose que vous avez défini une fonction "_main" ou "main".

12
kanaka

Vous pouvez utiliser l'indicateur ONLY_MY_CODE, cela ne générera que le module wasm sans glue.js, par exemple.

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

Depuis Settings.js https://github.com/kripken/emscripten/blob/master/src/settings.js#L58 :

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.
4
Lisa Schuh

Vous pouvez, et cela devient plus facile avec le temps!

Si vous voulez éviter complètement C++, il est possible de créer des modules WebAssembly, par exemple comme cela se fait dans spec tests ou WebKit test suite .

Même avec C++, vous pouvez, sans Emscripten. wasm-stat.us le fait par exemple les tests de torture du CCG. Découvrez sa sortie de build, ou regardez sa source .

Par exemple, il fera ce qui suit pour compiler/lier/assembler:

# 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

Vous pouvez même télécharger tous les artefacts de construction de la cascade, y compris les chaînes d'outils complètes. Cliquez simplement sur une case verte et trouvez le téléchargement que vous recherchez.

Si vous vous sentez audacieux, vous pourriez même écrire votre libc en JavaScript au lieu de lier une implémentation existante écrite en C.

Lorsque vous dites "seul", n'oubliez pas que WebAssembly ne peut actuellement rien faire sans créer de lien vers son embedder (c'est-à-dire JavaScript). Le modèle qu'Emscripten suit (et je m'attends à ce que les autres fassent de même) est que JavaScript est un micro-noyau et fournit des appels système.

4
JF Bastien

LLVM prend désormais en charge la compilation directe de C vers wasm à l'aide de WASI. Emscripten n'est plus nécessaire.

Si aucune libc n'est requise, vous pouvez utiliser LLVM dès la sortie de la boîte. Par exemple, le fichier foo.c peut être compilé avec:

clang --target=wasm32 --no-standard-libraries -Wl,--export-all -Wl,--no-entry -o foo.wasm foo.c

Sinon, le projet WASI-libc a une libc autonome qui peut être utilisée.

Une procédure complète pour compiler C vers WebAssembly avec LLVM et l'exécuter dans un navigateur est disponible dans cet article .

1
Rich Apodaca