웹 개발 마조히스트를 위한 안내서

6 days ago 3

  • C/C++ 코드를 웹 브라우저 환경으로 이식하는 과정을 상세하게 소개함
  • Emscripten과 WebAssembly(WASM) 을 활용하여 네이티브에 가까운 성능을 웹에서 구현함
  • 프론트엔드의 최소한의 JavaScript/HTML 지식만으로 복잡한 C 코드 베이스를 웹으로 옮기는 실전 경험을 공유함
  • 멀티스레딩, 콜백 함수, 비동기 처리 등 난이도 높은 웹 개발 요소들을 C 개발자 관점에서 구체적으로 다룸
  • 실 활용 코드, 모듈화, 스레드 지원, 브라우저 스토리지 연동 등 실무에서 마주치는 복잡한 상황에 대한 해결법 제시함

소개

최근 Rubik’s Cube 최적해 알고리듬을 웹 앱으로 구현하는 프로젝트를 진행하였음.
이 과정에서 멀티스레딩, SIMD, 콜백 함수 등 다양한 C 기법으로 작성된 코드를 Emscripten을 통해 WebAssembly로 변환하고, 프론트엔드에는 최소한의 JavaScript/HTML만 사용함.
이 과정이 매우 복잡하고 피로도도 컸으나, 성공적으로 마무리하며 많은 경험과 지식을 얻게 되었음. 여기서는 C/C++ 개발자가 웹 환경으로 코드를 이식할 때 반드시 마주치는 세부적이고 복잡한 실전 팁을 공유함.
웹 개발을 처음 시작한다면 Mozilla Developer Network(MDN)의 튜토리얼을 먼저 참고하기를 권장함.
그러나 네이티브 성능과 웹 앱 이식성을 동시에 추구하는 C/C++ 개발자에게는 이 글이 실질적 도움을 줄 수 있음.

환경 구축

  • 모든 예시는 Git 저장소(https://github.com/sebastianotronto/emscripten-tutorial)에 포함됨
  • 준비물
    • 작동하는 Emscripten 설치 환경 (Node.js 포함)
    • 간단한 웹 서버(예: darkhttpd 또는 Python http.server)
  • 튜토리얼 코드 예제는 Linux 및 UNIX 계열에서 테스트되었음. Windows 사용자는 WSL(Windows Subsystem for Linux) 을 추천함

Hello World

  • 아래와 같은 간단한 C 코드가 Emscripten을 통해 웹 페이지로 실행됨
#include <stdio.h> int main() { printf("Hello, web!\n"); }
  • 다음 명령어로 컴파일 가능함
emcc -o index.html hello.c
  • 이 과정에서 index.html(웹 페이지), index.wasm(WebAssembly 바이트코드), index.js(JavaScript glue code) 세 파일이 생성됨
  • 브라우저나 Node.js에서 동작 가능하며, 각각의 환경에서 다른 활용법이 존재함
  • Emscripten에서 .wasm만 생성도 가능하지만, 대부분의 경우 JavaScript glue code가 필수적임

Intermezzo I: WebAssembly란?

  • WebAssembly(WASM) 은 웹 브라우저 내 고성능 가상 머신에서 실행되는 저수준 언어임
  • WASM은 2017년 이후 모든 주요 브라우저에서 지원됨
  • 원래 Emscripten은 C/C++ 코드를 asm.js라는 JavaScript 하위 집합으로 변환했으나, WASM의 등장으로 전환됨
  • 텍스트 표현식도 존재하며, 스택 기반 구조임. 최근까지 32비트 아키텍처만 지원해 4GB 이상의 메모리를 못 썼으나, WASM64가 점진적으로 브라우저에 도입되고 있음

라이브러리 빌드

  • C 함수 multiply() 를 WASM으로 빌드 후 JavaScript에서 호출하는 기본 예시 진행
  • 기본 빌드시 Emscripten은 함수 이름에 언더스코어(_) 를 붙임(예: _multiply)
  • 함수 외부 노출은 -sEXPORTED_FUNCTIONS 옵션 지정 필요함
  • 라이브러리 로딩 시 초기화가 비동기적이므로, onRuntimeInitialized나 await 등 비동기 처리 필요함
  • 실습 코드는 저장소 01_library 폴더에 있음

Intermezzo II: JavaScript와 DOM

  • JavaScript에서 HTML의 구성요소에 접근 및 수정하려면 Document Object Model(DOM) 을 활용해야 함
  • 이벤트 리스너(addEventListener) , 내장 연산자/함수 등으로 동적 UI 구현 가능
  • 예제를 위해 입력, 버튼, 결과 표시가 있는 기본적인 HTML/JavaScript 연동 구조 설명
  • script 분리/병합의 실전적 방법과 이슈(예: defer의 사용, DOM 요소 로드 순서)도 안내함

라이브러리 모듈화 및 로딩

  • WASM 라이브러리를 다중 포함하거나 Node.js/웹 양쪽에서 재사용하기 위해 MODULARIZE, EXPORT_NAME 옵션으로 모듈 형태로 빌드할 수 있음
  • .mjs (ES6 모듈) 확장자가 Node.js 호환성을 위해 추천됨
  • 웹/Node 양쪽에서 import MyLibrary from ... 식 모듈 사용 가능

멀티스레딩

  • WebAssembly에서 성능 강화를 위해 pthreads 기반 멀티스레드 코드 포팅 가능함
  • 함수 내 다수의 스레드를 생성해 병렬로 계산 작업(예: 소수 개수 세기) 을 실행함
  • 빌드시 -pthread, -sPTHREAD_POOL_SIZE=<n> 옵션 필요함
  • 실제 브라우저에서는 Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Embedder-Policy: require-corp와 같은 HTTP 헤더 추가 필요
  • 모든 예제는 저장소 03_threads 폴더에서 확인 가능함

Intermezzo III: Web Workers 및 Spectre

  • Emscripten 멀티스레드는 Web Workers로 구현됨(Web Workers는 별도의 프로세스이자 메시지 기반 통신 구조)
  • 공유 메모리(SharedArrayBuffer) 사용에는 보안 상의 제약이 존재
  • 2018년 Spectre 취약점 발생 후, 크로스 오리진 격리(cross-origin isolated) 요구사항 및 관련 헤더 필수화됨

메인 스레드 블로킹 주의

  • 긴 작업이 브라우저의 메인 UI 스레드를 BLOCK할 경우 사용자 경험이 급격히 저하됨
  • 이를 피하기 위해 웹 워커(Worker)를 도입: UI/입력 처리와 연산 처리를 명확히 분리
  • postMessage, onmessage로 메인-워커 간 이벤트 기반 통신 구현
  • 웹 워커 내에서 Emscripten-WASM 모듈을 불러 비동기 연산만 전담

콜백 함수

  • C 함수의 파라미터로 함수 포인터(콜백) 전달 시, 자바스크립트의 함수 객체와 자동 연동이 불가능함
  • Emscripten 제공 addFunction(), UTF8ToString() 등을 활용해야 하며, 빌드시 -sEXPORTED_RUNTIME_METHODS, -sALLOW_TABLE_GROWTH 옵션 추가 필요
  • 콜백은 반드시 메인 스레드에서만 호출되어야 안정적으로 동작함(웹 워커에서는 접근 불가)

영속적 스토리지

  • 사용자의 브라우저에 데이터를 영구 저장하기 위해 Emscripten의 IDBFS(IndexedDB 기반 파일 시스템) 를 사용함
  • 빌드시 --lidbfs.js 플래그와 --pre-js <JS파일> 등으로 초기 세팅 필요
  • C 코드에서는 파일 입출력 함수(fopen, fread, fwrite)를 그대로 사용할 수 있으나, 실제 데이터 반영/동기화 처리는 반드시 JavaScript에서 명시적 매핑 및 싱크 처리가 필요함
  • 브라우저의 Sandbox/보안 정책 특성상, 로컬 파일 시스템 직접 접근은 Node.js에서만 가능하며, 브라우저에서는 IDBFS와 같은 백엔드를 활용해야 안전하게 영구 데이터 저장 가능함

결론

  • 본 튜토리얼 전 과정을 통해 복잡한 네이티브 C/C++ 코드최소한의 JavaScript와 HTML만으로도 안전하고 성능 저하 없이 브라우저 상에서 실행할 수 있는 실질적인 방법을 자세히 배울 수 있음
  • 실전 환경에서 멀티스레드, 콜백, 비동기 처리, 스토리지 연동까지 모든 핵심 트랙의 난관/해결책을 경험하고, 관련 설정 및 브라우저 제약사항 등 최신 트렌드도 익힐 수 있음
  • 제공되는 Git 저장소 예제를 참고하여 자체 프로젝트에 적용 및 확장 가능함

Read Entire Article