Native Client

Application Structure

This chapter of the Developer's Guide describes the general structure of a Native Client application. The chapter assumes you are familiar with the material presented in the Technical Overview.

The "Hello, World" example is used here to illustrate basic Native Client programming techniques. You can find this code in the /examples/hello_world directory in the Native Client SDK download.

Glossary

instance
A rectangle on a web page that is managed by a Native Client module (the rectangle can have width=0 and height=0, which means that nothing is drawn on the page).
manifest file
A file containing metadata or information about accompanying files.
module
Short for "Native Client module," which is an executable file that is generated by compiling C or C++ code with the Native Client toolchain. The file extension for a module is .nexe.

Application components

A Native Client application typically contains the following components:

  • an HTML file;
  • JavaScript code, which can be included in the HTML file or contained in one or more separate .js files;
  • CSS styles, which can be included in the HTML file or contained in one or more separate .css files;
  • a Native Client manifest file (with a .nmf extension) that specifies how to load a Native Client module for different processors; and
  • a Native Client module, written in C or C++, and compiled into one or more executable files (with a .nexe extension) for different processors.

Applications that are published in the Chrome Web Store also include a Chrome Web Store manifest file (manifest.json) and one or more icon files.

HTML file and the <embed> element

The <embed> element in an HTML file triggers the loading of a Native Client module and specifies the rectangle on the web page that is managed by the module. Here is the <embed> element from the "Hello, World" application:

<embed name="nacl_module"
  id="hello_world"
  width=200 height=200
  src="hello_world.nmf"
  type="application/x-nacl" />

In the <embed> element:

name
is the DOM name attribute for the Native Client module ("nacl_module" is often used as a convention)
id
specifies the DOM ID for the Native Client module
width, height
specify the size in pixels of the rectangle on the web page that is managed by the Native Client module (if the module does not have a visible area, these values can be 0)
src
refers to the Native Client manifest file that is used to determine which version of a module to load based on the architecture of the user's computer (see the following section for more information)
type
specifies the MIME type of the embedded content; for Native Client modules the type must be "application/x-nacl"

Manifest files

Native Client applications have two types of manifest files: a Chrome Web Store manifest file and a Native Client manifest file.

A Chrome Web Store manifest file is a file with information about a web application that is published in the Chrome Web Store. This file, named manifest.json, is required for applications that are published in the Chrome Web Store. For more information about this file see Distributing Your Application and the Chrome Web Store manifest file format.

A Native Client manifest file is a file that specifies which Native Client module (executable) to load for each of the supported end-user computer architectures (for example, x86-32, x86-64, or ARM). This file is required for all Native Client applications. The extension for this file is .nmf.

The browser uses the Native Client manifest file to determine which compiled Native Client module to load for a given end-user computer architecture. In most cases, you can simply use the Python script provided with the SDK, create_nmf.py, to create a manifest file for your application as part of the compilation step (see the Makefile in any of the SDK examples for an illustration of how to do so).

Here's a sample manifest file for an application that uses the newlib C library:

{
  "program": {
    "x86-32": {
      "url": "hello_world_x86_32.nexe"
    },
    "x86-64": {
      "url": "hello_world_x86_64.nexe"
    },
    "arm": {
      "url": "hello_world_arm.nexe"
    }
  }
}

For applications that use the newlib library, a typical manifest file contains a JSON dictionary with a single top-level key/value pair: the "program" key and a value consisting of a nested dictionary. The nested dictionary contains keys corresponding to the names of the supported computer architectures, and values referencing the file to load for a given architecture—specifically, the URL of the .nexe file, given by the "url" key. URLs are specified relative to the location of the manifest file.

For applications that use the glibc library, the manifest file must also contain a "files" key that specifies the shared libraries that the applications use. This is discussed in detail in Dynamic Linking and Loading with glibc. To see some example manifest files, build some of the example applications in the SDK (run make in the example subdirectories) and look at the generated manifest files.

Modules and instances

A Native Client module is C or C++ code compiled into an executable .nexe file.

An instance is a rectangle on a web page that is managed by a module. An instance may have a dimension of width=0 and height=0, meaning that the instance does not have any visible component on the web page. An instance is created by including an <embed> element in a web page. The <embed> element references a Native Client manifest file that loads a version of the module compiled for the end-user's computer architecture. A module may be included in a web page multiple times by using multiple <embed> elements that refer to the module; in this case the Native Client runtime system loads the module once and creates multiple instances that are managed by the module.

The "Hello, World" example has one instance of the hello_world module, i.e., one <embed> element in hello_world.html. The actual module that is loaded (hello_world_x86_32.nexe or hello_world_x86_64.nexe) depends on the end-user computer architecture.

Native Client modules: A closer look

A Native Client module must include three components:

  • a factory function called CreateModule()
  • a Module class (derived from the pp::Module class)
  • an Instance class (derived from the pp:Instance class)

In the "Hello, World" example, these three components are specified in the file hello_world.cc. Here is the factory function:

Module* CreateModule() {
  return new hello_world::HelloWorldModule();
}

Native Client modules do not have a main() function. The CreateModule() factory function is the main binding point between a module and the browser, and serves as the entry point into the module. The browser calls CreateModule() when a module is first loaded; this function returns a Module object derived from the pp::Module class. The browser keeps a singleton of the Module object.

Below is the Module class from the "Hello, World" example:

class HelloWorldModule : public pp::Module {
 public:
  HelloWorldModule() : pp::Module() {}
  virtual ~HelloWorldModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new HelloWorldInstance(instance);
  }
};

The Module class must include a CreateInstance() function. The browser calls the CreateInstance() function of the Module object returned by CreateModule() every time it encounters an <embed> element on a web page that references the same module. The CreateInstance() function creates and returns an Instance object derived from the pp::Instance class.

Below is the Instance class from the "Hello, World" example:

class HelloWorldInstance : public pp::Instance {
 public:
  explicit HelloWorldInstance(PP_Instance instance) : pp::Instance(instance) {}
  virtual ~HelloWorldInstance() {}

  virtual void HandleMessage(const pp::Var& var_message);
};

As in the example above, the Instance class for your module will likely include an implementation of the HandleMessage() funtion. The browser calls an instance's HandleMessage() function every time the JavaScript code in an application calls postMessage() to send a message to the instance. See the Native Client messaging system for more information about how to send messages between JavaScript code and Native Client modules.

The module in the "Hello, World" example is created from two files: hello_world.cc and helper_functions.cc. The first file, hello_world.cc, contains the CreateModule() factory function and the Module and Instance classes described above. The second file, helper_functions.cc, contains plain C++ functions that do not use the Pepper API. This is a typical design pattern in Native Client, where plain C++ non-Pepper functions (functions that use standard types like string) are specified in a separate file from Pepper functions (functions that use Var, for example). This design pattern allows the plain C++ functions to be unit-tested with a command-line test (e.g., test_helper_functions.cc); this is easier than running tests inside Chrome.

While the CreateModule factory function, the Module class, and the Instance class are required for a Native Client application, the code samples shown above don't actually do anything. Subsequent chapters in the Developer's Guide build on these code samples and add more interesting functionality.

Threading

Currently, calls to a Native Client module always execute on the main thread of the module. Similarly, all calls to the Pepper API (with the exception of pp::Core::CallOnMainThread()) must be made on the main thread of the module.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.