이 번역은 완료되지 않았습니다. 이 문서를 번역해 주세요.

당신이 C/C++같은 언어로 새로운 모듈을 작성하고 있다면, 당신은 Emscripten같은 툴을 이용하여서 WebAssembly로 컴파일 할 수 있습니다. 이것이 어떻게 가능한지 봅시다!

Emscripten Environment Setup

처음으로, 필요한 개발 환경을 설정해 봅시다.

Prerequisites

당신의 컴퓨터에 설치가 필요한 필수 사항들이 있습니다. 아래의 환경 설정을 먼저 합시다.

  • Git —  Linux 와 OS X는 이미 설정되어 있을 것입니다.  Windows  에서는 Git for Windows installer을 다운받아 설정하세요.
  • CMake — Linux 와OS X 에서는 apt-get 같은 패키지매니저를 이용하여 설치하거나 brew 를 통해 dependencies(의존성)이나 path들이 제대로 관리되고 있는지 확인하세요.  Windows라면  CMake installer를 사용하여 설치하세요.
  • Host system compiler — Linux에서는, install GCC (GCC)를 설치하세요. OS X에서는 Xcode를 설치하세요. install Xcode. Windows에서는  Visual Studio Community 2015 with Update 3 or newer 를 설치하세요. 최근 릴리즈된 VS2017에서는 동작하지 않는 것을 유의하세요. — 아직 Emscripten을 지원하지 않습니다.
  • Python 2.7.x — Linux 와 OS X 에서는,  대부분 특별한 설치없이도 지원됩니다. 사용법 관련하여 this Beginners guide 참조해주세요. Windows에서는,  Python homepage에서 인스톨러를 받으세요.

Note: 윈도우 에서는  pywin32 필요할 수도 있습니다. pywin32 설치하는 동안 에러를 줄이기 위해서, 관리자 권한으로 실행된 CMD에서 인스톨러를 실행해주세요.

Compiling Emscripten

다음으로, 소스에서 Emscripten을 컴파일합니다.  아래의 커맨드들을 자동화 할 수 있도록Emscripten SDK를 통해 실행하세요(Emscripten을 저장하려는 부모 디렉토리에서 실행하세요)

git clone https://github.com/juj/emsdk.git
cd emsdk

# on Linux or Mac OS X
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

# on Windows
emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

The install step can take a while, so now is a good time to go and get a cup of tea. The install step sets up all the environment variables, etc., needed to run Emscripten.

Note: The --global flag causes the required PATH variables to be set globally, so this and all future terminal/command prompt windows will have them set. If you want to just activate Emscripten for the current window, omit this flag.

Note: It's a good idea to pull the latest emscripten code (run git pull inside the emsdk directory) and then rerun the install and activate commands shown each time you intend to use Emscripten, to make sure you have the latest features.

Now from inside the emsdk directory, enter the following command to enter an Emscripten compiler environment from which you can compile C examples to asm.js/wasm:

# on Linux or Mac OS X
source ./emsdk_env.sh

# on Windows
emsdk_env.bat

Compiling an example

With the environment set up, let's look at how to use it to compile a C example to Emscripten. There are a number of options available when compiling with Emscripten, but the main two scenarios we'll cover are:

  • Compiling to wasm and creating HTML to run our code in, plus all the JavaScript "glue" code needed to run the wasm in the web environment.
  • Compiling to wasm and just creating the JavaScript.

We will look at both below.

Creating HTML and JavaScript

This is the simplest case we'll look at, whereby you get emscripten to generate everything you need to run your code, as WebAssembly, in the browser.

  1. First we need an example to compile. Take a copy of the following simple C example, and save it in a file called hello.c in a new directory on your local drive:
    #include <stdio.h>
    
    int main(int argc, char ** argv) {
      printf("Hello World\n");
    }
  2. Now, using the terminal window you used to enter the Emscripten compiler environment, navigate to the same directory as your hello.c file, and run the following command:
    emcc hello.c -s WASM=1 -o hello.html

The options we’ve passed in with the command are as follows:

  • -s WASM=1 — Specifies that we want wasm output. If we don’t specify this, Emscripten will just output asm.js, as it does by default.
  • -o hello.html — Specifies that we want Emscripten to generate an HTML page to run our code in (and a filename to use), as well as the wasm module and the JavaScript "glue" code to compile and instantiate the wasm so it can be used in the web environment.

At this point in your source directory you should have:

  • The binary wasm module code (hello.wasm)
  • A JavaScript file containing glue code to translate between the native C functions, and JavaScript/wasm (hello.js)
  • An HTML file to load, compile, and instantiate your wasm code, and display its output in the browser (hello.html)

Running your example

Now all that remains is for you to load the resulting hello.html in a browser that supports WebAssembly. It is enabled by default in Firefox 52+ and Chrome 57+/latest Opera (you can also run wasm code in Firefox 47+ by enabling the javascript.options.wasm flag in about:config, or Chrome (51+) and Opera (38+) by going to chrome://flags and enabling the Experimental WebAssembly flag.)

If everything has worked as planned, you should see "Hello world" output in the Emscripten console appearing on the web page, and your browser’s JavaScript console. Congratulations, you’ve just compiled C to WebAssembly and run it in your browser!

Using a custom HTML template

Sometimes you will want to use a custom HTML template. Let's look at how we can do this.

  1. First of all, save the following C code in a file called hello2.c, in a new directory:

    #include <stdio.h>
    
    int main(int argc, char ** argv) {
        printf("Hello World\n");
    
    }
  2. Search for the file shell_minimal.html in your emsdk repo. Copy it into a sub-directory called html_template inside your previous new directory.

  3. Now navigate into your new directory (again, in your Emscripten compiler environment terminal window), and run the following command:

    emcc -o hello2.html hello2.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html

    The options we've passed are slightly different this time:

    • We've specified -o hello2.html, meaning that the compiler will still output the JavaScript glue code and .html.
    • We've also specified --shell-file html_template/shell_minimal.html — this provides the path to the HTML template you want to use to create the HTML you will run your example through.
  4. Now let's run this example. The above command will have generated hello2.html, which will have much the same content as the template with some glue code added into load the generated wasm, run it, etc. Open it in your browser and you'll see much the same output as the last example.

Note: You could specify outputting just JavaScript rather than the full HTML by specifying a .js file instead of an HTML file in the -o flag, e.g. emcc -o hello2.js hello2.c -O3 -s WASM=1. You could then build your custom HTML complete from scratch. This isn't recommended however — Emscripten requires a large variety of JavaScript "glue" code to handle memory allocation, memory leaks, and a host of other problems, which is already included in the provided template. It is easier to use that than having to write it all out yourself, although as you become more experienced at what it all does, you'll be able to create your own customized versions for your needs.

Calling a custom function defined in C

If you have a function defined in your C code that you want to call as needed from JavaScript, you can do this using the Emscripten ccall() function, and the EMSCRIPTEN_KEEPALIVE declaration (which adds your functions to the exported functions list (see Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?)). Let's look at how this works.

  1. To start with, save the following code as hello3.c in a new directory:

    #include <stdio.h>
    #include <emscripten/emscripten.h>
    
    int main(int argc, char ** argv) {
        printf("Hello World\n");
    }
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) {
      printf("MyFunction Called\n");
    }
    
    #ifdef __cplusplus
    }
    #endif

    By default, Emscripten-generated code always just calls the main() function, and other functions are eliminated as dead code. Putting EMSCRIPTEN_KEEPALIVE before a function name stops this from happening. You also need to import the emscripten.h library to use EMSCRIPTEN_KEEPALIVE.

    Note: We are including the #ifdef blocks so that if you are trying to include this in C++ code, the example will still work. Due to C versus C++ name mangling rules, this would otherwise break, but here we are setting it so that it treats it as an external C function if you are using C++.

  2. Now add html_template/shell_minimal.html into this new directory too, just for convenience (you'd obviously put this in a central place in your real dev environment).

  3. Now let's run the compilation step again. From inside your latest directory (and while inside your Emscripten compiler environment terminal window), compile your C code with the following command. (Note that we need to compile with NO_EXIT_RUNTIME, which is necessary as otherwise when main() exits the runtime would be shut down - necessary for proper C emulation, e.g., atexits are called - and it wouldn't be valid to call compiled code.)

    emcc -o hello3.html hello3.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1  -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall"]'
  4. If you load the example in your browser again, you'll see the same thing as before!

  5. Now we need to run our new myFunction() function from JavaScript. First of all, let's add a <button> as shown below, just above the first opening <script type='text/javascript'> tag.

    <button class="mybutton">Run myFunction</button>
  6. Now add the following code inside the last <script> element (just above the closing </script> tag):

    document.querySelector('.mybutton').addEventListener('click', function(){
      alert('check console');
      var result = Module.ccall('myFunction', // name of C function 
                                 null, // return type
                                 null, // argument types
                                 null); // arguments
    });

This illustrates how ccall() is used to call the exported function.

See also

문서 태그 및 공헌자

이 페이지의 공헌자: nakyong
최종 변경자: nakyong,