This chapter describes how to compile a Native Client module (that is, a .nexe file).
This chapter is intended for developers who have experience writing, compiling, and linking C and C++ code.
To compile a Native Client module, you must use the Native Client versions of the GNU tools. These versions use a variety of techniques to ensure that your .nexe doesn't violate Native Client's security constraints.
Note: In the future, additional tools will be available to compile Native Client modules written in other programming languages, such as C#. But this document covers only compiling C and C++ code, using the modified GNU toolchain provided with the SDK.
The tools are located in toolchain/platform/bin, where platform is the platform on which you are developing (either linux_x86, mac_x86, or win_x86). For example, the tools in the Macintosh version of the SDK are in toolchain/mac_x86/bin.
The SDK includes the following tools:
The bin directory contains two versions of each tool – one to compile Native Client modules for the x86-32 platform, and one to
compile modules for the x86-64 platform. (For additional information about target architectures, see the section immediately below.) Each
tool's name is preceded by "i686-nacl-" for the version used to compile for the x86-32 platform, and by "x86_64-nacl-" for the version used
to compile for the x86-64 platform (these prefixes conform to gcc naming standards and make it easier to use tools like autoconf).
For example, you can use i686-nacl-gcc to compile .nexe files for the x86-32 platform, and x86_64-nacl-gcc to compile .nexe files for the
x86-64 platform. Note that you can typically override a tool's default target architecture with command line flags, e.g., you can specify
x86_64-nacl-gcc -m32 ... to compile a .nexe for the x86-32 architecture.
As explained in the Technical Overview, Native Client modules are operating-system-independent, not processor-independent. Therefore, you must compile separate versions of your Native Client module for different processors on end-user machines, such as x86-32 and x86-64. The table below lists which .nexe modules run on which target architectures:
|End-user OS/architecture||... can only run these .nexe modules|
|Windows 32-bit||32-bit .nexe modules|
|Windows 64-bit||64-bit .nexe modules|
|Mac||32-bit .nexe modules|
|Linux 32-bit||32-bit .nexe modules|
|Linux 64-bit||both 32-bit and 64-bit .nexe modules, but only if matched with 32-bit or 64-bit Chrome, respectively|
In general, you'll want to compile your modules for both 32-bit and 64-bit target architectures, and create a
that specifies which version of your module to load based on the end-user's architecture. The SDK includes a custom SCons Builder
to generate manifest files (see the function
GenerateNmf() in build_tools/nacl_sdk_scons/nacl_utils.py). For an example of
how to compile modules for multiple architectures and generate manifest files, see the commands that are executed by the SCons build tool
for any of the examples in the SDK.
How to compile
To create a .nexe file, run the Native Client version of the appropriate compiler.
For example, to compile the x86-32 version of hello_world (on any of the supported platforms), you could use this series of command lines:
i686-nacl-g++ -o opt_x86_32/hello_world.o -Wall -c -Wno-long-long -pthread -O2 -m32 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/include -I ~/src/native_client_sdk_0_4_894 \ hello_world.cc i686-nacl-g++ -o opt_x86_32/helper_functions.o -Wall -c -Wno-long-long -pthread -O2 -m32 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/include -I ~/src/native_client_sdk_0_4_894 \ helper_functions.cc i686-nacl-g++ -o hello_world_x86_32.nexe -melf_nacl -m32 \ opt_x86_32/hello_world.o opt_x86_32/helper_functions.o -lppapi -lppapi_cpp
When you're compiling, be sure to link the libraries in the order shown above. For more information about the libraries, see Libraries and header files provided with the SDK.
Compiling the x86-64 version is the same, except that you use
-m64 instead of
x86_64-nacl-g++ -o opt_x86_64/hello_world.o -Wall -c -Wno-long-long -pthread -O2 -m64 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/nacl64/include -I ~/src/native_client_sdk_0_4_894 \ hello_world.cc x86_64-nacl-g++ -o opt_x86_64/helper_functions.o -Wall -c -Wno-long-long -pthread -O2 -m64 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/nacl64/include -I ~/src/native_client_sdk_0_4_894 \ helper_functions.cc x86_64-nacl-g++ -o hello_world_x86_64.nexe -melf64_nacl -m64 \ opt_x86_64/hello_world.o opt_x86_64/helper_functions.o -lppapi -lppapi_cpp
The executable module is always named with the filename extension .nexe, regardless of what platform you're using.
Note: To see how the example Native Client modules in the SDK are compiled, run
../scons from any of
the example subdirectories (e.g., examples/hello_world). On Windows, run
..\scons.bat. The SCons build tool displays the
command it executes for each step of the build process. You may have to run
../scons -c first to clean (delete) previously
compiled files, so that SCons won't skip any steps. The compile commands executed by SCons are slightly different than the commands shown
above; in particular they include optional flags to turn on various compiler warnings, and canonical paths to the include file
For more information about command-line options, see the options summary for the GNU tools, especially gcc.
The SDK includes the following SCons-related files:
- Shell driver script that executes the
sconscommand. On Windows this script is named
- SCons configuration files that contain the build rules; these are the equivalent of Makefiles. There is a
build.sconsfile in each of the example subdirectories (e.g., examples/hello_world/build.scons). There is also a
build.sconsfile in the top-level examples directory, which you can use to build all the examples.
- Script that creates a SCons construction environment that uses the Native Client toolchain instead of the platform-native toolchain (e.g., nacl-g++ instead of g++). This script also sets variables like CCFLAGS and CPPPATH with base options used to compile .nexes.
- Script that appends options to CCFLAGS for debug and optimized build variants, and that extends the SCons construction environment with NaCl-specific builders.
There are a number of additional SDK-specific SCons utilities in the nacl_sdk_scons directory.
Note: You must have Python installed in order to use SCons. See the Download page for instructions on installing Python.
To build the examples in the SDK, go to any of the example subdirectories and run the SCons driver script:
cd examples/hello_world ../scons
Note the "../" before the
scons command. On Windows, run
If you don't specify any arguments, the SCons driver script and configuration files for the examples will execute the following actions:
- build optimized versions of a .nexe for both 32- and 64-bit architectures (e.g., hello_world_x86_32.nexe and hello_world_x86_64.nexe)
- build debug versions of a .nexe for both 32- and 64-bit architectures (e.g., hello_world_x86_32_dbg.nexe and hello_world_x86_64_dbg.nexe)
- generate optizimized and debug versions of a manifest file to load either the optimized or debug .nexes (e.g., hello_world.nmf and hello_world_dbg.nmf)
- build test versions of a .nexe for both 32- and 64-bit architectures
(e.g., hello_world_test_x86_32_test32.nexe and hello_world_test_x86_64_test64.nexe); you can use
nacl-sel_ldr(described below) to load and run these .nexe files from the command line
Here are a few additional SCons commands:
- To build a specific target, run scons and specify that target on the command line, e.g.,
- To build all of the examples in the SDK, go to the examples directory and run
- To delete a specific target and its build artifacts, use the
../scons -c hello_world_x86_32.nexe.
- To delete all previously compiled files and build artifacts, run
../scons -cwithout any targets. This is equivalent to
- To add a compile flag for your project, append the flag to the appropriate variable in your project's build.scons file. For example,
to compile with the
‑Werrorflag, add the following line to build.scons:
nacl_env.Append(CCFLAGS=['-Werror'])The call to the Append() method typically goes right after the
nacl_envvariable is created, near the top of the build.scons file. For an example of how to add compile flags, see the SCons configuration file for the hello_world example in the SDK (examples/hello_world/build.scons).
- To add an include directory for your project, make sure your project's build.scons file includes the line
import os" near the top, and then, to add a path like path/to/include, add the following line to build.scons:
nacl_env.Append(CPPPATH=[os.path.join('path', 'to', 'include')The call to the Append() method typically goes right after the
nacl_envvariable is created, near the top of the build.scons file. See examples/hello_world/build.scons for an example.
- To see a list of SCons options, run
If you use the Python script
init_project.py to set up template files for a project, the project directory will include
both the scons driver script and the build.scons configuration file for your project. To build your project simply run
in the project directory. For additional information on setting up a project see the description of
project template files in the C++ Tutorial.
Libraries and header files provided with the SDK
The Native Client SDK includes modified versions of standard toolchain-support libraries, such as iberty, nosys, pthread, and valgrind, plus the relevant header files.
The libraries are located in toolchain/platform/x86_64-nacl/lib32 (x86-32) and toolchain/platform/x86_64-nacl/lib64 (x86-64). For example, the x86-64 libraries in the Macintosh version of the SDK are in toolchain/mac_x86/x86_64-nacl/lib64.
The standard gcc libraries are also available, in toolchain/platform/lib.
The header files are in toolchain/platform/x86_64-nacl/include.
Note: The Native Client toolchain has its own default library and header search paths. Thus if you use a specific third-party library in your non-Native-Client development, the Native Client tools won't find that library. If you want to use the library for Native Client development, then look for it in naclports, or port it yourself.
The toolchain intentionally leaves out some standard libraries and header files; in particular, for sandboxing reasons, the SDK doesn't
support some POSIX-specified items. For example,
open(2) isn't included, and
close(2) doesn't precisely match the
Many other libraries have been ported for use with Native Client; for more information, see the naclports project. If you port an open-source library for your own use, we recommend adding it to naclports.
Here are descriptions of some of the Native Client-specific libraries provided in the SDK:
- Is used to implement Native Client logging and some other features in nacl_platform.
- Implementations of the intermodule communications layer (IMC), which is used to implement SRPC, the Native Client RPC library.
- Provides some platform abstractions, and is used to implement some other Native Client libraries.
- Implementation of the Pepper (PPAPI) C++ interface.
- Implementation of the Pepper (PPAPI) C interface; needed for all applications that use Pepper.
- Implementation of the Native Client pthread interface.
- Implementation of the Native Client RPC layer, and is used to implement the Pepper C layer.
Use of a debugger is not yet supported in Native Client. We're actively working on better debugging support.
However, there are some alternative approaches to debugging that expert gdb users may be able to use.
You can also use various environment variables to output logging information. In particular, setting the
NACL_PLUGIN_DEBUG=1 environment variables before starting the browser will give you
a lot of logging information from the browser on Linux or Macintosh (those variables have no effect on Windows). Setting the
NACL_SRPC_DEBUG=1 environment variable provides a huge amount of output.
Also, you may be able to use
printf() to display information.
If you want to compile a debug version of a module, retaining symbol information, you can use the standard
i686-nacl-g++ -o opt_x86_32/hello_world.o -Wall -c -Wno-long-long -pthread -g -m32 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/include -I ~/src/native_client_sdk_0_4_894 \ hello_world.cc i686-nacl-g++ -o opt_x86_32/helper_functions.o -Wall -c -Wno-long-long -pthread -g -m32 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/include -I ~/src/native_client_sdk_0_4_894 \ helper_functions.cc i686-nacl-g++ -o hello_world_x86_32.nexe -melf_nacl -m32 \ opt_x86_32/hello_world.o opt_x86_32/helper_functions.o -lppapi -lppapi_cpp
Or for x86-64 debug versions:
x86_64-nacl-g++ -o opt_x86_64/hello_world.o -Wall -c -Wno-long-long -pthread -g -m64 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/nacl64/include -I ~/src/native_client_sdk_0_4_894 \ hello_world.cc x86_64-nacl-g++ -o opt_x86_64/helper_functions.o -Wall -c -Wno-long-long -pthread -g -m64 \ -I ~/src/native_client_sdk_0_4_894/toolchain/linux_x86/nacl64/include -I ~/src/native_client_sdk_0_4_894 \ helper_functions.cc x86_64-nacl-g++ -o hello_world_x86_64.nexe -melf64_nacl -m64 \ opt_x86_64/hello_world.o opt_x86_64/helper_functions.o -lppapi -lppapi_cpp
The SDK includes two tools to help you test .nexe modules:
sel_ldr_x86_32(if your development machine is an x86-32 machine)
sel_ldr_x86_64(if your development machine is an x86-64 machine)
These tools are located in toolchain/platform/bin, where platform is the platform on which you are developing (either linux_x86, mac_x86, or win_x86). You can use ncval to verify that a module meets Native Client's security constraints (address alignment, no restricted instructions, etc.). You can use sel_ldr to load and run a module from the command line. For an example of a unit test that you can run with sel_ldr, see examples/hello_world/test_helper_functions.cc.
Reducing code size
When you're ready to release, you'll probably want to make your .nexe file as small as possible, to improve download speed.
To reduce the size of your final .nexe files, compile your modules with the standard
-O2 flag, and then use the
x86_64-nacl-strip hello_world_x86_32.nexe -o hello_world_x86_32.nexe x86_64-nacl-strip hello_world_x86_64.nexe -o hello_world_x86_64.nexe
nacl-strip is based on the standard
strip utility; for information on how to use it, see the man page for
-Os flag (to optimize for size without loss of speed) has not been thoroughly tested.
The example SCons configuration files use the
-O2 flag. If you run into problems with optimization options, please
file a bug.
Some common problems, and how to fix them:
- SCons commands don't work
- Be sure to have Python installed (see the Download page for instructions), and to invoke the SCons driver script from the appropriate directory.
- "Undefined reference" errors
An "undefined reference" error may indicate incorrect link order and/or missing libraries. For example, if you leave out
-lppapiwhen compiling the hello_world example, you'll see a series of undefined reference errors.
One common type of "undefined reference" error is with respect to certain system calls, e.g., "undefined reference to 'mkdir'". For security reasons, Native Client does not support a number of system calls. Depending on how your code uses such system calls, you have a few options:
- Link with the
-lnosysflag to provide empty/always-fail versions of unsupported system calls. This will at least get you past the link stage.
- Find and remove use of the unsupported system calls.
- Create your own implementation of the unsupported system calls to do something useful for your application.
If your code uses
mkdiror other file system calls, you might find nacl-mounts useful. Nacl-mounts essentially does option 3 for you: It lets your code use POSIX-like file system calls, and implements the calls using various technologies (e.g., App Engine or an in-memory filesystem).
- Link with the
- Module doesn't load in browser
- There can be various reasons for this problem:
- You must use Chrome 14 or greater.
- You must enable the Native Client flag in Chrome, and relaunch your browser (all Chrome windows will restart).
- You may also need to enable the Native Client plugin in Chrome.
- The .nexe file must be served from a web server (e.g., the local mini-server included with the SDK).
- The .nexe file must be compiled for your machine's architecture (x86-32 or x86-64).
For instructions on how to resolve these issues, see the .nexe files never finish loading question in the FAQ.
- Can't find libraries containing necessary symbols
- One way to find the appropriate library for a given symbol:
nm -o toolchain/platform/x86_64-nacl/lib64/*.a | grep MySymbolName