Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / doc / devguide / tutorial / tutorial-part2.rst
blob6338b19fd15b184f52536fdf31f4cfef9b956f95
1 .. _tutorial2:
3 ######################################
4 C++ Tutorial: Getting Started (Part 2)
5 ######################################
7 .. contents::
8   :local:
9   :backlinks: none
10   :depth: 2
12 Overview
13 ========
15 This tutorial shows how to convert the finished PNaCl web application from
16 :doc:`Part 1 <tutorial-part1>` to use the Native Client SDK build system and
17 common JavaScript files. It also demonstrates some techniques to make your web
18 application `Content Security Policy (CSP)-compliant
19 </apps/contentSecurityPolicy>`_, which is necessary for `Chrome Apps </apps>`_.
21 Using the Native Client SDK build system makes it easy to build with all of the
22 SDK toolchains, and switch between the Debug and Release configurations. It
23 also simplifies the makefiles for your project, as we'll see in the next
24 section. Finally, it adds some useful commands for :ref:`running
25 <running_the_sdk_examples>` and :ref:`debugging <debugging_the_sdk_examples>`
26 your application.
28 The finished code for this example can be found in the
29 ``pepper_$(VERSION)/getting_started/part2`` directory in the Native Client SDK
30 download.
32 Using the Native Client SDK build system
33 ========================================
35 This section describes how to use the SDK build system. To do so, we'll make
36 changes in the makefile. Because the makefile in part1 and part2 are so
37 different, it is easier to start from scratch. Here is the contents of the new
38 makefile. The following sections will describe it in more detail.
40 Simplifying the Makefile
41 ------------------------
43 The makefile from part1 only supports one toolchain (PNaCl) and one
44 configuration (Release). It also only supports one source file. It's relatively
45 simple, but if we want to add support for multiple toolchains, configurations,
46 source files, or build steps, it would grow increasingly complex. The SDK build
47 system uses a set of variables and macros to make this possible, without
48 significantly increasing the complexity of the makefile.
50 Here is the new makefile, supporting three toolchains (PNaCl, Newlib NaCl,
51 Glibc NaCl) and two configurations (Debug, Release).
53 .. naclcode::
55     VALID_TOOLCHAINS := pnacl newlib glibc
57     NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
58     include $(NACL_SDK_ROOT)/tools/common.mk
60     TARGET = part2
61     LIBS = ppapi_cpp ppapi
63     CFLAGS = -Wall
64     SOURCES = hello_tutorial.cc
66     # Build rules generated by macros from common.mk:
68     $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
70     # The PNaCl workflow uses both an unstripped and finalized/stripped binary.
71     # On NaCl, only produce a stripped binary for Release configs (not Debug).
72     ifneq (,$(or $(findstring pnacl,$(TOOLCHAIN)),$(findstring Release,$(CONFIG))))
73     $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
74     $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
75     else
76     $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
77     endif
79     $(eval $(call NMF_RULE,$(TARGET),))
81 Choosing valid toolchains, and including common.mk
82 --------------------------------------------------
84 The makefile begins by specifying the toolchains that are valid for this
85 project. The Native Client SDK build system supports multi-toolchain projects
86 for its examples and libraries, but generally you will choose one toolchain
87 when you begin your project and never change it. Please see the
88 :ref:`Toolchains section of the Native Client overview <toolchains>` for more
89 information.
91 For this example, we support the ``pnacl``, ``newlib`` and ``glibc`` toolchains.
93 .. naclcode::
95     VALID_TOOLCHAINS := pnacl newlib glibc
97 Next, as a convenience, we specify where to find ``NACL_SDK_ROOT``. Because
98 this example is located in ``pepper_$(VERSION)/getting_started/part2``, the
99 root of the SDK is two directories up.
101 .. naclcode::
103     NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../..)
105 .. Note::
106   :class: note
108    In your own projects, you can use the absolute path to your installed SDK
109    here. You can also override this default by setting the ``NACL_SDK_ROOT``
110    environment variable. See :ref:`Step 5 of Part 1 of this tutorial
111    <tutorial_step_5>` for more details.
113 Next, we include the file ``tools/common.mk``. This file provides the
114 functionality for the Native Client SDK build system, including new build rules
115 to compile and link a project, which we'll use below.
117 .. naclcode::
119   include $(NACL_SDK_ROOT)/tools/common.mk
121 Configuring your project
122 ------------------------
124 After including ``tools/common.mk``, we configure the project by specifying its
125 name, the sources and libraries it uses:
127 .. naclcode::
129     TARGET = part2
130     LIBS = ppapi_cpp ppapi
132     CFLAGS = -Wall
133     SOURCES = hello_tutorial.cc
135 These variable names are not required and not used by the SDK build system;
136 they are only used in the rules described below. By convention, all SDK
137 makefiles use the following variables:
139 TARGET
140   The name of the project to build. This variable determines the name of the
141   library or executable that will be generated. In the above example, we call
142   the target ``part2``, which will generate an executable called
143   ``part2.pexe`` for PNaCl. For NaCl toolchains, the executable's file name
144   will be given a suffix for its architecture. For example, the ARM executable
145   is called ``part2_arm.nexe``.
147 LIBS
148   A list of libraries that this executable needs to link against. The library
149   search path is already set up to only look in the directory for the current
150   toolchain and architecture. In this example, we link against ``ppapi_cpp``
151   and ``ppapi``. ``ppapi_cpp`` is needed to use the `Pepper C++ interface
152   </native-client/pepper_stable/cpp/>`_. ``ppapi`` is needed for communicating
153   with the browser.
155 CFLAGS
156   A list of extra flags to pass to the compiler. In this example, we pass
157   ``-Wall``, which turns on all warnings.
159 LDFLAGS
160   A list of additional flags to pass to the linker. This example does not need
161   any special linker flags, so this variable is omitted.
163 SOURCES
164   A list of C or C++ sources to compile, separated by spaces. If you have a
165   long list of sources, it may be easier to read if you put each file on its
166   own line, and use ``\`` as a line-continuation character. Here's an example:
168 .. naclcode::
170     SOURCES = foo.cc \
171               bar.cc \
172               baz.cc \
173               quux.cc
175 Build macros
176 ------------
178 For many projects, the following build macros do not need to be changed; they
179 will use the variables we've defined above.
181 .. naclcode::
183     $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
185     ifneq (,$(or $(findstring pnacl,$(TOOLCHAIN)),$(findstring Release,$(CONFIG))))
186     $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
187     $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
188     else
189     $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
190     endif
192     $(eval $(call NMF_RULE,$(TARGET),))
194 The first line defines rules to compile each source in ``SOURCES``, using the
195 flags in ``CFLAGS``:
197 .. naclcode::
199     $(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
201 The next six lines define rules to link the object files into one or more
202 executables. When ``TOOLCHAIN`` is ``pnacl``, there is only one executable
203 generated: in the example above, ``part2.pexe``. When using a NaCl toolchain,
204 there will be three executables generated, one for each architecture: in the
205 example above, ``part2_arm.nexe``, ``part2_x86_32.nexe`` and
206 ``part2_x86_64.nexe``.
208 When ``CONFIG`` is ``Release``, each executable is also stripped to remove
209 debug information and reduce the file size. Otherwise, when the ``TOOLCHAIN``
210 is ``pnacl``, the workflow involves creating an unstripped binary for debugging
211 and then finalizing it and stripping it for publishing.
213 .. naclcode::
215     ifneq (,$(or $(findstring pnacl,$(TOOLCHAIN)),$(findstring Release,$(CONFIG))))
216     $(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
217     $(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
218     else
219     $(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
220     endif
222 Finally, the NMF rule generates a NaCl manifest file (``.nmf``) that references
223 each executable generated in the previous step:
225 .. naclcode::
227     $(eval $(call NMF_RULE,$(TARGET),))
229 Making index.html work for Chrome Apps
230 ======================================
232 This section describes the changes necessary to make the HTML and JavaScript in
233 part1 CSP-compliant. This is required if you want to build a `Chrome App
234 </apps>`_, but is not necessary if you want to use PNaCl on the open web.
236 CSP rules
237 ---------
239 `Chrome Apps CSP </apps/contentSecurityPolicy#what>`_ restricts you from doing
240 the following:
242 * You can’t use inline scripting in your Chrome App pages. The restriction
243   bans both ``<script>`` blocks and event handlers (``<button onclick="...">``).
244 * You can’t reference any external resources in any of your app files (except
245   for video and audio resources). You can’t embed external resources in an
246   iframe.
247 * You can’t use string-to-JavaScript methods like ``eval()`` and ``new
248   Function()``.
250 Making index.html CSP-compliant
251 -------------------------------
253 To make our application CSP-compliant, we have to remove inline scripting. As
254 described above, we can't use inline ``<script>`` blocks or event handlers. This
255 is easy to do---we'll just reference some new files from our script tag, and
256 remove all of our inlined scripts:
258 .. naclcode::
260     <head>
261       ...
262       <script type="text/javascript" src="common.js"></script>
263       <script type="text/javascript" src="example.js"></script>
264     </head>
266 ``common.js`` has shared code used by all SDK examples, and is described
267 later in this document. ``example.js`` is a script that has code specific to
268 this example.
270 We also need to remove the inline event handler on the body tag:
272 .. naclcode::
274   <body onload="pageDidLoad()">
275   ...
277 This logic is now handled by ``common.js``.
279 Making index.html support different toolchains and configurations
280 -----------------------------------------------------------------
282 Finally, there are a few changes to ``index.html`` that are not necessary for
283 CSP-compliance, but help make the SDK examples more generic.
285 First, we add some `data attributes
286 <https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes>`_
287 to the body element to specify the name, supported toolchains, supported
288 configurations, and path to the ``.nmf`` file:
290 .. naclcode::
292     <body data-name="part2"
293         data-tools="newlib glibc pnacl"
294         data-configs="Debug Release"
295         data-path="{tc}/{config}">
296     ...
298 ``common.js`` will read these data attributes to allow you to load the same
299 example with different toolchains by changing the URL's `query string
300 <http://en.wikipedia.org/wiki/Query_string>`_. For example, you can load the
301 glibc Debug version of this example by navigating to
302 ``index.html?tc=glibc&config=Debug``.  Path URI's such as ``../``, for example
303 do not work for either the data-path parameter or its corresponding query
304 string.
306 Next, we remove the ``embed`` element that is described in HTML. This will be
307 automatically added for us by ``common.js``, based on the current
308 toolchain/configuration combination:
310 .. naclcode::
312     <!--
313     Just as in part1, the <embed> element will be wrapped inside the <div>
314     element with the id "listener". In part1, the embed was specified in HTML,
315     here the common.js module creates a new <embed> element and adds it to the
316     <div> for us.
317     -->
318     <div id="listener"></div>
320 Sharing common code with common.js
321 ==================================
323 ``common.js`` contains JavaScript code that each example uses to create a
324 NaCl module, handle messages from that module and other common tasks like
325 displaying the module load status and logging messages. Explaining all of
326 ``common.js`` is outside the scope of this document, but please look at the
327 documentation in that file for more information.
329 Loading the page and creating the module
330 ----------------------------------------
332 Since we've added ``<script>`` tags for ``common.js`` and ``example.js`` to the
333 ``head`` element, they will be loaded and executed before the rest of the
334 document has been parsed. As a result, we have to wait for the page to finish
335 loading before we try to create the embed element and add it to the page.
337 We can do that by calling ``addEventListener`` and listening for the
338 ``DOMContentLoaded`` event:
340 .. naclcode::
342     // Listen for the DOM content to be loaded. This event is fired when parsing of
343     // the page's document has finished.
344     document.addEventListener('DOMContentLoaded', function() {
345       ...
346     });
348 Inside this function, we parse the URL query string, and compare that to the
349 data attributes:
351 .. naclcode::
353     // From https://developer.mozilla.org/en-US/docs/DOM/window.location
354     var searchVars = {};
355     if (window.location.search.length > 1) {
356       var pairs = window.location.search.substr(1).split('&');
357       for (var key_ix = 0; key_ix < pairs.length; key_ix++) {
358         var keyValue = pairs[key_ix].split('=');
359         searchVars[unescape(keyValue[0])] =
360             keyValue.length > 1 ? unescape(keyValue[1]) : '';
361       }
362     }
364     ...
366     var toolchains = body.dataset.tools.split(' ');
367     var configs = body.dataset.configs.split(' ');
369     ...
371     var tc = toolchains.indexOf(searchVars.tc) !== -1 ?
372         searchVars.tc : toolchains[0];
374     // If the config value is included in the search vars, use that.
375     // Otherwise default to Release if it is valid, or the first value if
376     // Release is not valid.
377     if (configs.indexOf(searchVars.config) !== -1)
378       var config = searchVars.config;
379     else if (configs.indexOf('Release') !== -1)
380       var config = 'Release';
381     else
382       var config = configs[0];
384 Then ``domContentLoaded`` is called, which performs some checks to see if the
385 browser supports Native Client, then creates the NaCl module.
387 .. naclcode::
389     function domContentLoaded(name, tool, path, width, height, attrs) {
390       updateStatus('Page loaded.');
391       if (!browserSupportsNaCl(tool)) {
392         updateStatus(
393             'Browser does not support NaCl (' + tool + '), or NaCl is disabled');
394       } else if (common.naclModule == null) {
395         updateStatus('Creating embed: ' + tool);
397         // We use a non-zero sized embed to give Chrome space to place the bad
398         // plug-in graphic, if there is a problem.
399         width = typeof width !== 'undefined' ? width : 200;
400         height = typeof height !== 'undefined' ? height : 200;
401         attachDefaultListeners();
402         createNaClModule(name, tool, path, width, height, attrs);
403       } else {
404         // It's possible that the Native Client module onload event fired
405         // before the page's onload event.  In this case, the status message
406         // will reflect 'SUCCESS', but won't be displayed.  This call will
407         // display the current message.
408         updateStatus('Waiting.');
409       }
410     }
412 ``attachDefaultListeners`` is added before the creation of the module, to make
413 sure that no messages are lost. Note that ``window.attachListeners`` is also
414 called; this is the way that ``common.js`` allows each example to configure
415 itself differently. If an example defines the ``attachListeners`` function, it
416 will be called by ``common.js``.
418 .. naclcode::
420     function attachDefaultListeners() {
421       var listenerDiv = document.getElementById('listener');
422       listenerDiv.addEventListener('load', moduleDidLoad, true);
423       listenerDiv.addEventListener('message', handleMessage, true);
424       listenerDiv.addEventListener('crash', handleCrash, true);
425       if (typeof window.attachListeners !== 'undefined') {
426         window.attachListeners();
427       }
428     }
430 Finally, ``createNaClModule`` actually creates the ``embed``, and appends it as
431 a child of the element with id ``listener``:
433 .. naclcode::
435     function createNaClModule(name, tool, path, width, height, attrs) {
436       var moduleEl = document.createElement('embed');
437       moduleEl.setAttribute('name', 'nacl_module');
438       moduleEl.setAttribute('id', 'nacl_module');
439       moduleEl.setAttribute('width', width);
440       moduleEl.setAttribute('height', height);
441       moduleEl.setAttribute('path', path);
442       moduleEl.setAttribute('src', path + '/' + name + '.nmf');
444       ...
446       var mimetype = mimeTypeForTool(tool);
447       moduleEl.setAttribute('type', mimetype);
449       var listenerDiv = document.getElementById('listener');
450       listenerDiv.appendChild(moduleEl);
451       ...
452     }
454 When the module finishes loading, it will dispatch a ``load`` event, and the
455 event listener function that was registered above (``moduleDidLoad``) will be
456 called. Note that ``common.js`` allows each example to define a
457 ``window.moduleDidLoad`` function, that will be called here as well.
459 .. naclcode::
461     function moduleDidLoad() {
462       common.naclModule = document.getElementById('nacl_module');
463       updateStatus('RUNNING');
465       if (typeof window.moduleDidLoad !== 'undefined') {
466         window.moduleDidLoad();
467       }
468     }
470 Example-specific behavior with example.js
471 =========================================
473 As described in the previous section, ``common.js`` will call certain functions
474 during the module loading process. This example only needs to respond to two:
475 ``moduleDidLoad`` and ``handleMessage``.
477 .. naclcode::
479     // This function is called by common.js when the NaCl module is
480     // loaded.
481     function moduleDidLoad() {
482       // Once we load, hide the plugin. In this example, we don't display anything
483       // in the plugin, so it is fine to hide it.
484       common.hideModule();
486       // After the NaCl module has loaded, common.naclModule is a reference to the
487       // NaCl module's <embed> element.
488       //
489       // postMessage sends a message to it.
490       common.naclModule.postMessage('hello');
491     }
493     // This function is called by common.js when a message is received from the
494     // NaCl module.
495     function handleMessage(message) {
496       var logEl = document.getElementById('log');
497       logEl.textContent += message.data;
498     }
499     
500 Compile the Native Client module and run the application again
501 ==============================================================
503 #. Compile the Native Client module by running the ``make`` command again.
504 #. Start the SDK web server by running ``make server``.
505 #. Re-run the application by reloading ``http://localhost:5103/part2`` in 
506    Chrome.
507    
508    After Chrome loads the Native Client module, you should see the message sent
509    from the module.