C и C++ в Wasm: Emscripten
Знакомимся с Emscripten — главным мостом из C/C++ в Wasm.
Emscripten — это тулчейн на базе LLVM, компилирующий C и C++ в WebAssembly вместе с эмуляцией привычного системного окружения.
Зачем нужен Emscripten
Огромный пласт быстрых библиотек написан на C и C++: видеокодеки, движки игр, физика, графика. Переписывать их на JS бессмысленно. Emscripten берёт существующий C/C++ код и компилирует в Wasm, причём так, чтобы он работал в браузере, где нет привычных файлов, потоков и системных вызовов. Это связь между огромной экосистемой C и вебом.
Простой пример на C
Возьмём функцию на C и пометим её для экспорта в Wasm. Исходник на C мы помечаем language-text — он не исполняется в браузерной песочнице, его компилируют тулчейном:
// add.c
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
Макрос EMSCRIPTEN_KEEPALIVE говорит компилятору не выбрасывать функцию при оптимизации и экспортировать её. Компилируем командой emcc:
emcc add.c -o add.js -s EXPORTED_RUNTIME_METHODS=ccall,cwrap
# создаст add.wasm + add.js (склейка для загрузки)
Что генерирует Emscripten
Помимо .wasm, Emscripten обычно создаёт JS-обёртку. Она грузит модуль, настраивает память и эмулирует системное окружение: виртуальную файловую систему, printf (через console.log), даже SDL/OpenGL поверх WebGL. Благодаря этому код, который раньше писал в файлы и рисовал в окно, начинает работать в браузере почти без изменений.
| В нативном C | Что делает Emscripten в вебе |
printf | выводит через console.log |
файлы (fopen) | виртуальная ФС в памяти / IndexedDB |
| SDL / OpenGL | рисует через Canvas / WebGL |
malloc/free | работа с линейной памятью |
Логика на JS для проверки
Чтобы убедиться, что наша C-функция считает верно, повторим её логику на JS — результат будет тот же, что и у скомпилированного Wasm:
function add(a, b) { return a + b; } // эквивалент C-функции
console.log("add(7, 8) =", add(7, 8));
console.log("add(-3, 10) =", add(-3, 10));
Вывод:
add(7, 8) = 7 + 8 = 15 add(-3, 10) = 7
Как работает под капотом
Emscripten использует LLVM: компилятор Clang переводит C/C++ в промежуточное представление LLVM IR, а затем бэкенд генерирует из него Wasm. Эмуляция окружения (libc, файлы, графика) — это библиотеки на JS и Wasm, которые Emscripten подмешивает к вашему коду. Поэтому простой printf("Hi") в браузере на самом деле вызывает цепочку: ваш код → эмулированный libc → импортированная JS-функция вывода → console.log.
Частые ошибки
- Функция «пропала» — без
EMSCRIPTEN_KEEPALIVEили списка экспортов оптимизатор удалит неиспользуемую функцию. - Ждать прямой работы с файлами диска — в браузере это виртуальная ФС, а не реальный диск.
- Огромный размер — эмуляция libc и графики тянет вес; для маленьких задач это избыточно.
Итоги
- Emscripten компилирует C/C++ в Wasm на базе LLVM/Clang.
- Он эмулирует системное окружение:
printf, файлы, SDL/OpenGL. - Команда
emccсоздаёт.wasmи JS-склейку. EMSCRIPTEN_KEEPALIVEсохраняет функцию от удаления оптимизатором.