summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorsbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 13:26:13 +0000
committersbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 13:26:13 +0000
commitef85628d40792da33e27ca005fc23671afd70060 (patch)
treecff484f4e5f4cc53f8e05dea923b707d3d33a640 /native_client_sdk
parent2485946501c9755d7146a575186027ec121cbe8b (diff)
downloadchromium_src-ef85628d40792da33e27ca005fc23671afd70060.zip
chromium_src-ef85628d40792da33e27ca005fc23671afd70060.tar.gz
chromium_src-ef85628d40792da33e27ca005fc23671afd70060.tar.bz2
[NaCl Docs] Port dynamic-loading page from devsite.
This is just a content port. No content changes at this point. R=binji@chromium.org Review URL: https://codereview.chromium.org/24080004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224120 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/doc/community/middleware.rst4
-rw-r--r--native_client_sdk/src/doc/devguide/coding/application-structure.rst2
-rw-r--r--native_client_sdk/src/doc/devguide/devcycle/building.rst4
-rw-r--r--native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst606
-rw-r--r--native_client_sdk/src/doc/index.rst1
5 files changed, 617 insertions, 0 deletions
diff --git a/native_client_sdk/src/doc/community/middleware.rst b/native_client_sdk/src/doc/community/middleware.rst
new file mode 100644
index 0000000..9a02f13
--- /dev/null
+++ b/native_client_sdk/src/doc/community/middleware.rst
@@ -0,0 +1,4 @@
+###############################
+Middleware and Software Support
+###############################
+
diff --git a/native_client_sdk/src/doc/devguide/coding/application-structure.rst b/native_client_sdk/src/doc/devguide/coding/application-structure.rst
index c791850..286b57af 100644
--- a/native_client_sdk/src/doc/devguide/coding/application-structure.rst
+++ b/native_client_sdk/src/doc/devguide/coding/application-structure.rst
@@ -4,5 +4,7 @@
Application Structure
#####################
+.. _manifest_file:
+
foo
diff --git a/native_client_sdk/src/doc/devguide/devcycle/building.rst b/native_client_sdk/src/doc/devguide/devcycle/building.rst
index 413d6b0..48cca76 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/building.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/building.rst
@@ -19,6 +19,8 @@ If you haven't read the Native Client :doc:`Technical Overview
<../../overview>` and :doc:`Tutorial <../tutorial>`, we recommend starting
with those.
+.. _target_architectures:
+
Target architectures
--------------------
@@ -195,6 +197,8 @@ targets the x86-64 architecture, i.e., ``x86_64-nacl-gcc``.
You should name executable modules with a ``.nexe`` filename extension,
regardless of what platform you're using.
+.. _compile_flags:
+
Compile flags for different development scenarios
=================================================
diff --git a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
index a5f7e5e..c19fa82 100644
--- a/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
+++ b/native_client_sdk/src/doc/devguide/devcycle/dynamic-loading.rst
@@ -1,3 +1,609 @@
######################################
Dynamic Linking and Loading with glibc
######################################
+
+.. contents::
+ :local:
+ :backlinks: none
+ :depth: 2
+
+Introduction
+============
+
+This document describes how to create and deploy dynamically linked and loaded
+applications with the glibc library in the Native Client SDK. Before reading
+this document, we recommend reading :doc:`Building Native Client Modules
+<building>`
+
+.. _c_libraries:
+
+C standard libraries: glibc and newlib
+--------------------------------------
+
+The Native Client SDK comes with two C standard libraries --- glibc and
+newlib. These libraries are described in the table below.
+
++--------+----------+-------------+--------------------------------------------+
+| Library| Linking | License | Description |
++========+==========+=============+============================================+
+| glibc | dynamic | GNU Lesser | glibc is the GNU implementation of the |
+| | or static| General | POSIX_ standard runtime library for the C |
+| | | Public | programming language. Designed for |
+| | | License | portability and performance, glibc is one |
+| | | (LGPL) | of the most popular implementations of the |
+| | | | C library. It is comprised of a set of |
+| | | | interdependent libraries including libc, |
+| | | | libpthreads, libdl, and others. For |
+| | | | documentation, FAQs, and additional |
+| | | | information about glibc, see GLIBC_ |
++--------+----------+-------------+--------------------------------------------+
+| newlib | static | Berkeley | newlib is a C library intended for use in |
+| | | Software | embedded systems. Like glibc, newlib is a |
+| | | Distribution| conglomeration of several library parts. |
+| | | (BSD) type | It is available for use under BSD-type free|
+| | | free | software licenses, which generally makes it|
+| | | software | more suitable to link statically in |
+| | | licenses | commercial, closed-source applications. For|
+| | | | documentation, FAQs, and additional |
+| | | | information about newlib, see the `newlib |
+| | | | documentation`__. |
++--------+----------+-------------+--------------------------------------------+
+
+.. _GLIBC: http://www.gnu.org/software/libc/index.html
+.. _POSIX: http://en.wikipedia.org/wiki/POSIX
+__ http://sourceware.org/newlib
+
+For proprietary (closed-source) applications, your options are to either
+statically link to newlib, or dynamically link to glibc. We recommend
+dynamically linking to glibc, for a couple of reasons:
+
+* The glibc library is widely distributed (it's included in Linux
+ distributions), and as such it's mature, hardened, and feature-rich. Your
+ code is more likely to compile out-of-the-box with glibc.
+
+* Dynamic loading can provide a big performance benefit for your application if
+ you can structure the application to defer loading of code that's not needed
+ for initial interaction with the user. It takes some work to put such code in
+ shared libraries and to load the libraries at runtime, but the payoff is
+ usually worth it. In future releases, Chrome may also support caching of
+ common dynamically linked libraries such as libc.so between applications.
+ This could significantly reduce download size and provide a further potential
+ performance benefit (for example, the hello_world example would only require
+ downloading a .nexe file that's on the order of 30KB, rather than a .nexe
+ file and several libraries, which are on the order of 1.5MB).
+
+Native Client support for dynamic linking and loading is based on glibc. Thus,
+**if your Native Client application must dynamically link and load code (e.g.,
+due to licensing considerations), we recommend that you use the glibc
+library.**
+
+.. Note::
+ :class: note
+
+ **Notes:**
+
+ * **None of the above constitutes legal advice, or a description of the legal
+ obligations you need to fulfill in order to be compliant with the LGPL or
+ newlib licenses. The above description is only a technical explanation of
+ the differences between newlib and glibc, and the choice you must make
+ between the two libraries.**
+
+ * Static linking with glibc is rarely used. Use this feature with caution.
+
+ * The standard C++ runtime in Native Client is provided by libstdc++; this
+ library is independent from and layered on top of glibc. Because of
+ licensing restrictions, libstdc++ must be statically linked for commercial
+ uses, even if the rest of an application is dynamically linked.
+
+SDK toolchains
+--------------
+
+The Native Client SDK contains multiple toolchains, which are differentiated by
+:ref:`target architecture <target_architectures>` and C library:
+
+=================== ========= ===============================
+Target architecture C library Toolchain directory
+=================== ========= ===============================
+x86 newlib toolchain/<platform>_x86_newlib
+x86 glibc toolchain/<platform>_x86_glibc
+ARM newlib toolchain/<platform>_arm_newlib
+PNaCl newlib toolchain/<platform>_pnacl
+=================== ========= ===============================
+
+In the directories listed above, <platform> is the platform of your development
+machine (i.e., win, mac, or linux). For example, in the Windows SDK, the x86
+toolchain that uses glibc is in ``toolchain/win_x86_glibc``.
+
+.. Note::
+ :class: note
+
+ **Note:** The ARM and PNaCl toolchains are currently restricted to newlib.
+
+To use the glibc library and dynamic linking in your application, you **must**
+use a glibc toolchain. (Currently the only glibc toolchain is
+``<platform>_x86_glibc``.) Note that you must build all code in your application
+with one toolchain. Code from multiple toolchains cannot be mixed.
+
+Specifying and delivering shared libraries
+------------------------------------------
+
+One significant difference between newlib and glibc applications is that glibc
+applications must explicitly list and deploy the shared libraries that they
+use.
+
+In a desktop environment, when the user launches a dynamically linked
+application, the operating system's program loader determines the set of
+libraries the application requires by reading explicit inter-module
+dependencies from executable file headers, and loads the required libraries
+into the address space of the application process. Typically the required
+libraries will have been installed on the system as a part of the application's
+installation process. Often the desktop application developer doesn't know or
+think about the libraries that are required by an application, as those details
+are taken care of by the user's operating system.
+
+In the Native Client sandbox, dynamic linking can't rely in the same way on the
+operating system or the local file system. Instead, the application developer
+must identify the set of libraries that are required by an application, list
+those libraries in a Native Client :ref:`manifest file <manifest_file>`, and
+deploy the libraries along with the application. Instructions for how to build
+a dynamically linked Native Client application, generate a Native Client
+manifest (.nmf) file, and deploy an application are provided below.
+
+Building a dynamically linked application
+=========================================
+
+A dynamically linked application typically includes one Native Client module
+and one or more shared libraries. (How to allocate code between Native Client
+modules and shared libraries is a question of application design that is beyond
+the scope of this document.) Each Native Client module and shared library must
+be compiled for at least the x86 32-bit and 64-bit architectures.
+
+The dlopen example in the SDK
+-----------------------------
+
+The Native Client SDK includes an example that demonstrates how to build a
+shared library, and how to use the ``dlopen()`` interface to load that library
+at runtime (after the application is already running). Many applications load
+and link shared libraries at launch rather than at runtime, and hence do not
+use the ``dlopen()`` interface. The SDK example is nevertheless instructive, as
+it demonstrates how to build Native Client modules (.nexe files) and shared
+libraries (.so files) with the x86 glibc toolchain, and how to generate a
+Native Client manifest file for glibc applications.
+
+The SDK example, located in the directory examples/dlopen, includes two C++
+files:
+
+eightball.cc
+ This file implements the function ``Magic8Ball()``, which is used to provide
+ whimsical answers to user questions. The file is compiled into a shared
+ library, ``libeightball.so``.
+
+dlopen.cc
+ This file implements the Native Client module, which loads
+ ``libeightball.so``, receives messages from JavaScript (sent in response to
+ user input), calls ``Magic8Ball()`` to generate answers, and sends messages
+ back to JavaScript with the generated answers. The file is compiled into a
+ .nexe file.
+
+.. TODO(sbc): also mention reverse.{cc,h} files
+
+Run ``make`` in the dlopen directory to see the commands the Makefile executes
+to build x86 32-bit and 64-bit .nexe and .so files, and to generate a .nmf
+file. These commands are described below.
+
+.. Note::
+ :class: note
+
+ **Note:** The Makefiles for most of the examples in the SDK build the
+ examples using multiple toolchains (x86 newlib, x86 glibc, ARM, and PNaCl).
+ With a few exceptions (listed in the :ref:`Release Notes
+ <sdk-release-notes>`), running "make" in each example's directory builds
+ multiple versions of the example using the SDK toolchains. The dlopen example
+ is one of those exceptions – it is only built with the x86 glibc toolchain,
+ as that is currently the only toolchain that supports glibc and thus dynamic
+ linking and loading. Take a look at the example Makefiles and the generated
+ .nmf files for details on how to build dynamically linked applications.
+
+
+Building a Native Client module (.nexe file)
+--------------------------------------------
+
+.. TODO(sbc): there is a lot of redundant detail here. Also the Makefile
+ structure has changed significantly.
+
+The Makefile in the dlopen example builds ``dlopen.cc`` into a .nexe file using
+the two commands shown below. (For simplicity, the full path to the
+compiler/linker is not shown; the tool is located in the bin directory in the
+x86 glibc toolchain, e.g. toolchain/win_x86_glibc/bin.)
+
+To compile dlopen.cc into dlopen_x86_32.o::
+
+ i686-nacl-g++ -o dlopen_x86_32.o -c dlopen.cc -m32 -g -O0 -pthread -std=gnu++98 -Wno-long-long -Wall
+
+To link dlopen_x86_32.o into dlopen_x86_32.nexe::
+
+ i686-nacl-g++ -o dlopen_x86_32.nexe dlopen_x86_32.o -m32 -g -ldl -lppapi_cpp -lppapi
+
+A few of the flags in these commands are described below:
+
+``-o`` *file*
+ put the output in *file*
+
+``-c``
+ compile the source file, but do not link it
+
+``-m32``
+ produce 32-bit code (i.e., code for the x86-32 target architecture)
+
+``-g``
+ produce debugging information
+
+``-O0``
+ use a base optimization level that minimizes compile time
+
+``-pthread``
+ support multithreading with the pthread library
+
+``-W`` *warning*
+ request or supress the specified warning
+
+``-l`` *library*
+ use the specified *library* when linking (per C library naming conventions,
+ the linker uses the file lib*library*.so, or if that file is not available,
+ lib*library*.a; e.g., -ldl corresponds to libdl.so or libdl.a)
+
+Many of these flags are optional; you need not use all of them to compile and
+link your application. For example, you only need to use -ldl if your
+application uses the dlopen() interface to open a library at runtime. The
+toolchains in the Native Client SDK are based on the gcc compiler; see `gcc
+command options <http://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html>`_ for a
+full description of the gcc flags. For flags that are recommended with Native
+Client, see :ref:`compile flags for different development scenarios
+<compile_flags>`.
+
+Note that you can combine the compile and link steps to build a .nexe file
+using one command. Simply run i686-nacl-g++ once and use the appropriate
+combination of flags (omit the -c flag and include the -l flag with the
+required libraries)::
+
+ i686-nacl-g++ -o dlopen_x86_32.nexe dlopen.cc ^ -m32 -g -O0 -pthread -std=gnu++98 -Wno-long-long -Wall -ldl -lppapi_cpp -lppapi
+
+(The carat ``^`` allows the command to span multiple lines on Windows; to do
+the same on Mac and Linux use a backslash instead. Or you can simply type the
+command and all its arguments on one line.)
+
+The commands above build a 32-bit .nexe. To build a 64-bit .nexe, run the same
+commands but with the **-m64** flag instead of -m32, and of course specify
+different output file names. Check the Makefile in the dlopen example to see
+the set of commands that is used to generate 32-bit and 64-bit .nexes.
+
+Building a shared library (.so file)
+------------------------------------
+
+The Makefile in the dlopen example builds eightball.cc into a .so file using
+the two commands shown below.
+
+To compile eightball.cc into eightball_x86_32.o::
+
+ i686-nacl-g++ -o eightball_x86_32.o -c eightball.cc -m32 -g -O0 -pthread -std=gnu++98 -Wno-long-long -Wall -fPIC
+
+To link eightball_x86_32.o into eightball_x86_32.so::
+
+ i686-nacl-g++ -o libeightball.so eightball_x86_32.o -m32 -g -ldl -lppapi_cpp -lppapi -shared
+
+A couple of the important flags in these commands are described below:
+
+``-fPIC``
+ generate position-independent code (PIC) suitable for use in a shared library
+ (this flag is required for all x86 64-bit modules and for 32-bit shared
+ libraries)
+``-shared``
+ produce a shared object that can be linked with other objects to form an
+ executable (this flag is required for .so files)
+ As when building a .nexe, you can combine compiling and linking into one step
+ by running i686-nacl-g++ once with the appropriate combination of flags.
+
+As with .nexes, you need to generate both 32-bit and 64-bit versions of a
+shared object -- see the dlopen example for an illustration. In the dlopen
+example, the shared objects are put into the subdirectories ``lib32`` and
+``lib64``. These directories are used to collect all the shared libraries
+needed by the application, as discussed below.
+
+Generating a Native Client manifest file for a dynamically linked application
+=============================================================================
+
+The Native Client manifest file must specify the full list of executable files
+needed by an application, including the recursive closure of shared library
+dependencies. Take a look at the manifest file in the dlopen example to see how
+a glibc-style manifest file is structured. (Run make in the dlopen directory to
+generate the manifest file if you haven't done so already.) Here is an excerpt
+from ``dlopen.nmf``::
+
+ {
+ "files": {
+ "libeightball.so": {
+ "x86-64": {
+ "url": "lib64/libeightball.so"
+ },
+ "x86-32": {
+ "url": "lib32/libeightball.so"
+ }
+ },
+ "libstdc++.so.6": {
+ "x86-64": {
+ "url": "lib64/libstdc++.so.6"
+ },
+ "x86-32": {
+ "url": "lib32/libstdc++.so.6"
+ }
+ },
+ "libppapi_cpp.so": {
+ "x86-64": {
+ "url": "lib64/libppapi_cpp.so"
+ },
+ "x86-32": {
+ "url": "lib32/libppapi_cpp.so"
+ }
+ },
+ ... etc.
+
+In most cases, you can use the ``create_nmf.py`` script in the SDK to generate
+a manifest file for your application. The script is located in the tools
+directory (e.g., pepper_28/tools).
+
+.. TODO(sbc): running create_nmf.py is much simpler now.
+
+The Makefile in the dlopen example generates the manifest file ``dlopen.nmf``
+by running the following command::
+
+ python <NACL_SDK_ROOT>/tools/create_nmf.py ^
+ -D <NACL_SDK_ROOT>/toolchain/win_x86_glibc/x86_64-nacl/bin/objdump ^
+ -o dlopen.nmf ^
+ -s . ^
+ dlopen_x86_32.nexe dlopen_x86_64.nexe lib32/libeightball.so lib64/libeightball.so ^
+ -L <NACL_SDK_ROOT>/toolchain/win_x86_glibc/x86_64-nacl/lib32 ^
+ -L <NACL_SDK_ROOT>/toolchain/win_x86_glibc/x86_64-nacl/lib64
+
+(The carat ``^`` allows the command to span multiple lines on Windows; to do the
+same on Mac and Linux use a backslash instead, or you can simply type the
+command and all its arguments on one line. *<NACL_SDK_ROOT>* represents the path
+to the top-level directory of the bundle you are using, e.g.,
+*<location-where-you-installed-the-SDK>*/pepper_28.)
+
+
+Run python ``create_nmf.py --help`` to see a description of the command-line
+flags. A few of the important flags are described below.
+
+.. TODO(sbc): remove -D option which is now deprecated.
+
+``-D`` *tool*
+ use *tool* to read information about a file and determine shared library
+ dependencies (the tool must be a version of the `objdump
+ <http://en.wikipedia.org/wiki/Objdump>`_ utility)
+
+``-s`` *directory*
+ use *directory* to stage libraries (libraries are added to ``lib32`` and
+ ``lib64`` subfolders)
+
+``-L`` *directory*
+ add *directory* to the library search path
+
+.. Note::
+ :class: note
+
+ **Caution:** The ``create_nmf.py`` script only recognizes explicit shared
+ library dependencies (for example, dependencies specified with the -l flag
+ for the compiler/linker). The manifest file generated by create_nmf.py will
+ be incorrect in the following situations:
+
+ * You run ``create_nmf.py`` without listing as arguments all the libraries
+ that your application opens with ``dlopen()``.
+
+ * After you run ``create_nmf.py``, you subsequently add a library dependency
+ that is not mentioned in the manifest file.
+
+ * After you run ``create_nmf.py``, you subsequently change the directory
+ structure on your server or in your Chrome Web Store manifest file, such
+ that the needed libraries are no longer in the location specified in the
+ .nmf file
+
+ To handle the above situations correctly, you must re-run ``create_nmf.py``
+ (for example, if you added a new library dependency in your application or
+ changed the application directory structure), and make sure to list all the
+ libraries that your application opens at runtime with ``dlopen()`` (e.g.,
+ libeighball.so in the dlopen example).
+
+.. TODO(sbc): We probably don't want/need this next section in the docs at all.
+
+As an alternative to using ``create_nmf.py``, you can also chase down the full
+list of shared library dependencies manually and add those to your .nmf file.
+To do so, start by running the Native Client version of the objdump utility on
+your .nexe file, as shown below. (The objdump utility is located in the same
+directory as the glibc toolchain, e.g., toolchain/win_x86_glibc/bin.)
+
+::
+
+ i686-nacl-objdump -p dlopen_x86_32.nexe
+
+A .nexe file contains compiled machine code, as well as headers that describe
+the contents of the file and information about how to use the file. The objdump
+utility lets you examine the file's headers, including the "Dynamic Section,"
+which specifies shared library dependencies, as in this example output from the
+dlopen example::
+
+ Dynamic Section:
+ NEEDED libdl.so.32d9fc17
+ NEEDED libppapi_cpp.so
+ NEEDED libpthread.so.32d9fc17
+ NEEDED libstdc++.so.6
+ NEEDED libm.so.32d9fc17
+ NEEDED libgcc_s.so.1
+ NEEDED libc.so.32d9fc17
+ INIT 0x01000140
+ FINI 0x01002560
+ HASH 0x110025fc
+ ...
+
+
+All the files that are identified as NEEDED in the "Dynamic Section" portion of
+the objdump output are files that you need to list in your Native Client
+manifest file and distribute with your application. (The numbers listed at the
+end of the file names are version numbers, and you must list and distribute
+those exact versions.) Once you've identified the shared libraries that are
+needed by your .nexe file, you must repeat the process recursively: Run objdump
+on each of the NEEDED files, and add the newly-identified NEEDED files to your
+manifest file and to your distribution directories. To get the full list of
+libraries for an application, repeat the process until you've identified the
+recursive closure of dependencies.
+
+Deploying a dynamically linked application
+==========================================
+
+As described above, an application's manifest file must explicitly list all the
+executable code modules that the application requires, including modules from
+the application itself (.nexe and .so files), modules from the Native Client
+SDK (e.g., libppapi_cpp.so), and perhaps also modules from `naclports
+<http://code.google.com/p/naclports>`_ or from :doc:`middleware systems
+<../../community/middleware>` that the application uses. You must provide all of
+those modules as part of the application deployment process.
+
+As explained in :doc:`Distributing Your Application
+<../distributing>`, there are two basic ways to deploy an application:
+
+* **hosted application:** all modules are hosted together on a web server of
+ your choice
+
+* **packaged application:** all modules are packaged into one file, hosted in
+ the Chrome Web Store, and downloaded to the user's machine
+
+You must deploy all the modules listed in your application's manifest file for
+either the hosted application or the packaged application case. For hosted
+applications, you must upload the modules to your web server. For packaged
+applications, you must include the modules in the application's Chrome Web
+Store .crx file. Modules should use URLs/names that are consistent with those
+in the Native Client manifest file, and be named relative to the location of
+the manifest file. Remember that some of the libraries named in the manifest
+file may be located in directories you specified with the -L option to
+``create_nmf.py``. You are free to rename/rearrange files and directories
+referenced by the Native Client manifest file, so long as the modules are
+available in the locations indicated by the manifest file. If you move or
+rename modules, it may be easier to re-run create_nmf.py to generate a new
+manifest file rather than edit the original manifest file. For hosted
+applications, you can check for name mismatches during testing by watching the
+request log of the web server hosting your test deployment.
+
+Opening a shared library at runtime
+===================================
+
+Native Client supports a version of the POSIX standard ``dlopen()`` interface
+for opening libraries explicitly, after an application is already running.
+Calling ``dlopen()`` may cause a library download to occur, and automatically
+loads all libraries that are required by the named library.
+
+.. Note::
+ :class: note
+
+ **Caution:** Since ``dlopen()`` can potentially block, you must initially
+ call ``dlopen()`` off your application's main thread. Initial calls to
+ ``dlopen()`` from the main thread will always fail in the current
+ implementation of Native Client.
+
+The best practice for opening libraries with ``dlopen()`` is to use a worker
+thread to pre-load libraries asynchronously during initialization of your
+application, so that the libraries are available when they're needed. You can
+call ``dlopen()`` a second time when you need to use a library -- per the
+specification, subsequent calls to ``dlopen()`` return a handle to the
+previously loaded library. Note that you should only call dlclose() to close a
+library when you no longer need the library; otherwise, subsequent calls to
+``dlopen()`` could cause the library to be fetched again.
+
+The dlopen example in the SDK demonstrates how to open a shared library,
+magiceightball.so, at runtime. To reiterate, the example includes two C++
+files:
+
+.. TODO(sbc): mention the third .cc file which is now part of this example.
+
+* eightball.cc: this is the shared library that implements the function
+ ``Magic8Ball()`` (this file is compiled into libeightball.so)
+* dlopen.cc: this is the Native Client module that loads ``libeightball.so``
+ and calls ``Magic8Ball()`` to generate answers (this file is compiled into
+ dlopen_x86_{32,64}.nexe)
+
+When the Native Client module starts, it kicks off a worker thread that calls
+``dlopen()`` to load magiceightball.so. When the download of
+``libeightball.so`` completes, the worker thread schedules a callback function
+on the main thread. The callback function calls ``dlopen()`` for
+``magiceightball.so`` a second time; this second call obtains a proper handle
+to the library. Once the module has a handle to the library, it grabs the entry
+point in libeightball.so for the ``Magic8Ball()`` function. When a user types
+in a query and clicks the 'ASK!' button, the module calls ``Magic8Ball()`` to
+generate an answer, and returns the result to the user.
+
+The sequence of calls in the dlopen module is illustrated by the pseudo-code in
+the table below:
+
++------------------------------------------------+------------------------------------------+
+| Worker Thread | Main Thread |
++================================================+==========================================+
+| :: | :: |
+| | |
+| pthread_create(.., LoadLibrariesOnWorker, ..)| - |
+| - | LoadLibrariesOnWorker() |
+| - | LoadLibrary() |
+| - | dlopen("libeightball.so",...) |
+| - | CallOnMainThread(.., LoadDone, ..) |
+| LoadDone() | - |
+| UseLibrary() | - |
+| dlopen("libeightball.so", ...) | - |
+| offset = dlsym(..., "Magic8Ball") | - |
+| HandleMessage() | - |
+| _eightball = (TYPE_eightball) offset; | - |
+| PostMessage() | - |
++------------------------------------------------+------------------------------------------+
+
+Troubleshooting
+===============
+
+If your .nexe isn't loading, the best place to look for information that can
+help you troubleshoot the problem is stdout and nacllog. See the Debugging page
+for instructions about how to access those streams.
+
+Here are a few common error messages and explanations of what they mean:
+
+**/main.nexe: error while loading shared libraries: /main.nexe: failed to allocate code and data space for executable**
+ The .nexe may not have been compiled correctly (e.g., the .nexe may be
+ statically linked). Try cleaning and recompiling with the glibc toolchain.
+
+**/main.nexe: error while loading shared libraries: libpthread.so.xxxx: cannot open shared object file: Permission denied**
+ (xxxx is a version number, for example, 5055067a.) This error can result from
+ having the wrong path in the .nmf file. Double-check that the path in the
+ .nmf file is correct.
+
+**/main.nexe: error while loading shared libraries: /main.nexe: cannot open shared object file: No such file or directory**
+ If there are no obvious problems with your main.nexe entry in the .nmf file,
+ check where main.nexe is being requested from. Use Chrome's Developer Tools:
+ Click the menu icon |menu-icon|, select Tools > Developer Tools, click the
+ Network tab, and look at the path in the Name column.
+
+**NaCl module load failed: ELF executable text/rodata segment has wrong starting address**
+ This error happens when using a newlib-style .nmf file instead of a
+ glibc-style .nmf file. Make sure you build your application with the glic
+ toolchain, and use the create_nmf.py script to generate your .nmf file.
+
+**NativeClient: NaCl module load failed: Nexe crashed during startup**
+ This error message indicates that a module crashed while being loaded. You
+ can determine which module crashed by looking at the Network tab in Chrome's
+ Developer Tools (see above). The module that crashed will be the last one
+ that was loaded.
+
+**/lib/main.nexe: error while loading shared libraries: /lib/main.nexe: only ET_DYN and ET_EXEC can be loaded**
+ This error message indicates that there is an error with the .so files listed
+ in the .nmf file -- either the files are the wrong type or kind, or an
+ expected library is missing.
+
+**undefined reference to 'dlopen' collect2: ld returned 1 exit status**
+ This is a linker ordering problem that usually results from improper ordering
+ of command line flags when linking. Reconfigure your command line string to
+ list libraries after the -o flag.
+
+.. |menu-icon| image:: /images/menu-icon.png
diff --git a/native_client_sdk/src/doc/index.rst b/native_client_sdk/src/doc/index.rst
index 750f2b4..84e78bf 100644
--- a/native_client_sdk/src/doc/index.rst
+++ b/native_client_sdk/src/doc/index.rst
@@ -29,4 +29,5 @@ Contents:
devguide/coding/progress-events.rst
devguide/distributing.rst
community/application-gallery.rst
+ community/middleware.rst
peppercpp/index.rst