Comenzando con WebAssembly

WebAssembly es una nueva tecnología que hace posible ejecutar a alto rendimiento, código de bajo nivel en el navegador. Puede utilizarse para traer grandes codebases de C y C ++ como juegos, motores físicos e incluso aplicaciones de escritorio a la plataforma web.

WebAssembly se puede utilizar en Chrome y Firefox, y cuenta con soporte casi completo en Edge y Safari también. Esto significa que muy pronto, serás capaz de ejecutar wasm en todo navegador web.

En este tutorial, te mostraremos cómo compilar un archivo C a wasm e incluirlo en una página web.

¿Cómo funciona WebAssembly?

En primer lugar, una descripción rápida de lo que realmente hace WebAssembly. Intentaremos no ser demasiado técnicos.

En los navegadores de hoy en día, JavaScript se ejecuta en una máquina virtual (VM) que optimiza su código y exprime cada bit de rendimiento. Tal y como están las cosas, JS es uno de los lenguajes dinámicos más rápidos. A pesar de que es rápido, todavía no puede competir con el código C y C++. Aquí es donde entra WebAssembly.

Wasm se ejecuta en la misma VM de JavaScript, pero funciona mucho mejor. Los dos pueden comunicarse libremente y no se excluyen entre sí. De esta manera puedes tener lo mejor de ambos mundos: el enorme ecosistema de JavaScript y su sencilla sintaxis, combinado con el rendimiento casi nativo de WebAssembly.

La mayoría de la gente desarrolla los módulos de WebAssembly en C y los compila en archivos .wasm. Estos archivos wasm no son reconocidos por el navegador directamente, por lo que necesitan algo llamado código de pegamento para cargar.

En el futuro, este proceso probablemente será más breve mediante frameworks de WebAssembly y el soporte nativo del módulo wasm.

Lo que necesitarás para esta lección

Necesitas unas cuantas herramientas para desarrollar en Web Assembly. Pero no te preocupes, la mayoría de las cosas de esta lista son la mar de comunes y es probable que ya las tengas.

  • Navegador con soporte para WebAssembly. Chrome actualizado a la última versión, por ejemplo.
  • Compilador de C a WebAssembly, como por ejemplo Emscripten portable.
  • Compilador para C (GCC en Linux, Xcode en OS X, Visual Studio para Windows).
  • Servidor web local sencillo para ejecutar el ejemplo (por ejemplo, python -m SimpleHTTPServer 9000)

Instalar Emscripten tarda un tiempo y definitivamente no es divertido, pero es el mejor compilador en estos momentos. Además, asegúrate de que tiene suficiente espacio libre en el disco duro, ya que en mi equipo ocupó casi 1GB.

Paso 1: Escribir código C

Crearemos un ejemplo super simple en C que seleccionará un número aleatorio entre 1 y 6. En el directorio de trabajo que quieras, crea un nuevo archivo dice-roll.c.

#include <stdio.h>
#include <stdlib.h>
#include <emscripten/emscripten.h>

int main(int argc, char ** argv) {
    printf("WebAssembly module loadedn");
}

int EMSCRIPTEN_KEEPALIVE roll_dice() {
    srand ( time(NULL) );
    return rand() % 6 + 1;
}

Cuando compiles a wasm y cargues este código en el navegador, se ejecutará el main automáticamente. El printf dentro de él será traducido a un console.log y llamado.

Queremos que la función roll_dice esté disponible en JavaScript siempre que lo necesitemos. Para decirle al compilador de Emscripten nuestras intenciones tenemos que agregar EMSCRIPTEN_KEEPALIVE.

Paso 2: Compilar C en WebAssembly

Ahora que tenemos nuestro programa C simple, tenemos que compilarlo en wasm. No sólo eso, sino que también necesitamos generar el código de pegamento de Javascript que nos ayudará realmente a hacerlo funcionar.

Aquí tenemos que usar el compilador Emscripten. Hay toneladas de opciones de CLI disponibles y muchos enfoques diferentes. Creo que la siguiente combinación es la más fácil de usar:

emcc dice-roll.c -s WASM = 1 -O3 -o index.js

Aquí tienes un desglose de lo que está sucediendo:

  • emcc - El compilador Emscripten.
  • dice-roll.c - El archivo de entrada que contiene nuestro código C.
  • -s WASM = 1 - Especifica que estamos trabajando con WebAssembly.
  • -03 - El nivel de optimización de código que queremos, 3 es bastante alto.
  • -o index.js - Dice a emcc que genere un archivo JS con todo el código de pegamento necesario para nuestro módulo wasm.

Después de ejecutar el comando, en nuestro directorio de trabajo se añadirán dos archivos: index.wasm e index.js. Uno con el módulo de WebAssembly, y el otro, con el código de pegamento, respectivamente.

Paso 3: Cargar código de WebAssembly en el navegador

Aterrizamos en territorio de desarrollo web de toda la vida. Creamos un archivo index.html básico e incluimos el código de pegamento de JavaScript en una etiqueta de script.

<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>WebAssembly Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>

    <!-- Include the JavaScript glue code. -->
    <!-- This will load the WebAssembly module and run its main. --> 
    <script src="index.js"></script>

  </body>
</html> 

Debido a problemas de cross-origin, para ejecutar el proyecto necesitaremos un servidor web local. En Linux / OS X puede iniciar uno ejecutando el siguiente código en el directorio del proyecto:

python -m SimpleHTTPServer 9000

Ahora en el navegador, ve a localhost: 9000 para ver la aplicación. Si abres la consola del navegador, debe mostrarse el mensaje de bienvenida que imprimimos en el main de nuestro código C.

Paso 4: Funciones de WebAssembly

El último paso de nuestro experimento es conectar JavaScript y WebAssembly. Esto es en realidad es muy sencillo debido al código de pegamento de JavaScript generado a partir de Emscripten. Maneja todo los hilos por nosotros.

Hay una API bastante potente para trabajar con WebAssembly en el navegador. No entraremos en ella en detalle ya que está muy por encima del alcance de este tutorial. Las únicas piezas que necesitaremos son la interfaz del módulo y su método ccall. Este método nos permite llamar a una función del código C por su nombre, y usarlo como una de JS.

var result = Module.ccall(
    'funcName',     // name of C function 
    'number',       // return type
    ['number'],     // argument types
    [42]);          // arguments

Después del ccall, en result tendremos lo que se haya devuelto a la respectiva función C. Todos los argumentos aparte del primero son opcionales.

También existe una versión abreviada:

// Call a C function by adding an underscore in front of its name:
var result = _funcName();

Nuestra función roll_dice de C no requiere ningún parámetro. Llamarla en JavaScript es muy fácil:

// When a HTML dice is clicked, it's value will change.
var dice = document.querySelector('.dice');

dice.addEventListener('click', function(){

    // Make a call to the roll_dice function from the C code.
    var result = _roll_dice();
    dice.className = "dice dice-" + result;                   

});

Fuente: tutorialzine.com

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP