Emscripten : du C++ vers JavaScript via LLVM

Arnaud de la Grandière |
L'une des grandes quêtes du développement logiciel depuis de nombreuses années consiste à permettre l'exécution d'un code arbitraire sur n'importe quelle architecture matérielle sans avoir à rien recoder.

De nombreuses architectures se sont frottées au problème (de Java en passant par .NET) sans pour autant parvenir à résoudre la quadrature du cercle : celles-ci ne prennent pas en charge le code natif dans des langages universels tels que le C/C++.

De son côté Google a bien tenté de remédier à la question en proposant Native Client, un plugin qui permet l'exécution d'un même code en natif dans n'importe quel navigateur (lire Google NaCl : du code natif dans le navigateur), mais les plugins sont en passe de tomber en désuétude et NaCl ne semble pas décoller.

Le problème devient d'autant plus prégnant avec l'avènement des plateformes mobiles, pour lesquelles JavaScript est en passe de devenir le seul sésame garanti.

C'est là où LLVM entre en jeu : cette technologie open-source (chapeautée par Apple, lire Apple tire le jus des processeurs) permet d'insérer une couche d'abstraction dans la compilation d'un code. Ce BitCode intermédiaire est alors susceptible d'être adapté à toute machine de destination, sans pour autant perdre le moins du monde en efficacité. Google a d'ailleurs créé une passerelle entre NaCl et LLVM.

Un développeur de Mozilla, Alon Zakai, a mis au point un compilateur nommé Emscripten, qui tire parti de cette capacité, en convertissant du BitCode LLVM en JavaScript. Ainsi, LLVM devient la passerelle entre n'importe quel langage qu'il est susceptible de prendre en charge (C/C++ en tête, mais également Python, Ruby, etc), et le navigateur.

Naturellement la conversion ne fonctionne pas de manière universelle : certaines commandes ne pourront pas être compilées, d'autres seront particulièrement lentes à l'exécution (Zakai donne une liste des choses à éviter), et il ne faut pas oublier que le JavaScript reste un langage interprété qui sera bien plus lent à l'exécution que du code natif (un benchmark donne Emscripten jusqu'à 140 fois plus lent que du code natif). De même, tous les moteurs JavaScript, qui varient d'un navigateur à l'autre, ne se valent pas. Ainsi certains projets réalisés avec Emscripten fonctionneront parfaitement sur certains navigateurs et beaucoup moins bien sur d'autres.

Il n'en reste pas moins que la prouesse est impressionnante : le GitHub consacré à Emscripten propose quelques démonstrations qui, si elles s'exécutent avec plus ou moins de bonheur d'un navigateur à l'autre, laissent miroiter la promesse du "write once, run anywhere".

Ainsi, Open-TTD, lui-même une version open-source du jeu Transport Tycoon, a pu être converti entièrement en JavaScript grâce à Emscripten, et est ainsi susceptible de fonctionner sur toute machine dotée d'un navigateur et d'un moteur JavaScript.



De même, il devient possible d'étendre les capacités des navigateurs sans même installer le moindre plugin, et en se contentant d'exploiter leur modularité native par le biais de JavaScript : cette démo permet d'afficher des images au format JPEG 2000, et cette autre rendra du PDF, sans même que le navigateur ne sache prendre en charge ce format. Un développeur a également porté son jeu écrit en C++ directement en JavaScript, prêt à fonctionner dans un navigateur, à l'aide d'Emscripten.

L'ajout de WebGL dans les navigateurs ouvre également à Emscripten l'accès de l'accélération matérielle (et du GPGPU, lire Lexique : si vous avez raté le début), et offre des perspectives enthousiasmantes.

Si Emscripten, dont le chantier a été entamé voilà deux ans, fait parfois plus œuvre de démonstration technique brillante que d'outil prêt à être exploité grandeur nature pour tout type de projet, il n'en souligne pas moins les avancées des moteurs JavaScript d'une part, et de l'autre l'excellente souplesse de LLVM, s'il fallait encore s'en convaincre.
avatar Imac7 | 

C'est génial ! Si ça développe bien, de nouvelles plateformes pour l'industrie du jeu vidéo ? Encore faudra avoir ce qui va avec, comme avec Onlive qui a fait un bide et nécessite une connexion adéquate...

avatar ovea | 

Ça semble indispensable cette démarche de réécriture de langage mais une fois le langage cible “universel” JavaScript désigné, existerait-il par hasard quelques démarches visant à introduire un tournant plus fonctionnel (sauce Scala) dans tout ce bouillon de langues un peu fadasse ?

avatar Psylo | 

Je critique souvent Macgé/igen/kernelpanic sur leur politique éditoriale ou quand ils pondent des articles d'une objectivité plus que douteuse, mais là je tire très bas mon plus beau chapeau pour la qualité exceptionnelle de cet article. Très intéréssant, très bien expliqué. Plus souvent ça. Merci.

avatar Macleone | 

Il faut arrêter de propager cette "Urban Legend" tenace selon laquelle le bitcode LLVM est intrinsèquement portable. Il y a eu de multiples discussions à ce sujet sur la liste LLVM et elles concluent toutes de la même façon.

C'est d'ailleurs pour cette raison que Google ne l'utilise pas comme bitcode pour NaCl, et qu'il leur faut un convertisseur NaCl qui s'exécute dans le plugin en fonction de l'architecture cible.

Il n'est pas, et ne sera jamais possible de compiler du code C/C++ standard de façon portable. Le langage n'étant pas à la base "architecture independant". La taille d'un entier et d'un pointeur varient d'une plateforme à l'autre. Plus important, l'alignement des variables et le padding des structure dépend de la platforme cible. Et je ne parle même pas de l'ABI C++.
Tout ça sans compter le preprocesseur, et sa capacité à choisir deux codes complètement différent en fonction de la machine cible.

Le Bitcode LLVM n'étant pas capable de représenter ces différences, il est impossible de convertir du code C/C++ en bitcode LLVM portable.

avatar ZeLegolas | 

Super news ! J'imagine l'équivalent d'un Framwork comme Qt tous en Javascript ! Alors si en plus on met ça sur un téléphone ou une tablette bonjour les dégâts ! Il va falloir qu'ils multiplient par 100 la puissance des téléphones et des tablettes, sans compter les Go de mémoire qu'on va devoir faire rentrer au forceps dans ces devices, pour qu'on puisse faire tous en Javascript.
Quoi qu'il en soit le concept reste intéressant... surtout pour ceux qui ne connaissent que Javascript :)

avatar unixorn | 

.net prend en charge le code natif via le mécanisme de P/Invoke.

Javascript comme plateforme d'exécution universelle, je n'y crois pas. Déjà parce que c'est très très lent même par rapport à Java / .net, ensuite parce que chaque interpréteur à ses spécificités (mais tout ça a été évoqué dans l'article).
Ensuite on remarque que même dans le mobile les projets à base de développement web se sont cassés la gueule (webos et compagnie) et que les applications natives (iPhone, Android NDK) ou managées (Windows Phone 7, Android SDK) règnent en maître.

avatar v1nce29 | 

> J'imagine l'équivalent d'un Framwork comme Qt tous en Javascript

Qt non. Mais pour gtk ça existe déjà. gtk 3.2 pourra tourner sur les navigateurs html5 et tourne déjà sur firefox.

avatar coink | 

Quoi de mieux pour illustrer cet article que Transport Tycoon !!!!

ne pas rechuter, ne pas rechuter, ne pas rechuter ... ;)

avatar ZeLegolas | 

@v1nce29
> Qt non. Mais pour gtk ça existe déjà. gtk 3.2 pourra tourner sur les navigateurs html5 et tourne déjà sur firefox.
Ça rame bien... je voulais dire ça marche bien ? :-D

avatar iljang | 

+1 avec Macleone, dans notre boite on avait une équipe "Unix Porting",
rien que son nom est évocateur . . .

et je n'ose même pas imaginer la tête du code javascript généré
à debugger, ça doit être sympa aussi !!!
comment se générer du travail ^^

CONNEXION UTILISATEUR