Compilando a WebAssembly : ¡está sucediendo!

27 marzo, 2016 3:08 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks. Traducción por Patricia Argüello.

WebAssembly es un nuevo formato binario para la compilación en la web. Está en el proceso de ser diseñado e implementado mientras hablamos, en colaboración entre los mayores proveedores de navegadores. ¡Las cosas se están moviendo deprisa! En este artículo mostraremos algunos de los recientes progresos con detalle en la parte de las cadenas de herramientas de WebAssembly.

Para que WebAssembly sea utilizable, necesitamos dos componentes principales: cadenas de herramientas que compilan código a WebAssembly, y navegadores que pueden ejecutar esa salida. Ambos componentes dependen del progreso en acabar la especificación de WebAssembly, pero sin embargo son esfuerzos de ingeniería independientes en gran manera. Esta separación es buena, dado que permitirá a los compiladores emitir WebAssembly que se ejecute en cualquier navegador, y navegadores ejecutar WebAssembly sin importar qué compilador lo generó; en otras palabras, permite múltiples herramientas y múltiples navegadores trabajar juntos, mejorando las posibilidades del usuario. La separación también permite trabajar en los dos componentes en paralelo ahora mismo.

Un nuevo proyecto en el aspecto de las cadenas de herramientas de WebAssembly es Binaryen. Binaryen es una librería de infraestructura de compilador para WebAssembly, escrita en C++. Si no estás trabajando en tu propio compilador WebAssembly, probablemente nunca necesitarás saber nada sobre ello, pero si usas un compilador WebAssembly entonces podría estar usando Binaryen por debajo; veremos ejemplos de eso más adelante.

El núcleo de Binaryen es un conjunto de clases modulares que pueden parsear y emitir WebAssembly, así como también representarlo en un AST diseñado para escribir transformaciones flexibles. Por encima existen varias herramientas útiles:

  • El shell Binaryen, el cual puede cargar un módulo WebAssembly, transformarlo, ejecutarlo en un intérprete, registrarlo en consola, etc. La carga e impresión de WebAssembly usan actualmente un formato temporal de expresión-s, el cual tiene el sufijo .wast (se sigue trabajando en el diseño del formato binario WebAssembly, así como en el formato de texto final, pero no están listos todavía).
  • asm2wasm, el cual compila asm.js a WebAssembly.
  • wasm2asm, el cual compila WebAssembly a asm.js. (Esto es un trabajo en curso).
  • s2wasm, el cual compila ficheros .s, en el formato emitido por el nuevo backend de WebAssembly siendo desarrollado en LLVM, a WebAssembly.
  • wasm.js, un puerto de Binaryen en sí mismo para JavaScript. Esto nos permite ejecutar todos los componentes mencionados en una página web o cualquier otro entorno JavaScript.

Para una visión general de Binaryen, puedes ver estas diapositivas de una charla reciente. No te pierdas la diapositiva #9 🙂

Es importante destacar que WebAssembly está todavía en fase de diseño, y los formatos que Binaryen puede leer y escribir (.wast, .s) no son definitivos. Binaryen ha sido actualizado constantemente con esos cambios; la tasa de rotación está disminuyendo, pero se esperan fracturas.

Hablemos sobre alguna de las áreas específicas donde Binaryen puede ser útil.

Compilando a WebAssembly usando Emscripten

Emscripten puede compilar C y C++ a asm.js, y la herramienta asm2wasm de Binaryen puede compilar asm.js a WebAssembly, así que juntas Emscripten+Bynaren suministran una manera completa de compilar C y C++ para WebAssembly. Puedes ejecutar asm2wasm sobre código asm.js directamente (puede ser ejecutado en la línea de comandos), pero lo más sencillo es dejar que Emscripten lo haga por ti, usando algo como

emcc file.cpp -o file.js -s 'BINARYEN="path-to-binaryen"'

Emscripten compilará el fichero file.cpp, y emitirá un fichero JavaScript principal y un fichero separado para la salida WebAssemly, en formato .wast. Por debajo, Emscripten compila a asm.js, entonces ejecuta asm2wasm en el fichero asm.js para producir el fichero.wast. Para más detalles, véase la página de la wiki Emscripten sobre WebAssembly.

Pero espera, ¿qué beneficio tiene compilar a WebAssembly cuando los navegadores aún no lo soportan? Buena pregunta 🙂 Sí, no queremos expedir este código mientras los navegadores no puedan ejecutarlo. Pero aun así es muy útil con finalidad de testing: queremos saber que Emscripten puede compilar adecuadamente a WebAssembly tan pronto como podamos, aun así no queremos esperar a la compatibilidad del navegador.

¿Pero cómo podemos verificar que Emscripten es de hecho compilado adecuadamente a WebAssembly, si no podemos ejecutarlo? Para ello, podemos usar wasm.js, el cual integró Emscripten en nuestro fichero de output.js cuando lo ejecutamos antes con el  comando emcc. wasm.js contiene partes de Binaryen compilado a JavaScript, incluyendo el intérprete Binaryen. Si ejecutas file.js en node.js, o en una página web entonces lo que ocurre es que el intérprete ejecutará ese WebAssembly. Eso nos permitirá en realidad verificar que el código compilado WebAssembly hizo lo correcto. Puedes ver un ejemplo de un programa compilado similar aquí, y hay más desarrollos con finalidad de testing en el repositorio del conjunto de builds.

Por supuesto, no estamos precisamente en una base tan sólida como nos gustaría, dado este extraño entorno de pruebas: un programa C++ compilado para WebAssembly, ejecutándose en un intérprete WebAssembly a su vez compilado desde C++ a JavaScript, y no hay otra forma de ejecutar el programa todavía. Pero tenemos algunas razones para estar seguros en los resultados:

  • Esta salida pasa la batería de pruebas de Emscripten. Eso incluye mucho código real (Python, zlib, SQLite, etc.) así como montones de test unitarios para los casos límite (corner cases) en C y C++. La experiencia ha demostrado que cuando un conjunto de pruebas ha pasado, es muy probable que otro código funcione también.
  • El intérprete Binaryen pasa la especificación del conjunto de pruebas WebAssemly, indicando que sí está ejecutando WebAssembly correctamente. En otras palabras, cuando los navegadores consiguen soporte nativo, deberían ejecutarlo de la misma manera (¡a excepción de que mucho más rápido! Este código está ejecutándose en un intérprete simple para finalidad de pruebas, así que es muy lento; pero date cuenta de que hay trabajo en desarrollo en maneras rápidas de usar polyfill).
  • Esta salida fue generada usando Emscripten, el cual es un compilador estable usado en producción, y una relativa pequeña cantidad de código por encima de lo que es Binaryen (solo unas miles de líneas). Cuanto menos código nuevo, menor riesgo de bugs.

Sobre todo, ésto indica que estamos en buena condición aquí, y podemos compilar C y C++ a WebAssemly hoy usando Emscripten + Binaryen, incluso si los navegadores no pueden ejecutarlo aún.

Nota que aparte de emitir WebAssembly, las estructuras que emitimos en este modo usan todo lo demás en la cadena de herramientas de Emscripten: el puerto de Emscripten de musl libc y syscalls para accederlo, el código OpenGL/WebGL, integración de código en el navegador, integración de código node.js, etc. Como resultado, esto soporta todo lo que Emscripten ya hace, y los proyectos existentes que usan Emscripten pueden cambiar para la emisión WebAssembly con sólo el toque de un interruptor. Esto es la parte fundamental de dejar proyectos C++ que compilan para la web tener beneficio de WebAssembly cuando se lance, con un poco o sin esfuerzo por su parte.

Usando el nuevo backend LLVM WebAssembly experimental con Emscripten

Acabamos de ver un importante hito para Emscripten, puede compilar para WebAssembly e incluso probar que obtenemos una salida válida. Pero las cosas no quedan aquí: ésto era usando el actual backend asm.js de Emscripten, junto con asm2wasm. Hay un nuevo backend LLVM  para WebAssembly en desarrollo directamente en el repositorio de LLVM, y aunque no esté listo para el uso general aún, a largo plazo será muy importante. Binaryen tiene soporte para eso también.

El backend LLVM, como la mayoría de los backends LLVM, emiten código ensamblador, en este caso en un formato específico .s. Esa salida está próxima a WebAssemly, pero no es idéntica – se parece más la salida de un compilador C (una lista lineal de instrucciones, una instrucción por línea, etc.) más bien que al AST más estructurado de WebAssembly. El fichero .s puede ser traducido a WebAssembly de una manera bastante directa, sin embargo, y Binaryen incluye s2wasm, una herramienta que traduce .s a WebAssembly. Puede ser ejecutado de manera standalone en la línea de comandos, pero también tiene soporte a la integración Emscripten: Emscripten ahora tiene una opción WASM_BACKEND, la cual puedes usar como esto:

emcc file.cpp -o file.js -s ‘BINARYEN=”path-to-binaryen”’ -s WASM_BACKEND=1

(Date cuenta que también necesitas la opción BINARYEN, como s2wasm es parte de Binaryen.) Cuando esta opción es proporcionada, Emscripten usa el nuevo backend de WebAssembly en lugar del existente con asm.js. Después de que la llamada al backend y recibir .s desde el, Emscripten llama s2wasm para convertir eso a WebAssembly. Algunos ejemplos de programas que puedes construir con el nuevo backend están en la wiki de Emscripten.

Hay, por lo tanto, dos maneras de compilar a WebAssemly usando Binaryen: Emscripten + asm.js backend + asm2wasm, lo cual funciona correctamente ahora y debería ser suficientemente robusto y seguro, y Emscripten + nuevo backend WebAssembly + s2wasm, el cual no es todavía totalmente funcional, pero a medida que el backend de WebAssembly vaya madurando debería convertirse en una opción potente, y ojala reemplace al backend asm.js en el futuro. El objetivo es hacer la transición fluida: cambiar entre los dos modos de WebAssembly es sólo una cuestión de ajustar una opción, como hemos visto.

Lo mismo es también cierto entre asm.js y el soporte WebAssembly en Emscripten, el cual es también sólo una opción que puedes establecer, y la transición allí debería ser fluida también. En otras palabras, habrá un camino simple y directo desde

  • usar Emscripten para emitir asm.js hoy, para
  • usarlo para emitir WebAssembly usando asm2wasm (posible hoy, pero los navegadores no pueden ejecutarlo aún), para
  • usarlo para emitir WebAssembly usando el nuevo backend LLVM (una vez que el backend esté listo).

Cada paso debería proveer beneficios sustanciales, sin esfuerzo extra para los desarrolladores.

Para concluir, observa que mientras este artículo se centró en el uso de Binaryen con Emscripten, en su núcleo está diseñado para ser una librería WebAssembly de uso general en C++: Si quieres escribir algo relacionado con la cadena de herramientas WebAssembly, probablemente necesitarás código para leer WebAssembly, emitirlo, un AST para funcionar, etc., el cual Binaryen suministra. Fue muy útil escribir asm2wasm, s2wasm, etc., y ojalá otros proyectos lo encuentren útil también.

The following two tabs change content below.

jorgev

Add-ons Developer Relations Lead at Mozilla
Jorge trabaja para el equipo de complementos de Mozilla, y se dedica a Mozilla Hispano y Mozilla Costa Rica en su tiempo libre. Actualmente está encargado del blog de Mozilla Hispano Labs.

Compartir artículo:

Start the discussion at foro.mozilla-hispano.org

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa