Emscripten - tech

Anuncio
Emscripten
Ernesto Alfonso Bascón Pantoja
Jalasoft
ernesto.bascon@jalasoft.com
http://oopscenities.net
RESUMEN
usuario, con muchas caracterı́sticas diseñadas para soportar mouse, aceleradores de teclado, múltiples ventanas, etc. (Adobe PhotoShop, Adobe Illustrator, Microsoft Office, Microsoft Visual Studio, Fruity Loops,
AutoCAD, etc.) que tienen interfaces de usuario maduras
y cuyas caracterı́sticas son difı́ciles de portar a entornos web.
En este ensayo presentaremos Emscripten [1], una infraestructura de desarrollo que permite que aplicaciones escritas en
código nativo (generalmente usando C ó C++) se ejecuten
dentro de un navegador web.
Keywords
Emscripten, web, nativo, C, C++, navegador, compilador,
plataforma, LLVM, JavaScript, asm.js
1.
• Alto consumo de recursos. Algunas aplicaciones
(como los juegos), necesitan una inmensa cantidad de
recursos (memoria, tarjetas gráficas, procesador, etc.)
no disponibles para aplicaciones web.
INTRODUCCIÓN
Dada la emergencia vertiginosa de las tecnologı́as web, el desarrollo de aplicaciones para estas tecnologı́as se ha visto a su
vez acelerado gracias a las grandes mejoras en el rendimiento
de los motores de ejecución de JavaScript en la mayorı́a de
los navegadores web (Firefox, Chrome, Internet Explorer,
Safari y Opera) y gracias a la proliferación de frameworks
que facilitan el desarrollo de mencionadas aplicaciones.
Estos frameworks implementan diferentes caracterı́sticas que
facilitan el desarrollo de aplicaciones cliente, mejoran la interacción con el servidor, mantienen el modelo de datos sincronizado entre los clientes y los servidores, etc.
Y aunque dichos frameworks facilitan la creación de software web, existe en el mercado una cantidad inmensa de
aplicaciones escritas para entornos de escritorio que no son
fácilmente portables a entornos web por diversos factores:
• Falta de motivación. Si bien estamos en una época
en que todo es desechable (incluı́do el software), muchas
empresas de desarrollo pueden encontrar falta de motivación para rehacer sobre una plataforma web sus aplicaciones que ya existen, escalan, tienen muchos bugs
arreglados, venden, funcionan y sobretodo, cubren las
necesidades de sus clientes.
Emscripten, al ser una infrastructura de desarrollo (compilador, toolchain, SDK, runtime, etc.) que permite compilar
aplicaciones nativas para que puedan ejecutarse (con poca o
ninguna modificación) dentro de un navegador, permite que
aplicaciones ya existentes, de alto rendimiento o de interfaz
de usuario compleja, puedan implantarse en el mundo de las
aplicaciones web; eliminando en su totalidad (o en muy alto
grado) la necesidad de reescribir la aplicación.
• Alta complejidad. Aplicaciones escritas desde hace
muchos años que han venido creciendo y adquiriendo
caracterı́sticas que las hacen muy completas pero a su
vez complejas y difı́ciles de rescribir en un tiempo prudente.
Emscripten es implementado y desarrollado en Mozilla.
• Interfaz de usuario sofisticada. Aplicaciones desarrolladas desde cero pensando en la experiencia del
El proyecto de software libre LLVM es una infraestructura de
compilación diseñada como un conjunto de librerı́as modulares reusables con una interfaz muy bien definida. Gracias a
este enfoque, LLVM facilita la construcción de compiladores,
optimizadores y generadores de código binario para diferentes conjuntos de instrucciones de una manera bastante
sencilla.[2]
Permission to make digital or hard copies of all or part of this work for
personal or classroom use is only granted for Jalasoft employees or use at
the Jala Foundation respectively; copies must bear this notice and the full
citation on the first page. To copy otherwise, or republish, to post on servers
or to redistribute to lists, requires prior specific permission and/or a fee.
c 2015 JalaTechZone, octubre 2015, Cochabamba, Bolivia. Copyright soft TechZone.
2.
2.1
INFRAESTRUCTURA
LLVM
A diferencia de los compiladores GCC que están diseñados de una manera monolı́tica, LLVM proporciona múltiples
componentes que pueden acoplarse o intercambiarse entre sı́
(ver figura 1), como ser:
3
Figura 1: Arquitectura de LLVM
CARACTERÍSTICAS DE EMSCRIPTEN
Figura 2: Comparativa de rendimiento de Asm.js [4]
• Varios front-ends.
LLVM soporta varios frontends, y gracias a ello, es posible conectar a la infraestructura de compilación una variedad de lenguajes
de programación diferentes, como ser C, C++, ObjectiveC, Rust, Ruby, Python, Haskell, etc. Los front-ends de
LLVM toman código fuente escrito en algún lenguaje
de programación y generan un Árbol de Sintaxis Abstracto (AST) que es una representación estándar del
código fuente.
• Optimizador de Representación Intermedia. Es
el corazón de LLVM: A partir del árbol de sintaxis
abstracto, LLVM genera la representación intermedia
(IR) que es su núcleo fundamental. Esta representación
intermedia es un lenguaje de programación de bajo
nivel similar a assembler. IR es un conjunto de instrucciones RISC fuertemente tipado que no toma en cuenta
detalles de la plataforma destino de la aplicación.
que el motor de ejecución que lo implementa, pueda optimizar la ejecución de un programa Asm.js bastante y ası́
lograr velocidades de ejecución mucho mayores y en algunos
casos cercanas a velocidades nativas. Mozilla ha diseñado y
agregado soporte para asm.js en su navegador Firefox, pero
Google Chrome y Microsoft Edge lo han implementado también.
Éste es un ejemplo de código Asm.js escrito manualmente:
function s t r l e n ( ptr )
{ // c a l c u l a e l tamaño de una cadena C
ptr = ptr | 0 ;
var c u r r = 0 ;
curr = ptr ;
w h i l e (MEM8[ c u r r ] | 0 != 0 )
{
curr = ( curr + 1 ) | 0 ;
}
return ( curr − ptr ) | 0 ;
}
• Varios back-ends. Los back-ends permiten transformar código IR en una salida orientada a la plataforma
de destino, ası́, se pueden proveer back-ends para x86,
x86-64, AMD, MIPS, etc. Emscripten es un back-end
de LLVM, puesto que transforma IR en asm.js.
En el código escrito arriba,
• Intérprete. LLVM también provee de un intérprete
que permite ejecutar directamente IR.
• ptr representa el puntero que apunta al primer caracter de una cadena C.
• Depurador.
LLVM incorpora un depurador que
reemplaza al depurador gdb de gcc.
2.2
• "|0" no tiene efecto en la expresión donde se encuentra pues realiza una operación ”OR” a nivel de bits;
PERO indica al motor de ejecución de JavaScript que
la expresión es una expresión entera (y ası́ optimizar
su ejecución). Sin dicha operación ”OR”, el motor de
ejecución podrı́a inferir que la variable es de otro tipo
numérico.
Asm.js
Asm.js es un subconjunto estricto de JavaScript que puede
ser usado como un lenguaje de bajo nivel como destino de
compilación. Asm.js provee una abstracción similar a la del
modelo de C ó C++: un gran ”heap” binario con almacenamiento eficiente, aritmética de números enteros y con
coma flotante, definiciones de funciones de primer orden y
punteros a funciones[3].
• MEM8 es el array que representa a la memoria de la
aplicación C.
Asm.js es, a diferencia de JavaScript, un lenguaje fuertemente tipado donde la memoria es modelada como un gran
array; ası́, cualquier asignación, acceso o liberación de memoria es hecha como una operación sobre ese array. El código
Asm.js por lo general no es fácilmente legible o entendible
por seres humanos pero tampoco ha sido diseñado con ese
objetivo, sino como un lenguaje de muy bajo nivel (de ahı́ el
nombre asm.js) que simula un entorno de ejecución nativo.
En la figura 2, se pueden ver las diferencias de rendimiento
de varios algoritmos implementados nativamente y usando
Asm.js y ejecutándolos en varios entornos diferentes.
3.
CARACTERÍSTICAS DE EMSCRIPTEN
Como se ve en la figura 3, Emscripten está construı́do sobre
LLVM: Reutiliza el frontend de Clang y el optimizador de
IR e implementa un backend que genera código Asm.js.
Un programa escrito en Asm.js se comportará de manera
idéntica tanto en un motor de ejecución que sabe cómo ejecutarlo, como en un motor de JavaScript estándar. Las limitaciones incorporadas a Asm.js y el tipado estricto, hacen
Ası́mismo, Emscripten provee:
2
4
4.
USO DE APIS WEB
USO DE APIS WEB
Las siguientes APIs web son soportadas en Emscripten:
4.1
Figura 3: Infraestructura de Emscripten
3.1
• MEMFS, que es un sistema de archivos almacenados en memoria; por tanto, cada vez que el programa
es cargado de nuevo por el navegador, el sistema de
archivos aparece al usuario como totalmente vacı́o. Emscripten proporciona los mecanismos necesarios para
cargar los archivos necesarios por el sistema.
Compiladores C y C++
Emscripten provee un compilador que recibe los mismos argumentos y entiende la misma sintaxis que gcc ó clang.
Gracias a ello, es muy sencillo reemplazar el compilador
C ó C++ por el compilador de Emcripten (emcc, em++)
en un archivo make. Este compilador básicamente utiliza
Clang[5] (Clang es un front-end de LLVM que permite compilar C, C++ y Objective-C) para generar código Asm.js y
HTML. Al usar Clang como front-end, todas las caracterı́sticas disponibles en C++14 y en las últimas versiones del
lenguaje están ya disponibles para Emscripten.
3.2
• NODEFS, es un sistema de archivos virtual que permite almacenar la información usando los mecanismos
provistos por node.js.
• IDBFS, es un sistema de archivos que permite almacenar la información persistentemente utilizando indexedDB, que es parte del mecanismo de persistencia
de la mayorı́a de los navegadores actuales.
Generador de código Asm.js y HTML
El generador de código es capaz de generar, a partir de la
representación intermedia de LLVM (IR), código Asm.js que
puede ser ejecutado por cualquier motor de ejecución de
JavaScript (como node.js) ó HTML con código JavaScript
incrustado, para poder ser ejecutado directamente en un
navegador web.
3.3
Lo interesante de estos sistemas de archivos virtuales, es que,
aunque cada uno almacena la información de manera muy
diferente, Emscripten se encarga de que su comportamiento
sea exactamente el mismo para las funciones de C y C++
de manejo de archivos.
Inclusión de librerías estándar
4.2
Emscripten viene con las librerı́as estándares de C y C++;
ası́ cualquier aplicación estándar puede ser compilada de
manera muy sencilla usando Emscripten.
3.4
FileSystem API
Emscripten provee las funciones básicas de manejo de archivos
de C (FILE*, fopen, fclose, fread, fwrite, etc.) pero están implementadas de tal manera que en lugar de acceder al
sistema de archivos nativo (no posible debido a que el navegador trabaja en un ”sandbox” seguro), accede a un sistema
de archivos virtual que puede ser:
WebGL
WebGL[7] es una API disponible en JavaScript que permite
acceso a aceleración de gráficos por hardware. Gracias a
WebGL se pueden desarrollar juegos o animaciones de alta
calidad y buen rendimiento en JavaScript.
SDL
SDL[6] ha sido portado a Emscripten y viene ya en la plataforma. Emscripten permite utilizar las APIs de OpenGL y a parSDL es importante porque provee los cimientos para la creación
tir de un ”wrapper”, dichas llamadas son transformadas en
de interfaces gráficas de usuario en C++ (Qt tiene un backinvocaciones WebGL en el navegador.
end para SDL y la mayorı́a de los juegos comerciales están
escritos con librerı́as escritas usando SDL).
4.3 HTML5
3.5
Emscripten provee una librerı́a escrita en C que permite acceder a:
Emscripten ports
Emscripten ports[8] es un repositorio que contiene un conjunto de librerı́as nativas portadas a JavaScript usando Emscripten. Entre dichas librerı́as están vorbis, zlib, libpng
y otras.
• Eventos de teclado, ratón, rueda, foco, etc. en nivel
DOM 3.
3.6
• Eventos de orientación de dispositivo para giroscopio
y acelerómetro.
Interoperabilidad
Emscripten provee varios mecanismos para conectar C y
C++ con JavaScript[9]. Existen mecanismos para:
• Eventos de orientacion de pantalla, para manejo de
pintado como retrato o paisaje.
• Eventos para manipulación de pantalla completa.
• Invocar funciones compiladas en C desde código JavaScript.
• Invocar código JavaScript desde código C/C++.
• APIs para manejo de vibración en teléfonos móviles.
• Eventos de visibilidad de página.
• Implementar una API C en JavaScript. Usando este
enfoque se portó exitosamente SDL y se hizo la implementación de WebGL y libc.
• Eventos de toque.
• Manejo de CSS.
3
8
5.
WEBASSEMBLY
LIMITACIONES
Emscripten posee las siguientes limitaciones:
• Emscripten no soporta múltiples hilos de ejecución (threads)
aunque sus desarrolladores están trabajando para sı́
soportarlos. Mientras tanto, sı́ provee facilidades para
utilizar Web Workers[11]. Los Web Workers, aunque
mucho más restrictivos que los hilos, al no permitir acceso a recursos compartidos entre workers, logran que
la paralelización de tareas se haga de manera mucho
más simple y eficiente (no hay necesidad de semáforos y
por tanto no existe la posibilidad de dead-locks, condiciones de carrera o corrupción de datos compartidos).
• Su soporte para manejo de audio es aún limitado.
• Su soporte para acceso a redes es sólo ası́ncrono dada
la naturaleza ası́ncrona de las APIs de JavaScript.
Figura 4: ”Hola mundo” en Firefox
• Si bien varias aplicaciones y juegos han sido portados con éxito a Emscripten, existen varias aplicaciones
construı́das utilizando tecnologı́as propietarias o no estándares, que son difı́ciles o imposibles de portar hacia
Emscripten. Por ejemplo, todas las aplicaciones implementadas sobre Windows usando la Win32 API, MFC
ó tecnologı́as COM, no son portables a menos que se
re-escriba buena parte del código que utiliza dichas tecnologı́as o se escriban librerı́as que publiquen las mismas APIs pero que utilicen tecnologı́as estándar por
debajo. WineLib[10] es una librerı́a de código abierto
que implementa la Win32 API. Lo mismo ocurre con
aplicaciones escritas en Objective-C utilizando las librerı́as propias de Apple (Cocoa, Core Audio, Core
Graphics, etc.).
Si el código es guardado en un archivo hm.cpp, el comando
para compilarlo usando el compilador de C++ es:
g++ hm.cpp -o hm -std=c++1y
g++ es el nombre del compilador de C++; -o especifica el
nombre del archivo de salida y -std=c++1y especifica que se
está utilizando el estándar C++14. Ese comando generará
un archivo llamado hm que se puede ejecutar en un entorno
Linux escribiendo:
./hm
E imprimirá ”Hola mundo” en la consola.
6.
LICENCIA
Para compilarlo usando Emscripten, se debe escribir la siguiente lı́nea de comandos:
Emscripten es un proyecto de software libre que puede ser
utilizado y distribuido de acuerdo a lo estipulado por la licencia MIT[12] que permite distribuir y utilizarlo tanto en
software comercial como libre siempre y cuando se distribuya
con una copia de la licencia MIT y el respectivo copyright
del proyecto.
7.
em++ hm.cpp -o hm.js -std=c++1y
Como se puede ver, la interfaz es casi la misma; em++ es el
nombre del compilador Emscripten de C++. Si el archivo de
salida tiene extensión .js, el compilador generará un archivo
JavaScript que puede ser ejecutado usando Node.js:
"HOLA MUNDO"
Para ejemplificar un poco el uso de Emscripten, veremos
cómo compilar y ejecutar un programa ”Hola mundo” escrito
en C++14:
nodejs hm.js
También puede compilarse para generar un archivo HTML5
con código JavaScript incrustado usando la siguiente lı́nea
de comandos:
#i n c l u d e <i o s t r e a m >
u s i n g namespace s t d ;
em++ hm.cpp -o hm.html -std=c++1y
auto main ( ) −> i n t
{
auto f = [ ] ( auto&& s )
{
c o u t << s << e n d l ;
};
f ( ” Hola mundo ”s ) ;
return 0;
}
La figura 4 muestra la ejecución de ese archivo hm.html en
una ventana de navegador.
8.
WEBASSEMBLY
WebAssembly[13] es un proyecto conjunto de Mozilla, Microsoft, Google y Apple cuya finalidad es la de diseñar un
bytecode para JavaScript; gracias a ese bytecode, las aplicaciones en JavaScript podrán ser cargadas de manera binaria
4
12
REFERENCIAS
en lugar de código fuente, eliminando ası́ los procesos de
”parseado”, compilado y optimizado de los programas y por
tanto, mejorando aún más el rendimiento de una aplicación
nativa corriendo en el navegador.
Dado que Emscripten usa toda la infraestructura de LLVM,
serı́a posible utilizar frontends de Haskell, Rust ó D por
ejemplo, para compilar aplicaciones existentes en dichos lenguajes a Asm.js.
9.
Aún existen varias cosas que deben ser implementadas y
mejoradas, pero el futuro de esta tecnologı́a se ve brillante.
RELACIÓN CON NACL Y PNACL
NaCl (Native Client) y PNaCl (Portable Native Client) son
tecnologı́as de Google implementadas en Chrome que permiten ejecutar código nativo dentro de dicho navegador.
Aunque la finalidad es la misma que la de Emscripten, presenta varias diferencias:
12.
• NaCl y PNaCl presentan una API que el programador
debe utilizar al implementar o portar su aplicación
C++ para que pueda ejecutarse dentro de Google Chrome.
Emscripten permite portar la aplicación sin modificación alguna.
• Ya que Chrome ejecuta el código nativo, el rendimiento
de una aplicación implementada usando su tecnologı́a
deberı́a ser mejor que la de Emscripten.
• NaCl y PNaCl son tecnologı́as especı́ficas a Google Chrome
y ninguna otra empresa las ha implementado en sus
navegadores, convirtiéndose en una tecnologı́a privativa a Chrome. Emscripten, por el contrario, utiliza
Asm.js que es un subconjunto de JavaScript; donde
está implementado (Firefox, Chrome y Edge) permite
la ejecución muy óptima y eficiente de la aplicación
compilada a Asm.js; y donde no, permite la ejecución de la aplicación con un rendimiento inferior. Por
tanto Emscripten es una tecnologı́a mucho más universal porque está construı́da sobre tecnologı́a ya existente.
• NaCl y PNaCl replican hasta cierto punto tecnologı́as
como Microsoft ActiveX que limitaron el progreso de
las tecnologı́as web.
10.
USOS NOTABLES
• Los motores de juego Unity3D, Godot Game Engine y Unreal Engine proveen opciones para exportar sus resultados en HTML5 y para ello utilizan Emscripten como backend.
• En diciembre de 2014, el Internet Archive lanzó
un emulador DOSBox compilado en Emscripten que
provee acceso a miles de juegos desarrollados para PC
y MS-DOS.[14]
11.
CONCLUSIONES
Emscripten es una plataforma que ya permite que muchas
aplicaciones nativas sean fácilmente portadas a la web. Después de su aparición y de haber demostrado su factibilidad, WebAssembly se presenta como el paso siguiente hacia
la ejecución de aplicaciones nativas sobre la web. Implementar un front-end en Emscripten que genere bytecodes de
WebAssembly en lugar de Asm.js deberı́a ser una tarea relativamente sencilla dada toda la infraestructura ya existente.
Es posible que aparezcan frameworks y librerı́as escritas en
C++ orientadas al desarrollo de aplicaciones nativas para
Emscripten.
5
[1]
[2]
[3]
[4]
REFERENCIAS BIBLIOGRÁFICAS
http://emscripten.org 1
http://en.wikipedia.org/wiki/LLVM 1
http://asmjs.org/spec/latest 2
http://ejohn.org/blog/asmjs-javascript-compile-target/
2
[5] http://clang.llvm.org 3
[6] http://www.libsdl.org 3
[7] https://www.khronos.org/webgl/ 3
[8] https://github.com/emscripten-ports 3
[9] http://kripken.github.io/emscriptensite/docs/porting/connecting cpp and javascript/Interactingwith-code.html
3
[10] http://wiki.winehq.org/Winelib 4
[11] https://w3c.github.io/workers/ 4
[12] http://opensource.org/licenses/MIT 4
[13] https://www.w3.org/community/webassembly/ 5
[14] https://github.com/jsmess/jsmess 5
Descargar