Cómo compilar C y C++ en WebAssembly con Emscripten

Funciones web: WebAssembly

Usa Emscripten para compilar C y C++ en módulos de WebAssembly (Wasm) de alto rendimiento para el navegador.

1. Marcas de compilación modernas de Emscripten

Cuando compiles y vincules con emcc o em++, usa siempre marcas modulares modernas:

  • -sEXPORT_ES6: Emite la sintaxis estándar del módulo ES6 (import/export) en lugar de los objetos globales heredados. Esto establece -sMODULARIZE de forma automática.
  • -sENVIRONMENT=web: Quita el código del entorno de ejecución de Node.js o de shell para minimizar el tamaño del paquete.
  • -sSTRICT: Aplica los valores predeterminados modernos de Emscripten y falla en las marcas obsoletas.
  • -sALLOW_MEMORY_GROWTH: Permite que el montón de memoria lineal de WebAssembly se expanda de forma dinámica cuando se asigna memoria.
  • -Oz (o -O3) + -flto: Optimiza el tamaño mínimo de la carga útil en las compilaciones de lanzamiento.

2. Evita bloquear el subproceso principal

Si es probable que una llamada a WebAssembly tarde una cantidad de tiempo significativa (es decir, más de unos milisegundos), no se debe llamar en el subproceso principal del navegador.

Para evitar ejecutar ese código en el subproceso principal del navegador, existen varios enfoques posibles:

  1. Ejecuta todo el programa de WebAssembly en un Web Worker. Esta suele ser la solución más sencilla, ya que no implica configurar el acceso a SharedArrayBuffer ni cambiar la fuente del programa.

  2. Usa pthreads o Wasm Workers. Esto permite que el trabajo se comparta entre muchos trabajadores, pero requiere acceso a SharedArrayBuffer, lo que puede implicar agregar encabezados HTTP COOP/COEP.

  3. Refactoriza el código C/C++ para evitar llamadas de larga duración. Por ejemplo, dividir el trabajo en partes pequeñas que se puedan llamar desde requestIdleCallback.

3. Presta atención a las advertencias y los errores del entorno de ejecución

Asegúrate de probar el programa WebAssembly resultante y de que no se generen advertencias ni errores en la consola.

Compila y ejecuta los programas con -sASSERTIONS habilitado y corrige cualquier falla de tiempo de ejecución que se produzca.

4. Evita la vinculación dinámica si es posible

Emscripten funciona mejor con bibliotecas estáticas (.a). Las bibliotecas compartidas (.so, .dylib, .dll) son menos útiles en la implementación del navegador y pueden complicar las cosas de forma innecesaria.

5. Cómo portar bibliotecas de C/C++ existentes

Cuando integres bibliotecas de C/C++ existentes con sistemas de compilación estándar, ten en cuenta lo siguiente:

Proyectos de CMake

Une los comandos de CMake con emcmake y emmake:

mkdir build && cd build
emcmake cmake .. -DCMAKE_BUILD_TYPE=Release
emmake make

Proyectos de Autoconf/Make

Usa emconfigure para establecer los destinos de la cadena de herramientas de compilación cruzada:

emconfigure ./configure --host=wasm32-unknown-emscripten --disable-shared
emmake make