blob: f95714387ab4b09de60c285716dd6e4ffa613692 [file] [log] [blame]
.. _devcycle-native-client-modules:
#####################
Native Client Modules
#####################
This document describes the classes and functions that you need to
implement in a Native Client module in order for Chrome to load,
initialize, and run a Native Client module. The requirements depend on
whether the module is written in C or C++.
.. contents::
:local:
:backlinks: none
:depth: 2
Introduction
============
Native Client modules do not have a ``main()`` function. When a module loads,
the Native Client runtime calls the code in the module to create an instance and
initialize the interfaces for the APIs the module uses. This initialization
sequence depends on whether the module is written in C or C++ and requires that
you implement specific functions in each case.
Writing modules in C
====================
The C API uses a prefix convention to show whether an interface is implemented
in the browser or in a module. Interfaces starting with ``PPB_`` (which can be
read as "Pepper *browser*") are implemented in the browser and they are called
from your module. Interfaces starting with ``PPP_`` ("Pepper *plugin*") are
implemented in the module; they are called from the browser and will execute on
the main thread of the module instance.
When you implement a Native Client module in C you must include these components:
* The functions ``PPP_InitializeModule`` and ``PPP_GetInterface``
* Code that implements the interface ``PPP_Instance`` and any other C interfaces
that your module uses
For each PPP interface, you must implement all of its functions, create the
struct through which the browser calls the interface, and insure that the
function ``PPP_GetInterface`` returns the appropriate struct for the interface.
For each PPB interface, you must declare a pointer to the interface and
initialize the pointer with a call to ``get_browser`` inside
``PPP_InitializeModule``.
These steps are illustrated in the code excerpt below, which shows the
implementation and initialization of the required ``PPP_Instance``
interface. The code excerpt also shows the initialization of three additional
interfaces which are not required: ``PPB_Instance`` (through which the Native
Client module calls back to the browser) and ``PPB_InputEvent`` and
``PPP_InputEvent``.
.. naclcode::
// Include the interface headers.
// PPB APIs describe calls from the module to the browser.
// PPP APIs describe calls from the browser to the functions defined in your module.
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppb_InputEvent.h"
#include "ppapi/c/ppp_InputEvent.h"
// Create pointers for each PPB interface that your module uses.
static PPB_Instance* ppb_instance_interface = NULL;
static PPB_Instance* ppb_input_event_interface = NULL;
// Define all the functions for each PPP interface that your module uses.
// Here is a stub for the first function in PPP_Instance.
static PP_Bool Instance_DidCreate(PP_Instance instance,
uint32_t argc,
const char* argn[],
const char* argv[]) {
return PP_TRUE;
}
// ... more API functions ...
// Define PPP_GetInterface.
// This function should return a non-NULL value for every interface you are using.
// The string for the name of the interface is defined in the interface's header file.
// The browser calls this function to get pointers to the interfaces that your module implements.
PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
// Create structs for each PPP interface.
// Assign the interface functions to the data fields.
if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
static struct PPP_Instance instance_interface = {
&Instance_DidCreate,
// The definitions of these functions are not shown
&Instance_DidDestroy,
&Instance_DidChangeView,
&Instance_DidChangeFocus,
&Instance_HandleDocumentLoad
};
return &instance_interface;
}
if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0) {
static struct PPP_InputEvent input_interface = {
// The definition of this function is not shown.
&Instance_HandleInput,
};
return &input_interface;
}
// Return NULL for interfaces that you do not implement.
return NULL;
}
// Define PPP_InitializeModule, the entry point of your module.
// Retrieve the API for the browser-side (PPB) interfaces you will use.
PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser) {
ppb_instance_interface = (PPB_Instance*)(get_browser(PPB_INSTANCE_INTERFACE));
ppb_input_event_interface = (PPB_Instance*)(get_browser(PPB_INPUT_EVENT_INTERFACE));
return PP_OK;
}
Writing modules in C++
======================
When you implement a Native Client module in C++ you must include these components:
* The factory function called ``CreateModule()``
* Code that defines your own Module class (derived from the ``pp::Module``
class)
* Code that defines your own Instance class (derived from the ``pp:Instance``
class)
TODO: this example no longer exists. Update this paragraph and the the hello
world reference in the paragraph below.
In the interactive "Hello, World" example (examples/hello_world_interactive),
these three components are specified in the file ``hello_world.cc``. Here is
the factory function:
.. naclcode::
namespace pp {
Module* CreateModule() {
return new hello_world::HelloWorldModule();
}
}
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:
.. naclcode::
class HelloWorldModule : public pp::Module {
public:
HelloWorldModule() : pp::Module() {}
virtual ~HelloWorldModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new HelloWorldInstance(instance);
}
};
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
:doc:`Native Client messaging system<message-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 documents in the
Developer's Guide build on these code samples and add more interesting
functionality.
Threading
=========
TODO: Update/remove this.
Currently, calls from the browser to a Native Client module always execute on
the main thread of the module. Similarly, all Pepper API calls, both C and C++,
must be made on the main thread of the module, with the exception of
pp::Core::CallOnMainThread() and PPB_Core::CallOnMainThread().