blob: 9d402bf2600de4ed549ce3fd831eff7efbec16f5 [file] [log] [blame]
.. _tutorial:
#############################
C++ Tutorial: Getting Started
#############################
.. contents::
:local:
:backlinks: none
:depth: 2
Overview
========
This tutorial shows how to build and run a web application using Portable Native
Client (PNaCl). This is a client-side application that uses HTML, JavaScript and
a Native Client module written in C++. The PNaCl toolchain is used to enable
running the Native Client module directly from a web page.
It's recommended to read the :doc:`Native Client Technical Overview
<../overview>` prior to going through this tutorial.
What the application in this tutorial does
------------------------------------------
The application in this tutorial shows how to load a Native Client module in a
web page, and how to send messages between JavaScript and the C++ code in the
Native Client module. In this simple application, the JavaScript code in the web
page sends a ``'hello'`` message to the Native Client module. When the Native
Client module receives a message, it checks whether the message is equal to the
string ``'hello'``. If it is, the Native Client module returns a message saying
``'hello from NaCl'``. A JavaScript alert panel displays the message received
from the Native Client module.
Communication between JavaScript and Native Client modules
----------------------------------------------------------
The Native Client programming model supports bidirectional communication between
JavaScript and the Native Client module (C/C++ code). Both sides can initiate
and respond to messages. In all cases, the communication is asynchronous: The
caller (JavaScript or the Native Client module) sends a message, but the caller
does not wait for, or may not even expect, a response. This behavior is
analogous to client/server communication on the web, where the client posts a
message to the server and returns immediately. The Native Client messaging
system is part of the Pepper API, and is described in detail in
:doc:`Developer's Guide: Messaging System <coding/message-system>`.
TODO: would it be better to compare to web-worker communication?
Step 1: Download and install the Native Client SDK
==================================================
Follow the instructions on the :doc:`Download <../sdk/download>` page to
download and install the Native Client SDK.
.. _tutorial_step_2:
Step 2: Start a local server
============================
To simulate a production environment, the SDK provides a simple web server that
can be used to serve the application on ``localhost``. A convenience Makefile
rule called ``serve`` is the easiest way to invoke it:
.. naclcode::
:prettyprint: 0
$ cd pepper_$(VERSION)/getting_started
$ make serve
.. Note::
:class: note
The SDK may consist of several "bundles", one per Chrome/Pepper version (see
:doc:`versioning information <../version>`). In the sample invocation above
``pepper_$(VERSION)`` refers to the specific version you want to use. For
example, ``pepper_31``. If you don't know which version you need, use the
one labeled ``(stable)`` by ``naclsdk list``. See :doc:`Download the Native
Client SDK <../sdk/download>` for more details.
If no port number is specified, the server defaults to port 5103, and can be
accessed at http://localhost:5103.
Any server can be used for the purpose of development. The one provided with the
SDK is just a convenience, not a requirement.
.. _tutorial_step_3:
Step 3: Set up the Chrome browser
=================================
PNaCl is enabled by default in Chrome version 31 and later. Please make sure
that you have a suitable version to work through this tutorial. It's also
important to use a Chrome version that's the same or newer than the SDK bundle
used to build the Native Client modules.
.. Note::
:class: note
To find out the version of Chrome, type ``about:chrome`` in the address bar.
For a better development experience, it's also recommended to disable the
Chrome cache. Chrome caches resources aggressively; disabling the cache helps
make sure that the latest version of the Native Client module is loaded during
development.
* Open Chrome's developer tools by clicking the menu icon |menu-icon| and
choosing ``Tools > Developer tools``.
* Click the gear icon |gear-icon| in the bottom right corner of the Chrome
window.
* Under the "General" settings, check the box next to "Disable cache (while
DevTools is open)".
* Keep the Developer Tools pane open while developing Native Client
applications.
.. |menu-icon| image:: /images/menu-icon.png
.. |gear-icon| image:: /images/gear-icon.png
Step 4: Stub code for the tutorial
==================================
The stub code for the tutorial is avalable in the SDK, in
``pepper_$(VERSION)/getting_started/part1``. It contains the following files:
* ``index.html``: Contains the HTML layout of the page as well as the JavaScript
code that interacts with the Native Client module.
The Native Client module is included in the page with an ``<embed>`` tag that
points to a manifest file.
* ``hello_tutorial.nmf``: A manifest file that's used to point the HTML to the
Native Client module and optionally provide additional commands to the PNaCl
translator that is part of the Chrome browser.
* ``hello_tutorial.cc``: C++ code for a simple Native Client module.
* ``Makefile``: Compilation commands to build the **pexe** (portable executable)
from the C++ code in ``hello_tutorial.cc``.
It's a good idea to take a look at these files now---they contain a large amount
of comments that help explain their structure and contents. For more details
on the structure of a typical Native Client application, see
:doc:`Application Structure <coding/application-structure>`.
The stub code is intentionally very minimal. The C++ code does not do anything
except correctly initialize itself. The JavaScript code waits for the Native
Client module to load and changes the status text on the web page accordingly.
Step 5: Compile the Native Client module and run the stub application
=====================================================================
To compile the Native Client module, run ``make``:
.. naclcode::
:prettyprint: 0
$ cd pepper_$(VERSION)/getting_started/part1
$ make
Since the sample is located within the SDK tree, the Makefile knows how to find
the PNaCl toolchain automatically and use it to build the module. If you're
building applications outside the NaCl SDK tree, you should set the
``$NACL_SDK_ROOT`` environment variable. See :doc:`Building Native Client
Modules <devcycle/building>` for more details.
Assuming the local server was started according to the instructions in
:ref:`Step 2 <tutorial_step_2>`, you can now load the sample by pointing Chrome
to http://localhost:5103/part1. Chrome should load the Native Client module
successfully and the Status text should change from "LOADING..." to "SUCCESS".
If you run into problems, check out the :ref:`Troubleshooting section
<tutorial_troubleshooting>` below.
Step 6: Modify the JavaScript code to send a message to the Native Client module
================================================================================
In this step, you'll modify the web page (``index.html``) to send a message to
the Native Client module after the page loads the module.
Look for the JavaScript function ``moduleDidLoad()``, and add new code to send
a 'hello' message to the module. The new function should look as follows:
.. naclcode::
function moduleDidLoad() {
HelloTutorialModule = document.getElementById('hello_tutorial');
updateStatus('SUCCESS');
// Send a message to the Native Client module
HelloTutorialModule.postMessage('hello');
}
Step 7: Implement a message handler in the Native Client module
===============================================================
In this step, you'll modify the Native Client module (``hello_tutorial.cc``) to
respond to the message received from the JavaScript code in the application.
Specifically, you'll:
* Implement the ``HandleMessage()`` member function of the module instance.
* Use the ``PostMessage()`` member function to send a message from the module to
the JavaScript code.
First, add code to define the variables used by the Native Client module (the
'hello' string you're expecting to receive from JavaScript and the reply string
you want to return to JavaScript as a response). In the file
``hello_tutorial.cc``, add this code after the ``#include`` statements:
.. naclcode::
namespace {
// The expected string sent by the browser.
const char* const kHelloString = "hello";
// The string sent back to the browser upon receipt of a message
// containing "hello".
const char* const kReplyString = "hello from NaCl";
} // namespace
Now, implement the ``HandleMessage()`` member function to check for
``kHelloString`` and return ``kReplyString.`` Look for the following line:
.. naclcode::
// TODO(sdk_user): 1. Make this function handle the incoming message.
Populate the member function with code, as follows:
.. naclcode::
virtual void HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string())
return;
std::string message = var_message.AsString();
pp::Var var_reply;
if (message == kHelloString) {
var_reply = pp::Var(kReplyString);
PostMessage(var_reply);
}
}
See the Pepper API documentation for additional information about the
`pp::Instance.HandleMessage
<https://developers.google.com/native-client/peppercpp/classpp_1_1_instance.html#a5dce8c8b36b1df7cfcc12e42397a35e8>`_
and `pp::Instance.PostMessage
<https://developers.google.com/native-client/peppercpp/classpp_1_1_instance.html#a67e888a4e4e23effe7a09625e73ecae9>`_
member functions.
Step 8: Compile the Native Client module and run the application again
======================================================================
Compile the Native Client module by running the ``make`` command again.
Re-run the application by reloading http://localhost:5103/part1 in Chrome.
After Chrome loads the Native Client module, you should see an alert panel
appear with the message sent from the module.
.. _tutorial_troubleshooting:
Troubleshooting
===============
If your application doesn't run, see :ref:`Step 3 <tutorial_step_3>` above to
verify that you've set up your environment correctly, including both the Chrome
browser and the local server. Make sure that you're running a correct version of
Chrome, which is also greater or equal than the SDK bundle version you are
using.
Another useful debugging aid is the Chrome JavaScript console (available via the
``Tools`` menu in Chrome). Examine it for clues about what went wrong. For
example, if there's a message saying "NaCl module crashed", there is a
possibility that the Native Client module has a bug; :doc:`debugging
<devcycle/debugging>` may be required.
There's more information about troubleshooting in the documentation:
* :ref:`FAQ Troubleshooting <faq_troubleshooting>`.
* The :doc:`Progress Events <coding/progress-events>` document contains some
useful information about handling error events.
.. TODO: fix links to :ref:/:doc: once ReST-ified.
Next steps
==========
* See the :doc:`Application Structure <coding/application-structure>`
chapter in the Developer's Guide for information about how to structure a
Native Client module.
* Check the `C++ Reference
<https://developers.google.com/native-client/peppercpp>`_ for details about
how to use the Pepper APIs.
* Browse through the source code of the SDK examples (in the ``examples``
directory) to learn additional techniques for writing Native Client
applications and using the Pepper APIs.
* See the :doc:`Building <devcycle/building>`, :doc:`Running
<devcycle/running>`, and :doc:`Debugging pages <devcycle/debugging>`
for information about how to build, run, and debug Native Client
applications.
* Check the `naclports <http://code.google.com/p/naclports/>`_ project to see
what libraries have been ported for use with Native Client. If you port an
open-source library for your own use, we recommend adding it to naclports
(see `How to check code into naclports
<http://code.google.com/p/naclports/wiki/HowTo_Checkin>`_).