Utiliser des fonctions Wasm avec Node.js
Le meilleur moyen d'inclure du code C dans une application JavaScript et rester portable.
Même si WebAssembly a originellement été conçu pour les applications Web, ce n'est pas le domaine où il excelle le plus. L'utilisation trop fréquente de code Wasm sur des sites malicieux à conduit à rendre son utilisation plus stricte dans les pages web, et donc le rendre plus difficile à utiliser. On contraire sur le poste local, il est extrêmement simple à utiliser et ouvre un nouvel horizon et de vastes possibilités aux programmeurs.
Il est aussi plus facile de compiler un fichier source C en Wasm qu'un fichier C++ car le compilateur emcc dérivé de CLang modifie le nom des fonctions C++ dans le code généré ce qu'il ne fait pas avec C, et il est ainsi plus compliqué de les appeler dans le code JavaScript.
On utilisera dans cet exemple une bibliothèque de fonctions similaire à celle que l'on a utilisé dans le chapitre Générer une bibliothèque pour un projet Wasm.
int fnadd(int x, int y) {
return x + y;
}
int fnmul(int x, int y) {
return x * y;
}
int fibonacci(int n) {
int z;
if(n < 2) {
z= n;
}
else {
z= fibonacci(n-1) + fibonacci(n-2);
}
return z;
}
On sauvera ce code dans le fichier demolib.c.
Il est compilé en wasm avec cette commande:
emcc demolib.c -Oz -s WASM=1 -s SIDE_MODULE=1 -o demolib.wasm
Le programme JavaScript charge le code Wasm avec la fonction readFileSync, crée des références utilisables en JavaScript avec la méthode instantiate de WebAssembly.
const fs = require("fs");
async function demo() {
let wasm = fs.readFileSync("demolib.wasm");
let lib = await WebAssembly.instantiate(wasm);
let arith = lib.instance.exports
console.log(arith.fnadd(10,20));
console.log(arith.fnmul(100,9));
let fmax = 20
for(var i=0; i <= fmax; i++) {
console.log("fib(" + i + ")=" + arith.fibonacci(i));
}
};
demo().then();
On sauvera le code dans le fichier demo.js.
On peut alors exécuter le script avec cette commande:
node demo.js
Cela doit afficher 30 puis 900 puis une suite de Fibonacci.
Noter que les fonctions WebAssembly sont normalement appelées avec le format lib.instance.exports.nom_fonction() et pour simplifier les appels on a assigné lib.instance.exports à la variable arith.
Ce programme est particulièrement simple parce que la bibliothèque Wasm n'utilise pas la librairie standard C. Si c'était le cas il faudrait déclarer la liste des fonctions de la libraire que l'on utilise, dans la déclaration d'instantiation wasm.
La bibliothèque n'utilise pas non plus le système de fichiers, ce qui compliquerait encore le code. Ce n'est pas absolument nécessaire en fait, car les accès aux fichiers ne sont jamais des opérations rapides, on peut les réaliser dans le code JavaScript et éventuellement passer les données comme arguments aux fonctions wasm.