| .. _Tutorial: |
| |
| =================== |
| Emscripten Tutorial |
| =================== |
| |
| **Using Emscripten is, at a base level, fairly simple. This tutorial takes you |
| through the steps needed to compile your first Emscripten examples from the |
| command line. It also shows how to work with files and set the main compiler |
| optimization flags.** |
| |
| First things first |
| ====================== |
| |
| Make sure you have :ref:`downloaded and installed <sdk-download-and-install>` |
| Emscripten (the exact approach for doing this will depend on your operating system: |
| Linux, Windows, or Mac). |
| |
| Emscripten is accessed using the :ref:`emccdoc`. This script invokes all the |
| other tools needed to build your code, and can act as a drop-in replacement for |
| a standard compiler like *gcc* or *clang*. It is called on the command line |
| using ``./emcc`` or ``./em++``. |
| |
| .. note:: On Windows the tool is called using the slightly different syntax: |
| ``emcc`` or ``em++``. The remainder of this tutorial uses the Linux approach |
| (``./emcc``). |
| |
| For the next section you will need to open a command prompt: |
| |
| - On Linux or macOS, open a *Terminal*. |
| - On Windows, open the :ref:`Emscripten Command Prompt <emcmdprompt>`, a command |
| prompt that has been pre-configured with the correct system paths and settings |
| to point to the :term:`active <Active Tool/SDK>` Emscripten tools. To access |
| this prompt, type **Emscripten** in the Windows start menu, and then |
| select the **Emscripten Command Prompt** option. |
| |
| Navigate with the command prompt to the emscripten directory under the SDK. This |
| is a folder below the :term:`emsdk root directory`, typically |
| **<emsdk root directory>/upstream/emscripten/**. |
| The examples below will depend on finding files relative to that location. |
| |
| .. note:: In older emscripten versions, the directory structure was different: |
| the version number appeared, and the backend (fastcomp/upstream) did not, so |
| you would use something like **<emsdk root directory>/emscripten/1.20.0/**. |
| |
| |
| Verifying Emscripten |
| ===================== |
| |
| If you haven't run Emscripten before, run it now with: :: |
| |
| ./emcc -v |
| |
| If the output contains warnings about missing tools, see |
| :ref:`verifying-the-emscripten-environment` for debugging help. Otherwise, |
| continue to the next sections where we'll build some code. |
| |
| |
| Running Emscripten |
| ================== |
| |
| You can now compile your first C/C++ file to JavaScript. |
| |
| First, let's have a look at the file to be compiled: **hello_world.c**. This is |
| the simplest test code in the SDK, and as you can see, all it does is print |
| "hello, world!" to the console and then exit. |
| |
| .. include:: ../../../../test/hello_world.c |
| :literal: |
| |
| |
| To build the JavaScript version of this code, simply specify the C/C++ file |
| after *emcc* (use *em++* to force compilation as C++): :: |
| |
| ./emcc test/hello_world.c |
| |
| |
| You should see two files generated by that command: **a.out.js** and |
| **a.out.wasm**. The second is a WebAssembly file containing the compiled code, |
| and the first is a JavaScript file containing the runtime support to load and |
| execute it. You can run them using :term:`node.js`: |
| |
| :: |
| |
| node a.out.js |
| |
| This prints "hello, world!" to the console, as expected. |
| |
| .. tip:: If an error occurs when calling *emcc*, run it with the ``-v`` option |
| to print out a lot of useful debug information. |
| |
| .. note:: In this section, and later on, we run some files from the ``test/`` |
| folder. That folder contains files for the Emscripten test suite. Some can be |
| run standalone, but others must be run through the test harness itself, see |
| :ref:`emscripten-test-suite` for more information. |
| |
| |
| |
| Generating HTML |
| =============== |
| |
| Emscripten can also generate HTML for testing embedded JavaScript. To generate |
| HTML, use the ``-o`` (:ref:`output <emcc-o-target>`) command and specify an html |
| file as the target file: :: |
| |
| ./emcc test/hello_world.c -o hello.html |
| |
| You can now open ``hello.html`` in a web browser. |
| |
| .. note:: Unfortunately, several browsers (including *Chrome* and *Safari*) do |
| not support ``file://`` :term:`XHR` requests, and can't load extra files |
| needed by the HTML (like a ``.wasm`` file, or packaged file data as mentioned |
| lower down). For these browsers, you'll need to serve the files using a |
| :ref:`local webserver <faq-local-webserver>` and then open |
| ``http://localhost:8000/hello.html``). |
| |
| Once you have the HTML loaded in your browser, you'll see a text area for |
| displaying the output of the ``printf()`` calls in the native code. |
| |
| The HTML output isn't limited just to just displaying text. You can also use the |
| SDL API to show a colored cube in a ``<canvas>`` element (on browsers that |
| support it). For an example, build the `hello_world_sdl.c |
| <https://github.com/emscripten-core/emscripten/blob/main/test/hello_world_sdl.c>`_ |
| test code and then refresh the browser: :: |
| |
| ./emcc test/hello_world_sdl.c -o hello.html |
| |
| The source code for the second example is given below: |
| |
| .. include:: ../../../../test/hello_world_sdl.c |
| :literal: |
| |
| |
| .. _tutorial-files: |
| |
| Using files |
| =========== |
| |
| .. note:: Your C/C++ code can access files using the normal libc stdio API |
| (``fopen``, ``fclose``, etc.) |
| |
| JavaScript is usually run in the sandboxed environment of a web browser, without |
| direct access to the local file system. Emscripten simulates a file system that |
| you can access from your compiled C/C++ code using the normal libc stdio API. |
| |
| Files that you want to access should be :ref:`preloaded <emcc-preload-file>` or |
| :ref:`embedded <emcc-embed-file>` into the virtual file system. Preloading (or |
| embedding) generates a virtual file system that corresponds to the file system |
| structure at *compile* time, *relative to the current directory*. |
| |
| |
| The `hello_world_file.cpp |
| <https://github.com/emscripten-core/emscripten/blob/main/test/hello_world_file.cpp>`_ |
| example shows how to load a file (both the test code and the file to be loaded |
| shown below): |
| |
| .. include:: ../../../../test/hello_world_file.cpp |
| :literal: |
| |
| .. include:: ../../../../test/hello_world_file.txt |
| :literal: |
| |
| .. note:: The example expects to be able to load a file located at **test/hello_world_file.txt**: :: |
| |
| FILE *file = fopen("test/hello_world_file.txt", "rb"); |
| |
| We compile the example from the directory "above" **test** to ensure the |
| virtual filesystem is created with the correct structure relative to the |
| compile-time directory. |
| |
| The following command is used to specify a data file to :ref:`preload |
| <emcc-preload-file>` into Emscripten's virtual file system — before running any |
| compiled code. This approach is useful because Browsers can only load data from |
| the network asynchronously (except in Web Workers) while a lot of native code |
| uses synchronous file system access. Preloading ensures that the asynchronous |
| download of data files is complete (and the file is available) before compiled |
| code has the opportunity to access the Emscripten file system. |
| |
| :: |
| |
| ./emcc test/hello_world_file.cpp -o hello.html --preload-file test/hello_world_file.txt |
| |
| |
| Run the above command, then open **hello.html** in a web browser to see the data |
| from **hello_world_file.txt** being displayed. |
| |
| For more information about working with the file system see the |
| :ref:`file-system-overview`, :ref:`Filesystem-API` and |
| :ref:`Synchronous-virtual-XHR-backed-file-system-usage`. |
| |
| |
| Optimizing code |
| =============== |
| |
| Emscripten, like *gcc* and *clang*, generates unoptimized code by default. You |
| can generate :ref:`slightly-optimized <emcc-O1>` code with the ``-O1`` command |
| line argument: :: |
| |
| ./emcc -O1 test/hello_world.cpp |
| |
| The "hello world" code created in **a.out.js** doesn't really need to be |
| optimized, so you won't see a difference in speed when compared to the |
| unoptimized version. |
| |
| However, you can compare the generated code to see the differences. ``-O1`` |
| applies several minor optimizations and removes some runtime assertions. For |
| example, ``printf`` will have been replaced by ``puts`` in the generated code. |
| |
| The optimizations provided by ``-O2`` (see :ref:`here <emcc-O2>`) are much more |
| aggressive. If you run the following command and inspect the generated code |
| (**a.out.js**) you will see that it looks very different: :: |
| |
| ./emcc -O2 test/hello_world.cpp |
| |
| For more information about compiler optimization options see |
| :ref:`Optimizing-Code` and the :ref:`emcc tool reference |
| <emcc-compiler-optimization-options>`. |
| |
| |
| .. _running-emscripten-tests: |
| |
| Emscripten Test Suite and Benchmarks |
| ==================================== |
| |
| Emscripten has a comprehensive test suite, which covers virtually all Emscripten |
| functionality. These tests are an excellent resource for developers as they |
| provide practical examples of most features, and are known to build successfully |
| on the ``main`` branch. |
| |
| See :ref:`emscripten-test-suite` for more information. |
| |
| |
| General tips and next steps |
| =========================== |
| |
| This tutorial walked you through your first steps in calling Emscripten from the |
| command line. There is, of course, far more you can do with the tool. Below are |
| other general tips for using Emscripten: |
| |
| - This site has lots more information about :ref:`compiling and building |
| projects <compiling-and-running-projects-index>`, :ref:`integrating your |
| native code with the web environment <integrating-porting-index>`, |
| :ref:`packaging your code <packaging-code-index>` and publishing. |
| - The Emscripten test suite is a great place to look for examples of how to use |
| Emscripten. For example, if you want to better understand how the *emcc* |
| ``--pre-js`` option works, search for ``--pre-js`` in the test suite: the test |
| suite is extensive and there are likely to be at least some examples. |
| - To learn how to use Emscripten in advanced ways, read :ref:`src/settings.js |
| <settings-js>` and :ref:`emcc <emccdoc>` which describe the compiler options, |
| and :ref:`emscripten-h` for details on JavaScript-specific C APIs that your |
| C/C++ programs can use when compiled with Emscripten. |
| - Read the :ref:`FAQ`. |
| - When in doubt, :ref:`get in touch <contact>`! |