Trabajo con WebAssembly y C++: de la A a la Z

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción a WebAssembly y C++

\n\n

El 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\n

En 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\n

1. Herramientas y configuración del entorno

\n\n

La 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\n

Instalación de Emscripten

\n

La forma recomendada de instalación es a través del gestor de paquetes emsdk:

\n\n
# 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\n

Después de la instalación, tendrá los comandos emcc (compilador) y em++ (compilador de C++), que son envoltorios sobre Clang.

\n\n

2. Compilación de C++ a WebAssembly

\n\n

Consideremos un ejemplo muy simple. Crearemos un archivo hello.cpp:

\n\n
#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\n

Un elemento importante es la macro EMSCRIPTEN_KEEPALIVE. Evita que el optimizador elimine la función y la hace exportable.

\n\n

Compilaremos nuestro código:

\n\n
em++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3
\n\n

Analicemos 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
\n\n

Como resultado, obtendremos tres archivos: hello.html, hello.js (glue code) y hello.wasm.

\n\n

3. Interacción con JavaScript

\n\n

Despué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\n

Puntos 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._malloc y punteros.
  • \n
\n\n

Paso de cadenas

\n

Ejemplo 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\n

En JavaS

Blogs

Book Recommendations