C++을 웹에서 사용하기

2018-07-21, Sat

옛날에 서핑하다가 emscripten이란걸 본 적이 있다. llvm을 사용해서 여러 언어(C++ 포함)를 JS로 바꿀 수 있다는 것이었는데 그때는 와 신기하다 하고 그냥 끝냈었다.

요즘 다시 웹으로 뭔가를 굴려볼까 하다가 JS는 내 체질이 아닌거 같아서 포기하던 중에 다시 이게 떠올라 잠시 건드려 봤다.
emscripten에 기본으로 제공되는 emrun 같은 도구를 사용해봤지만 알아서 루프되는? 식으로 작동해서 내 취향은 아닌 것으로.. 직접 밑에서부터 만드는게 내 성향이다.
macOS 10.13.6 기준으로 실행했고 필요한 것들은 전부 brew로 설치된다.

#include <numeric>
#include <vector>

int funooc(void)
{
	std::vector<int> A(10);
	std::iota(A.begin(), A.end(), 12);

	return std::accumulate(A.begin(), A.end(), 0);
}

벡터에 12부터 21까지 값을 채운 뒤 합을 반환하는 함수이다.

컴파일은 아래와 같이 한다.

em++ -s "EXPORTED_FUNCTIONS=['__Z6funoocv']"

__Z6funoocv는 함수 이름인 funooc가 mangle된 이름이다. C++에서는 저런 식으로 복잡하게 되고 만약 C 컴파일러로 컴파일해주거나 extern "C"로 써준다면 _funooc처럼 이름 앞에 _가 붙는 형태로 된다.
로컬에서 서버를 열지 않고 테스트하고 싶다면 -s WASM=0 명령을 추가로 주어 wasm(web assembly)파일을 따로 만들지 않을 수 있다. 로컬에서 테스트할 때 wasm파일이 따로 있으면 CORS 때문에 정상적으로 작동하지 않는다.(wasm 파일을 fetch로 가져오는데, 그 과정에서 막힌다.) wasm파일을 만들면서 테스트하고 싶다면 python3 -m http.server 8080같은 식으로 간단히 서버를 열어서 테스트해볼 수 있다. 나름 최신 기술인데 현 시점에서 사파리, 크롬, ios 사파리에서 전부 잘 작동하는걸 보면 호환성 이슈는 딱히 없어보인다.

Emscripten에서 이 부분에 대한 더 자세한 정보는 emscripten FAQ참조.
Name mangling에 대한 간단한 설명은 여기에 있고, C++(clang)에서 mangle된 이름을 알아내는 법은 여기에 있다.

위와 같이 컴파일한 경우 HTML/JS에서 __Z6funoocv() 이런 식으로 불러와 사용할 수 있다.

Original
Content

요렇게.

C++ 과 JS 사이 값을 전달할 수 있는 방법이 여러 가지 있는데 int나 double은 그냥 넘기면 넘어가고, STL이 들어가는 값들은 bind로 하는게 편하다.