Cette traduction est incomplète. Aidez à traduire cet article depuis l'anglais.
Quand vous avez écrit un module de code dans un langage comme le C/C++, vous pouvez ensuite le compiler en WebAssembly en utilisant un outil comme Emscripten. Regardons comment cela fonctionne.
Mise en place de l'environnement Emscripten
D'abord, mettons en place l'environnement requis pour le developpement.
Prérequis
Il y a des prérequis qui ont besoin d'être installé sur votre ordinateur. Soyez sûr que les suivants soient présent:
- Git — Sur Linux and OS X, il est en principe déjà présent. Sur Windows chargez l'installeur de Git pour Windows.
- CMake — Sur Linux et OS X, l'installer en utilisant un gestionnaire de package comme apt-get ou brew pour être sûr que les dependances et les paths soient correct. Sur Windows, utliser l'installeur CMake.
- Un compilateur du systeme hôte — Sur Linux, installee GCC. Sur OS X, installez Xcode. On Windows, installez Visual Studio Community 2015 avec l'update 3 ou plus recent. A noter que les releases récentes VS 2017 ne fonctionneront pas — Elles ne sont pas encore supportées par Emscripten.
- Python 2.7.x — Sur Linux et OS X, il est le plus souvent fournit par défaut. Regarder ce guide pour débutants pour les instructions. Sur Windows, récuperer un installer de la Python homepage.
Note: Sur Windows vous pourriez avoir besoin de pywin32. Pour réduire les erreurs quand vous installez pywin32, s'il vous plait lancer l'installeur d'une CMD en tant qu'administrateur.
Compiler Emscripten
Ensuite, vous avez besoin de compiler Emscripten à partir des sources. Exécuter les commandes suivantes (dans le répertoire parent ou vous voulez sauver Emscripten) pour l'automatiser en utilisant l'Emscripten SDK:
git clone https://github.com/juj/emsdk.git cd emsdk # sur Linux ou Mac OS X ./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit ./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit # sur Windows emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
Cette étape d'installation peut prendre du temps, c'est pourquoi maintenant est le bon moment pour aller se prendre une tasse de thé. Cette étape d'installation mets aussi en place toutes les variables d'environnement nécessaires au bon fonctionnement d'Emscripten.
Note: Le flag --global
permet de definir globalement les PATH
variables, ainsi toutes les futures fenêtres d'invite de terminal/commandes seront aussi impactées. Si vous voulez juste activé Emscripten pour la fenetre courante omettez ce flag.
Note: C'est une bonne idée de puller la derniere version de Emscripten pour être sûr d'avoir les dernieres fonctionnalités. Pour cela, executer git pull
dans le répertoire emsdk
et ensuite réexécutez les commandes install
et activate
visibles chaque fois que vous souhaitez utiliser Emscripten.
Maintenant, à partir du répertoire emsdk
, entrez la commande suivante pour initialiser l'environnement du compilateur Emscripten à partir duquel vous pourrez compiler les exemples C en asm.js/wasm:
# sur Linux ou Mac OS X source ./emsdk_env.sh # sur Windows emsdk_env.bat
Compiler un exemple
Avec l'environnement mis en place, regardons comme l'utiliser pour compiler un exemple en C via Emscripten. Il existe un certains nombres d'options disponibles quand on compile avec Emscripten, mais nous allons couvrir seulement les deux principaux scénarios:
- Compiler vers du wasm et créer du HTML pour exécuter notre code plus toute la "glue" Javascript nécessaire à l'exécution du wasm dans l'environnement Web.
- Compiler vers du wasm et juste créer le Javascript.
Nous verrons les deux par la suite.
Créer le document HTML et la "glue" JavaScript
C'est le cas le plus simple que nous allons voir, pour lequel vous utiliserez Emscripten pour générer tout ce dont vous avez besoin pour exécuter votre code en WebAssembly dans le navigateur.
- D'abord nous avons besoin d'un exemple à compiler. Prenez une copie du simple programme C suivant et sauvez le dans un fichier nommé
hello.c
dans un nouveau répertoire de votre disque dur:#include <stdio.h> int main(int argc, char ** argv) { printf("Hello World\n"); }
- Maintenant, en utilisant la fênetre terminal qui vous a servi pour entrer dans l'environnement du compilateur Emscripten, naviguez jusqu'au répertoire dans lequel se trouve votre fichier
hello.c
et exécutez la commande suivante:emcc hello.c -s WASM=1 -o hello.html
Les options passées avec la commande sont les suivantes:
-s WASM=1
— Spécifie que nous voulons du wasm en sortie. Si nous ne spécifions pas cela, Emscripten générera juste en sortie du asm.js comme il fait le par défaut.-o hello.html
— Spécifie que nous voulons qu'Emscripten génère une page HTML (dont le nom de fichier est spécifié), le module wasm et le code "glue" en JavaScript pour une execution dans un contexte web.
À ce stade votre dossier source devrait contenir :
- Un fichier de code binaire wasm (
hello.wasm
) - Un fichier JavaScript contenant du code "glue" à traduire entre les fonctions natives C, et Java/wasm (
hello.js
) - Un fichier HTML pour charger, compiler et instancier votre code wasm, et l'afficher dans votre navigateur (
hello.html
)
Exécuter votre exemple
Now all that remains is for you to load the resulting hello.html
in a browser that supports WebAssembly. It is enabled by default in Firefox 52+ and Chrome 57+/latest Opera (you can also run wasm code in Firefox 47+ by enabling the javascript.options.wasm
flag in about:config, or Chrome (51+) and Opera (38+) by going to chrome://flags and enabling the Experimental WebAssembly flag.)
If everything has worked as planned, you should see "Hello world" output in the Emscripten console appearing on the web page, and your browser’s JavaScript console. Congratulations, you’ve just compiled C to WebAssembly and run it in your browser!
Utiliser un template HTML personnalisé
Vous souhaiterez parfois utiliser un template HTML personnalisé. Voyons comment faire :
-
Tout d'abord, sauvegarder le code C suivant dans un fichier nommé
hello2.c
, au sein d'un nouveau dossier (vide) :#include <stdio.h> int main(int argc, char ** argv) { printf("Hello World\n"); }
-
Cherchez le fichier
shell_minimal.html
dans le dépôt emsdk. Copiez-le dans un sous-dossier nomméhtml_template
dans votre précédent nouveau dossier. -
Naviguez maintenant jusqu'au nouveau dossier (toujours dans votre terminal disposant de l'environnement Emscripten), et exécutez la commande suivante :
emcc -o hello2.html hello2.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html
Les options que nous avons donné sont un peu différentes cette fois :
- Nous avons spécifié
-o hello2.html
, ce qui signifie que le compilateur va générer du code JavaScript "glue" ainsi qu'un.html
. - Nous avons également spécifié
--shell-file html_template/shell_minimal.html
— cela fournit le chemin vers le template HTML que vous souhaitez utiliser pour créer le HTML qui vous permettra d'exécuter l'exemple.
- Nous avons spécifié
-
Maintenant, lançons l'exemple. La commande ci-dessus aura généré hello2.html, qui aura à peu près le même contenu que le template avec un peu de code "glue" pour charger le code wasm généré, l'exéuter, etc. Ouvrez-le dans votre navigateur et vous verrez quasiment la même chose qu'avec notre dernier exemple.
Note: You could specify outputting just JavaScript rather than the full HTML by specifying a .js file instead of an HTML file in the -o
flag, e.g. emcc -o hello2.js hello2.c -O3 -s WASM=1
. You could then build your custom HTML complete from scratch. This isn't recommended however — Emscripten requires a large variety of JavaScript "glue" code to handle memory allocation, memory leaks, and a host of other problems, which is already included in the provided template. It is easier to use that than having to write it all out yourself, although as you become more experienced at what it all does, you'll be able to create your own customized versions for your needs.
Appeler une fonction personnalisée définie en C
If you have a function defined in your C code that you want to call as needed from JavaScript, you can do this using the Emscripten ccall()
function, and the EMSCRIPTEN_KEEPALIVE
declaration (which adds your functions to the exported functions list (see Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?)). Let's look at how this works.
-
To start with, save the following code as
hello3.c
in a new directory:#include <stdio.h> #include <emscripten/emscripten.h> int main(int argc, char ** argv) { printf("Hello World\n"); } #ifdef __cplusplus extern "C" { #endif void EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) { printf("MyFunction Called\n"); } #ifdef __cplusplus } #endif
By default, Emscripten-generated code always just calls the
main()
function, and other functions are eliminated as dead code. PuttingEMSCRIPTEN_KEEPALIVE
before a function name stops this from happening. You also need to import theemscripten.h
library to useEMSCRIPTEN_KEEPALIVE
.Note: We are including the
#ifdef
blocks so that if you are trying to include this in C++ code, the example will still work. Due to C versus C++ name mangling rules, this would otherwise break, but here we are setting it so that it treats it as an external C function if you are using C++. -
Now add
html_template/shell_minimal.html
into this new directory too, just for convenience (you'd obviously put this in a central place in your real dev environment). -
Now let's run the compilation step again. From inside your latest directory (and while inside your Emscripten compiler environment terminal window), compile your C code with the following command. (Note that we need to compile with NO_EXIT_RUNTIME, which is necessary as otherwise when main() exits the runtime would be shut down - necessary for proper C emulation, e.g., atexits are called - and it wouldn't be valid to call compiled code.)
emcc -o hello3.html hello3.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall"]'
-
If you load the example in your browser again, you'll see the same thing as before!
-
Now we need to run our new
myFunction()
function from JavaScript. First of all, let's add a<button>
as shown below, just above the first opening<script type='text/javascript'>
tag.<button class="mybutton">Run myFunction</button>
-
Now add the following code inside the last
<script>
element (just above the closing</script>
tag):document.querySelector('.mybutton').addEventListener('click', function(){ alert('check console'); var result = Module.ccall('myFunction', // name of C function null, // return type null, // argument types null); // arguments });
This illustrates how ccall()
is used to call the exported function.
Voir aussi
- emscripten.org — pour en apprendre plus sur Emscripten et sa large palette d'options
- Appeler des fonctions C compilées depuis JavaScript grâce à ccall/cwrap
- Pourquoi les fonctions dans mon code source C/C++ disparaissent quand je le compile dans JavaScript, et/ou je reçois une erreur "No functions to process" ?
- WebAssembly sur Mozilla Research