원글: https://tutorials.technology/tutorials/11-webassembly-initial-steps-tutorial.html

소개

웹어셈블리는 미래에 매우 유용하게 사용될 새롭고도 새로운 표준이다. 이 기술은 W3C 커뮤니티 그룹에서 애플, 구글 , 마이크로소프트 그리고 모질라와 함께 개발되고 있다. 이 프로젝트의 초기 시점인 지금은 고 수준의 언어가 아닌 C/C++로 초점이 맞춰져 있고 웹어셈블리의 약어는 wasm 이며 자바스크립트와 브라우저의 개선 사항 중 하나이다. 웹어셈블리는 자바스크립트를 대체하려는 목적이 아니며 사실 보완하려고 나왔다. 웹어셈블리를 사용하려면 크롬 카나리 버전이나 파이어폭스 나이틀리 버전을 설치해야 한다. 마이크로소프트의 엣지 프리뷰와 사파리도 곧 이 기술을 적용할 예정이다. 가장 큰 이점은 빠른 실행이지만 웹 프로그래밍이 더 이상 자바스크립트만으로 제한되지 않는다는 장점도 있다. 이 튜토리얼에서는 브라우저가 웹어셈블리를 실행할 수 있게 세팅하고 웹어셈블리를 컴파일할 수 있도록 필요한 도구들을 컴파일할 것이며 최종적으로 웹어셈블리가 printf를 수행하는 Hello world 예제를 만들어 볼 것이다.

자 시작해보자!

스텝 1: 데모를 확인할 브라우저를 설치한다.

현재 크롬 카나리는 리눅스를 지원하지 않으니 파이어폭스 나이틀리를 설치한다. 맥이나 윈도우 유저는 크롬 카나리를 이용할 것을 권장한다. 파이어폭스를 실행할 때는 절대 경로를 이용해서 실행해야 한다. 그렇지 않으면 인스톨 된 일반 파이어폭스가 실행된다.

cd
wget https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/firefox-53.0a1.en-US.linux-x86_64.tar.bz2
tar xf firefox-53.0a1.en-US.linux-i686.tar.bz2
cd firefox
./firefox

상태바를 확인해서 파이어폭스 나이틀리 버전이 실행되었는지 확인한다. 브라우저가 웹어셈블리를 사용할 수 있도록 설정한다.

  • 파이어폭스의 경우 주소창에 about:config 을 입력해 이동을 한다. 이동하게 되면 경고 얼럿이 뜨는데 수락해 주고 서치바에서 wasm을 입력하고 javascript.options.wasm 을 더블클릭해 값이 true가 되도록 바꾼다. 그리고 브라우저를 다시 시작한다.
  • 크롬 카나리의 경우 주소창에 chrome://flags 를 입력하고 Experimental WebAssembly 항목이 나올 때까지 스크롤하고 링크를 클릭해 활성화 한 뒤 브라우저를 재실행 한다.(역: 번역 시점 최신 버전인 카나리 59 버전에서는 별도의 설정을 안 해도 된다.)

여기에서 웹어셈블리의 데모를 확인할 수 있다.

스텝 2: 우분투의 요구 사항

우분투에서 binaryen 툴체인을 이용하려면 몇 가지 라이브러리를 컴파일해야 한다.

sudo apt-get install git cmake make ninja-build

웹어셈블리가 지원되는 LLVM을 빌드 하려면 최소한 3.4.4 버전 이상의 cmake가 필요하다. 하단에 부록 파트를 살펴보면 소스 코드를 이용해 cmake를 설치하는 방법을 찾을 수 있다.

스텝 3: 인프라스트럭처와 툴체인 컴파일

일단 LLVM이 웹어셈블리를 지원하도록 준비해야 한다. 만약 오래된 버전의 cmake를 사용하고 있다면 이 튜토리얼의 하단에 위치한 부록 파트를 확인한다.

git clone http://llvm.org/git/llvm.git
cd llvm/tools
git clone http://llvm.org/git/clang.git
cd ../projects
git clone http://llvm.org/git/compiler-rt.git
cd ..
mkdir build
cd build
cmake -G Ninja -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly ..
ninja
ninja install

만약 닌자가 메모리를 너무 많이 사용하는 경우 아래의 항목 살펴봐라(컴파일을 느리게 하는 원인들이다.)

  • 스왑 스페이스의 사용을 비활성화해 시스템이 멈추는것을 피한다 sudo swapoff -a
  • echo $MAKEFLAFS 의 내용을 확인해 얼마나 많은 프로세서가 컴파일할 때 사용되는지 확인한다. ninja -j1 을 이용하는 것을 추천한다.
  • 메모리를 적게 사용하는 골드 링커를 이용한다. 골드 링커를 이용하려면 id(id.bfd) 의 심벌릭 링크를 id.gold 로 변경한다.

id.bfg*를 *id.gold 로 변경하기 위해선 아래의 과정을 거친다.

ls -lah /usr/bin/ld # check which ld you are using
sudo rm /usr/bin/ld
sudo ln -s /usr/bin/ld.gold /usr/bin/ld
ls -lah /usr/bin/ld # check that you are using gold linker

스왑 스페이스를 다시 켜려면 sudo sudo swapon -a 를 입력한다. 그리고 이제 Binaryen 을 컴파일한다. Binaryen 는 최소 세 개의 필요한 바이너리들을 제공한다.

  • asm.js를 컴파일 하기 위한 asm2wasm
  • LLVM 웹어셈블리 백엔드 .s 아웃풋 파일을 컴파일 하기 위한 s2wasm
  • Rust MIR를 컴파일 하기 위한 mir2wasm
cd
git clone https://github.com/WebAssembly/binaryen
cd binaryen
cmake .
make

컴파일이 끝나면 bin 디렉터리에 필요한 실행파일들을 얻게 된다. 필요에 따라 sudo make install 을 수행할 수 있다. 마지막으로 WABT(The WebAssembly Binary Toolkit)을 아래의 순서에 따라 설치한다.

git clone https://github.com/WebAssembly/wabt.git
cd wabt
mkdir build
cd build
cmake -G Ninja -DBUILD_TESTS=OFF ..
ninja
sudo ninja install

스텝 4: HELLO WORLD 예제

웹어셈블리 Hello world 어플리케이션을 실행하려면 html 템플릿과 필요한 코드를 준비해야 한다. 아래의 hello_world 라는 새 디렉터리를 만들고 그 안에 아래의 html 코드를 index.html로 저장한다.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Hello world</title>
  <script>
     if ('WebAssembly' in window) {
        fetch('hello_world.wasm') // Fetch the binary
            .then(response => response.arrayBuffer())
            .then(buffer => WebAssembly.compile(buffer)) // Get a Module from the buffer
            .then(module => {
              // Get an Instance of the Module
              const instance = new WebAssembly.Instance(module);
              document.getElementById("btn").addEventListener("click", function() {
                      alert("count function result is : " + instance.exports.count());
                  }, false);
            });
      } else {
        output.value = "Your browser doesn't support Web Assembly. You may need " +
        "to enable it in your browser's flags.";
      }
  </script>
  </head>
<body>
  <input type="button" id="btn" value="Click me to execute hello world!" />
</body>
</html>

그리고 C를 이용해 출력해 보자, 아래의 내용을 hello_world.c로 저장한다.

int counter = 100;

int count() {
    return counter + 1;
}

이제 컴파일을 수행한다.

clang -emit-llvm --target=wasm32 -S hello_world.c
llc hello_world.ll -march=wasm32
s2wasm hello_world.s > hello_world.wast
wast2wasm -o hello_world.wasm hello_world.wast

스텝 5: 예제를 열어본다.

드디어 이번 단계에서 파이어폭스를 통해 예제 파일을 열어본다.

cd hello_world
python -m SimpleHTTPServer 8000

혹은 wasm-cli 를 이용해 wasm 파일만 테스트 해볼 수 있다.

npm install -g wasm-cli
wasm hello_world.wasm

http://localhost:8000 을 파이어폭스 주소창에 입력해 예제를 열어본다.

부록

Error libgtk-3.so.0: cannot open shared object file: No such file or directory

파이어폭스 53 버전을 실행하려 할때 아래의 에러를 만날 수 있다.

XPCOMGlueLoad error for file /home/parallels/firefox-32/libmozgtk.so:
libgtk-3.so.0: cannot open shared object file: No such file or directory
Couldn't load XPCOM.

이럴땐

locate libgtk-3.so.0

위와 같이 입력해 아래의 결과가 출력이 된다면

/usr/lib/x86_64-linux-gnu/libgtk-3.so.0
/usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1000.8

64비트 버전의 모질라 파이어폭스를 다운로드 해야한다.

Error: GDK_BACKEND does not match available displays

위와 같은 에러 메세지를 만나면 DISPLAY 환경 변수를 셋팅해야 한다.

export DISPLAY=:0.0

위의 내용을 .bashrc.zshrc 에 추가해 언제나 값이 설정되도록 한다.

Error: CMake 3.4.3 or higher is required. You are running version 3.2.2

이 에러를 해결하려면 cmake를 다운로드해 컴파일 해야한다.

wget https://cmake.org/files/v3.7/cmake-3.7.0.tar.gz
tar -xf cmake-3.7.0.tar.gz
cd cmake-3.7.0
./bootstrap
make
sudo make install

Error: Uncaught ReferenceError: Wasm is not defined

Wasm.instantiateModule() 대신 WebAssembly.instance() 를 사용한다.

Error: Uncaught Error: memory access out of bounds

이 이슈에 대해서 다시 업데이트할 예정이지만 이 문제는 간혹 s2wasm 을 사용할 때 –allocate-stack 옵션으로 해결이 될 때가 있다.

역자 부록(맥과 크롬 카나리 환경을 위한 팁)

  • 스텝 3의 첫번째, LLVM을 설치하기 전에 ninja-build를 설치해야 한다.
brew install ninja
  • LLVM은 다운로드하고 컴파일 하는 과정이 정말 오래 걸린다.
  • 역자의 경우 스텝 3의 첫번째 LLVM 설치하는 부분에서 ninja installsudo ninja install 로 권한을 주고 설치해야 했다.
  • binaryen 을 make 로 빌드한뒤 sudo make install 로 인스톨 해야 툴들의 경로가 제대로 잡힌다.