Introducción a WebAssembly y C++
\n\nEl desarrollo web moderno busca constantemente formas de mejorar el rendimiento. WebAssembly (Wasm) es un formato de instrucciones binarias de bajo nivel que se ejecuta en el navegador a una velocidad cercana a la nativa. En combinación con C++, uno de los lenguajes de programación más rápidos y potentes, Wasm abre nuevos horizontes: desde juegos y simulaciones de alto rendimiento hasta complejos algoritmos de procesamiento de datos directamente en el navegador.
\n\nEn este artículo, recorreremos el camino desde lo básico hasta la aplicación práctica: analizaremos cómo compilar código C++ a WebAssembly, ejecutarlo en el navegador y optimizarlo para obtener el máximo rendimiento.
\n\n1. Herramientas y configuración del entorno
\n\nLa herramienta principal para compilar C++ a WebAssembly es el conjunto de compiladores Emscripten. Este traduce el bytecode de LLVM a Wasm y genera automáticamente el código de unión (glue code) de JavaScript necesario para cargar el módulo.
\n\nInstalación de Emscripten
\nLa forma recomendada de instalación es a través del gestor de paquetes emsdk:
# Clonamos el repositorio\ngit clone https://github.com/emscripten-core/emsdk.git\ncd emsdk\n\n# Instalamos y activamos la última versión\n./emsdk install latest\n./emsdk activate latest\n\n# Agregamos las variables de entorno (variables de shell)\nsource ./emsdk_env.sh\n\nDespués de la instalación, tendrá los comandos emcc (compilador) y em++ (compilador de C++), que son envoltorios sobre Clang.
2. Compilación de C++ a WebAssembly
\n\nConsideremos un ejemplo muy simple. Crearemos un archivo hello.cpp:
#include <emscripten/emscripten.h>\n\n// Función accesible desde JavaScript\nextern "C" {\n int EMSCRIPTEN_KEEPALIVE add(int a, int b) {\n return a + b;\n }\n}\n\nUn elemento importante es la macro EMSCRIPTEN_KEEPALIVE. Evita que el optimizador elimine la función y la hace exportable.
Compilaremos nuestro código:
\n\nem++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3\n\nAnalicemos las banderas:
\n- \n
-o hello.html— crea un archivo HTML con un ejemplo de ejecución. \n -s WASM=1— indica explícitamente la generación de Wasm (activado por defecto). \n -s EXPORTED_FUNCTIONS='["_add"]'— lista de funciones exportadas (con el prefijo_). \n -O3— alto nivel de optimización. \n
Como resultado, obtendremos tres archivos: hello.html, hello.js (glue code) y hello.wasm.
3. Interacción con JavaScript
\n\nDespués de la compilación, podemos llamar a nuestra función de C++ desde JavaScript. Aquí hay un código mínimo para cargar el módulo:
\n\n<!DOCTYPE html>\n<html>\n<head>\n <script>\n var Module = {};\n Module.onRuntimeInitialized = function() {\n // La función add ahora está disponible\n var result = Module._add(5, 7);\n console.log("Resultado: " + result); // 12\n };\n </script>\n <script src="hello.js"></script>\n</head>\n<body></body>\n</html>\n\nPuntos clave:
\n- \n
Module.onRuntimeInitialized— evento que se activa después de cargar el módulo Wasm. \n - Los nombres de las funciones en JS reciben el prefijo
_(por ejemplo,_add). \n - Para pasar estructuras de datos complejas (cadenas, arrays) se utilizan
Module._mallocy punteros. \n
Paso de cadenas
\nEjemplo de una función que devuelve un saludo:
\n\n// Código C++\nextern "C" {\n const char* EMSCRIPTEN_KEEPALIVE greet(const char* name) {\n static std::string msg = "Hola, " + std::string(name) + "!";\n return msg.c_str();\n }\n}\n\nEn JavaS