diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-09-19 22:36:51 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-09-19 22:36:51 +0100 |
commit | d0247b1b59f9c528cb6df88b4f2b9afaf80d181e (patch) | |
tree | 5c397fadc190cc71bffe2ffad1efc27a5b95309d /native_client_sdk | |
parent | f7571f5f07547e2f3e0addf48d1f2a7ec3632957 (diff) | |
download | chromium_org-d0247b1b59f9c528cb6df88b4f2b9afaf80d181e.tar.gz |
Merge from Chromium at DEPS revision 224184
This commit was generated by merge_to_master.py.
Change-Id: Ia3424df5abed9bea642c522b9e2358dceabd8423
Diffstat (limited to 'native_client_sdk')
30 files changed, 1626 insertions, 81 deletions
diff --git a/native_client_sdk/src/build_tools/generate_make.py b/native_client_sdk/src/build_tools/generate_make.py index 2b402d5699..2140642679 100644 --- a/native_client_sdk/src/build_tools/generate_make.py +++ b/native_client_sdk/src/build_tools/generate_make.py @@ -21,7 +21,7 @@ Trace.verbose = False def IsExample(desc): dest = desc['DEST'] - return dest.startswith('examples') or dest.startswith('tests') + return dest.startswith(('examples', 'tests', 'getting_started')) def GenerateSourceCopyList(desc): @@ -39,7 +39,9 @@ def GenerateSourceCopyList(desc): sources.extend(desc.get('DATA', [])) if IsExample(desc): - sources.extend(['common.js', 'icon128.png', 'background.js']) + sources.append('common.js') + if not desc.get('NO_PACKAGE_FILES'): + sources.extend(['icon128.png', 'background.js']) return sources @@ -235,7 +237,8 @@ def ProcessProject(pepperdir, srcroot, dstroot, desc, toolchains, configs=None, if IsExample(desc): ProcessHTML(srcroot, dstroot, desc, toolchains, configs, first_toolchain) - GenerateManifest(srcroot, dstroot, desc) + if not desc.get('NO_PACKAGE_FILES'): + GenerateManifest(srcroot, dstroot, desc) return (name, desc['DEST']) diff --git a/native_client_sdk/src/build_tools/parse_dsc.py b/native_client_sdk/src/build_tools/parse_dsc.py index 848e74d973..bf18d5710f 100755 --- a/native_client_sdk/src/build_tools/parse_dsc.py +++ b/native_client_sdk/src/build_tools/parse_dsc.py @@ -15,7 +15,11 @@ VALID_TOOLCHAINS = ['newlib', 'glibc', 'pnacl', 'win', 'linux', 'mac'] DSC_FORMAT = { 'DISABLE': (bool, [True, False], False), 'SEL_LDR': (bool, [True, False], False), + # Disable this project from being included in the NaCl packaged app. 'DISABLE_PACKAGE': (bool, [True, False], False), + # Don't generate the additional files to allow this project to run as a + # packaged app (i.e. manifest.json, background.js, etc.). + 'NO_PACKAGE_FILES': (bool, [True, False], False), 'TOOLS' : (list, VALID_TOOLCHAINS, True), 'CONFIGS' : (list, ['Debug', 'Release'], False), 'PREREQ' : (list, '', False), diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list index 91bddbb93d..b42123d9b0 100644 --- a/native_client_sdk/src/build_tools/sdk_files.list +++ b/native_client_sdk/src/build_tools/sdk_files.list @@ -41,6 +41,7 @@ examples/tutorial/using_ppapi_simple/* [win]getting_started/make.bat getting_started/Makefile getting_started/part1/* +getting_started/part2/* include/error_handling/* include/GLES2/* include/gmock/* diff --git a/native_client_sdk/src/build_tools/test_sdk.py b/native_client_sdk/src/build_tools/test_sdk.py index 6adce2fcef..cf5db614b5 100755 --- a/native_client_sdk/src/build_tools/test_sdk.py +++ b/native_client_sdk/src/build_tools/test_sdk.py @@ -30,11 +30,11 @@ sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) import getos def StepBuildExamples(pepperdir): - build_sdk.BuildStepMakeAll(pepperdir, 'getting_started', - 'Build Getting Started', - deps=False, config='Release') - for config in ('Debug', 'Release'): + build_sdk.BuildStepMakeAll(pepperdir, 'getting_started', + 'Build Getting Started (%s)' % config, + deps=False, config=config) + build_sdk.BuildStepMakeAll(pepperdir, 'examples', 'Build Examples (%s)' % config, deps=False, config=config) diff --git a/native_client_sdk/src/doc/_sphinxext/devsite_builder.py b/native_client_sdk/src/doc/_sphinxext/devsite_builder.py index dc881bceb3..461c606554 100644 --- a/native_client_sdk/src/doc/_sphinxext/devsite_builder.py +++ b/native_client_sdk/src/doc/_sphinxext/devsite_builder.py @@ -61,6 +61,11 @@ class DevsiteHTMLTranslator(HTMLTranslator): Hooked into the HTML builder by setting the html_translator_class option in conf.py + + HTMLTranslator is provided by Sphinx. It's a subclass of the + HTMLTranslator provided by docutils, with Sphinx-specific features added. + Here we provide devsite-specific behavior by overriding some of the + visiting methods. """ def __init__(self, builder, *args, **kwds): # HTMLTranslator is an old-style Python class, so 'super' doesn't work: use @@ -85,6 +90,17 @@ class DevsiteHTMLTranslator(HTMLTranslator): # Override to not pop anything from context self.body.append('</ul>\n') + def visit_literal(self, node): + # Sphinx emits <tt></tt> for literals (``like this``), with <span> per word + # to protect against wrapping, etc. We're required to emit plain <code> + # tags for them. + # Emit a simple <code> tag without enabling "protect_literal_text" mode, + # so Sphinx's visit_Text doesn't mess with the contents. + self.body.append(self.starttag(node, 'code', suffix='')) + + def depart_literal(self, node): + self.body.append('</code>') + def visit_literal_block(self, node): # We don't use Sphinx's buildin pygments integration for code highlighting, # because the devsite requires special <pre> tags for that and handles the 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 0000000000..9a02f13fc9 --- /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 c79185085e..fd5a06d662 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,269 @@ Application Structure ##################### -foo +.. contents:: + :local: + :backlinks: none + :depth: 2 +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 :doc:`Technical Overview <../../overview>`. + + +.. Note:: + :class: note + + 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 +<https://chrome.google.com/webstore/search?q=%22Native+Client%22+OR+NativeClient+OR+NaCl>`_ +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: + +.. naclcode:: + + <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_file: + +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 :doc:`Distributing Your +Application <../distributing>`. and the `Chrome Web Store manifest file format +<http://code.google.com/chrome/extensions/manifest.html>`_. + +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 +:ref:`newlib<c_libraries>` C library: + +.. naclcode:: + + { + "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 <http://www.json.org/>`_ 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 :ref:`glibc<c_libraries>` +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 +:doc:`Dynamic Linking and Loading with glibc<../devcycle/dynamic-loading>`. 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: + +.. naclcode:: + + 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: + +.. naclcode:: + + 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: + +.. naclcode:: + + 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 +: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 chapters in the +Developer's Guide build on these code samples and add more interesting +functionality. + + +Threading +========= + +.. FIXME: link to pp:Core page for CallOnMainThread. But this is no longer + true anyway... + +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. diff --git a/native_client_sdk/src/doc/devguide/coding/message-system.rst b/native_client_sdk/src/doc/devguide/coding/message-system.rst index 6120254b41..14d52fc05d 100644 --- a/native_client_sdk/src/doc/devguide/coding/message-system.rst +++ b/native_client_sdk/src/doc/devguide/coding/message-system.rst @@ -1,5 +1,381 @@ -############## -Message System -############## +.. _messaging_system: -foo +################ +Messaging System +################ + +.. contents:: + :local: + :backlinks: none + :depth: 2 + +This chapter describes the messaging system used to communicate between the +JavaScript code and the Native Client module's C or C++ code in a +Native Client application. It introduces the concept of asynchronous +programming and the basic steps required to set up a Native Client module +that sends messages to and receive messages from JavaScript. This chapter +assumes you are familiar with the material presented in the +:doc:`Application Structure <application-structure>` chapter. + +.. Note:: + :class: note + + The "Hello, World" example for getting started with NaCl is used here to + illustrate basic programming techniques. You can find this code in + the ``/getting_started/part2`` directory in the Native Client SDK download. + +Reference information +===================== + +For reference information related to the Pepper messaging API, see the +following documentation: + +* `pp::Instance class <https://developers.google.com/native-client/peppercpp/classpp_1_1_instance>`_ HandleMessage(), PostMessage()) +* `pp::Module class <https://developers.google.com/native-client/peppercpp/classpp_1_1_module>`_ +* `pp::Var class <https://developers.google.com/native-client/peppercpp/classpp_1_1_var>`_ + + +Glossary +======== + +asynchronous programming + In the asynchronous programming model, function calls are executed and + return immediately without waiting for a response. Using this model, + functions are nonblocking; the web browser continues processing JavaScript + and C/C++ functions. +Var + An object in a Native Client module that corresponds to a JavaScript + variable. +web workers + `Web workers <http://en.wikipedia.org/wiki/Web_Workers>`_ provide a + mechanism for running heavy-weight JavaScript code on background threads + so that the main web page can continue to respond to user interaction. + Web pages interact with web workers by using ``postMessage()`` to send + messages. The way a web page interacts with a Native Client module + is analogous to the way it interacts with web workers. + + +Introduction to the messaging system +==================================== + +Native Client modules and JavaScript communicate by sending messages +to each other. The most basic form of a message is a string. Messages +support many JavaScript types, including ints, arrays, array buffers, +and dictionaries (see `pp::Var +<https://developers.google.com/native-client/peppercpp/classpp_1_1_var>`_, +`pp:VarArrayBuffer +<https://developers.google.com/native-client/peppercpp/classpp_1_1_var_array_buffer>`_, +and the general `messaging system documentation +<https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0>`_). +It's up to you to decide on the type of message and define how to +process the messages on both the JavaScript and Native Client +side. For the "Hello, World" example, we will work with string-typed +messages only. + +When JavaScript posts a message to the Native Client module, the +Pepper ``HandleMessage()`` function is invoked on the module +side. Similarly, the Native Client module can post a message to +JavaScript, and this message triggers a JavaScript event listener for +``message`` events in the DOM. (See the W3C specification on +`Document Object Model Events +<http://www.w3.org/TR/DOM-Level-2-Events/events.html>`_ for more +information.) In the "Hello, World" example, the JavaScript functions for +posting and handling messages are named ``postMessage()`` and +``handleMessage()`` (but any names could be used). On the Native Client +C++ side, the Pepper Library functions for posting and handling +messages are: + +* ``void pp::Instance::PostMessage(const Var &message)`` +* ``virtual void pp::Instance::HandleMessage(const Var &message)`` + +If you want to receive messages from JavaScript, you need to implement the +``pp::Instance::HandleMessage()`` function in your Native Client module. + +Design of the messaging system +------------------------------ + +The Native Client messaging system is analogous to the system used by +the browser to allow web workers to communicate (see the `W3 web +worker specification <http://www.w3.org/TR/workers>`_). The Native +Client messaging system is designed to keep the web page responsive while the +Native Client module is performing potentially heavy processing in the +background. When JavaScript sends a message to the Native Client +module, the ``postMessage()`` call returns as soon as it sends its message +to the Native Client module. The JavaScript does not wait for a reply +from Native Client, thus avoiding bogging down the main JavaScript +thread. On the JavaScript side, you set up an event listener to +respond to the message sent by the Native Client module when it has +finished the requested processing and returns a message. + +This asynchronous processing model keeps the main thread free while +avoiding the following problems: + +* The JavaScript engine hangs while waiting for a synchronous call to return. +* The browser pops up a dialog when a JavaScript entry point takes longer + than a few moments. +* The application hangs while waiting for an unresponsive Native Client module. + +Communication tasks in the "Hello, World" example +================================================= + +The following sections describe how the "Hello, World" example posts +and handles messages on both the JavaScript side and the Native Client +side of the application. + +JavaScript code +--------------- + +The JavaScript code and HTML in the "Hello, World" example can be +found in the ``example.js``, ``common.js``, and ``index.html`` files. +The important steps are: + +#. Sets up an event listener to listen for ``message`` events from the + Native Client module. +#. Implements an event handler that the event listener invokes to handle + incoming ``message`` events. +#. Calls ``postMessage()`` to communicate with the NaCl module, + after the page loads. + +Step 1: From common.js +^^^^^^^^^^^^^^^^^^^^^^ + +.. naclcode:: + + function attachDefaultListeners() { + // The NaCl module embed is created within the listenerDiv + var listenerDiv = document.getElementById('listener'); + // ... + + // register the handleMessage function as the message event handler. + listenerDiv.addEventListener('message', handleMessage, true); + // ... + } + + +Step 2: From example.js +^^^^^^^^^^^^^^^^^^^^^^^ + +.. naclcode:: + + // This function is called by common.js when a message is received from the + // NaCl module. + function handleMessage(message) { + // In the example, we simply log the data that's received in the message. + var logEl = document.getElementById('log'); + logEl.textContent += message.data; + } + + // In the index.html we have set up the appropriate divs: + <body {{attrs}}> + <!-- ... --> + <div id="listener"></div> + <div id="log"></div> + </body> + + +Step 3: From example.js +^^^^^^^^^^^^^^^^^^^^^^^ + +.. naclcode:: + + // From example.js, Step 3: + function moduleDidLoad() { + // After the NaCl module has loaded, common.naclModule is a reference to the + // NaCl module's <embed> element. + // + // postMessage sends a message to it. + common.naclModule.postMessage('hello'); + } + + +Native Client module +-------------------- + +The C++ code in the Native Client module of the "Hello, World" example: + +#. Implements ``pp::Instance::HandleMessage()`` to handle messages sent + by the JavaScript. +#. Processes incoming messages. This example simply checks that JavaScript + has sent a "hello" message and not some other message. +#. Calls ``PostMessage()`` to send an acknowledgement back to the + JavaScript code. The acknowledgement is a string in the form of a ``Var`` + that the JavaScript code can process. In general, a ``pp::Var`` can be + several JavaScript types, see the + `messaging system documentation + <https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0>`_. + + +.. naclcode:: + + class HelloTutorialInstance : public pp::Instance { + public: + // ... + + // === Step 1: Implement the HandleMessage function. === + virtual void HandleMessage(const pp::Var& var_message) { + + // === Step 2: Process the incoming message. === + // Ignore the message if it is not a string. + if (!var_message.is_string()) + return; + + // Get the string message and compare it to "hello". + std::string message = var_message.AsString(); + if (message == kHelloString) { + // === Step 3: Send the reply. === + // If it matches, send our response back to JavaScript. + pp::Var var_reply(kReplyString); + PostMessage(var_reply); + } + } + }; + + +Messaging in JavaScript code: More details. +=========================================== + +This section describes in more detail the messaging system code in the +JavaScript portion of the "Hello, World" example. + +Setting up an event listener and handler +---------------------------------------- + +The following JavaScript code sets up an event listener for messages +posted by the Native Client module. It then defines a message handler +that simply logs the content of messages received from the module. + +Setting up the 'message' handler on load +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. naclcode:: + + // From common.js + + // Listen for the DOM content to be loaded. This event is fired when + // parsing of the page's document has finished. + document.addEventListener('DOMContentLoaded', function() { + var body = document.body; + // ... + var loadFunction = common.domContentLoaded; + // ... set up parameters ... + loadFunction(...); + } + + // This function is exported as common.domContentLoaded. + function domContentLoaded(...) { + // ... + if (common.naclModule == null) { + // ... + attachDefaultListeners(); + // initialize common.naclModule ... + } else { + // ... + } + } + + function attachDefaultListeners() { + var listenerDiv = document.getElementById('listener'); + // ... + listenerDiv.addEventListener('message', handleMessage, true); + // ... + } + + +Implementing the handler +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. naclcode:: + + // From example.js + function handleMessage(message) { + var logEl = document.getElementById('log'); + logEl.textContent += message.data; + } + + +Note that the ``handleMessage()`` function is handed a message_event +containing ``data`` that you can display or manipulate in JavaScript. The +"Hello, World" application simply logs this data to the ``log`` div. + + +Messaging in the Native Client module: More details. +==================================================== + +This section describes in more detail the messaging system code in +the Native Client module portion of the "Hello, World" example. + +Implementing HandleMessage() +---------------------------- + +If you want the Native Client module to receive and handle messages +from JavaScript, you need to implement a ``HandleMessage()`` function +for your module's ``pp::Instance`` class. The +``HelloWorldInstance::HandleMessage()`` function examines the message +posted from JavaScript. First it examines that the type of the +``pp::Var`` is indeed a string (not a double, etc.). It then +interprets the data as a string with ``var_message.AsString()``, and +checks that the string matches ``kHelloString``. After examining the +message received from JavaScript, the code calls ``PostMessage()`` to +send a reply message back to the JavaScript side. + +.. naclcode:: + + namespace { + + // The expected string sent by the JavaScript. + const char* const kHelloString = "hello"; + // The string sent back to the JavaScript code upon receipt of a message + // containing "hello". + const char* const kReplyString = "hello from NaCl"; + + } // namespace + + class HelloTutorialInstance : public pp::Instance { + public: + // ... + virtual void HandleMessage(const pp::Var& var_message) { + // Ignore the message if it is not a string. + if (!var_message.is_string()) + return; + + // Get the string message and compare it to "hello". + std::string message = var_message.AsString(); + if (message == kHelloString) { + // If it matches, send our response back to JavaScript. + pp::Var var_reply(kReplyString); + PostMessage(var_reply); + } + } + }; + + +Implementing application-specific functions +------------------------------------------- + +While the "Hello, World" example is very simple, your Native Client +module will likely include application-specific functions to perform +custom tasks in response to messages. For example the application +could be a compression and decompression service (two functions +exported). The application could set up an application-specific +convention that messages coming from JavaScript are colon-separated +pairs of the form ``<command>:<data>``. The Native Client module +message handler can then split the incoming string along the ``:`` +character to determine which command to execute. If the command is +"compress", then data to process is an uncompressed string. If the +command is "uncompress", then data to process is an already-compressed +string. After processing the data asynchronously, the application then +returns the result to JavaScript. + + +Sending messages back to the JavaScript code +-------------------------------------------- + +The Native Client module sends messages back to the JavaScript code +using ``PostMessage()``. The Native Client module always returns +its values in the form of a ``pp::Var`` that can be processed by the +browser's JavaScript. In this example, the message is posted at the +end of the Native Client module's ``HandleMessage()`` function: + +.. naclcode:: + + PostMessage(var_reply); diff --git a/native_client_sdk/src/doc/devguide/devcycle/building.rst b/native_client_sdk/src/doc/devguide/devcycle/building.rst index 413d6b0d81..48cca76693 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 a5f7e5ec11..c19fa8244a 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/devguide/tutorial.rst b/native_client_sdk/src/doc/devguide/tutorial.rst index d9976afd90..c636941b4b 100644 --- a/native_client_sdk/src/doc/devguide/tutorial.rst +++ b/native_client_sdk/src/doc/devguide/tutorial.rst @@ -369,7 +369,7 @@ Look for the JavaScript function ``moduleDidLoad()``, and add the new code below (indicated by boldface type) to send a 'hello' message to the Native Client module: -..naclcode:: +.. naclcode:: function moduleDidLoad() { HelloTutorialModule = document.getElementById('hello_tutorial'); diff --git a/native_client_sdk/src/doc/images/postmessage.png b/native_client_sdk/src/doc/images/postmessage.png Binary files differdeleted file mode 100644 index e32876773c..0000000000 --- a/native_client_sdk/src/doc/images/postmessage.png +++ /dev/null diff --git a/native_client_sdk/src/doc/images/postmessage2.png b/native_client_sdk/src/doc/images/postmessage2.png Binary files differdeleted file mode 100644 index e26ec91667..0000000000 --- a/native_client_sdk/src/doc/images/postmessage2.png +++ /dev/null diff --git a/native_client_sdk/src/doc/index.rst b/native_client_sdk/src/doc/index.rst index 43fea41e76..84e78bf936 100644 --- a/native_client_sdk/src/doc/index.rst +++ b/native_client_sdk/src/doc/index.rst @@ -9,6 +9,7 @@ Contents: rest-devsite-examples.rst overview.rst quick-start.rst + nacl-and-pnacl.rst sdk/download.rst sdk/examples.rst sdk/index.rst @@ -28,4 +29,5 @@ Contents: devguide/coding/progress-events.rst devguide/distributing.rst community/application-gallery.rst + community/middleware.rst peppercpp/index.rst diff --git a/native_client_sdk/src/doc/nacl-and-pnacl.rst b/native_client_sdk/src/doc/nacl-and-pnacl.rst new file mode 100644 index 0000000000..3881297675 --- /dev/null +++ b/native_client_sdk/src/doc/nacl-and-pnacl.rst @@ -0,0 +1,100 @@ +.. _nacl-and-pnacl: + +############## +NaCl and PNaCl +############## + +Introduction and historical background +====================================== + +Since its initial launch in 2011, Native Client enables executing native code +securely inside a web application through the use of advanced Software Fault +Isolation (SFI) techniques. TODO: link to paper?. Native Client provides +developers with the ability to harness the client machine's computational power +to a much fuller extent than traditional web technologies, by running compiled C +and C++ code at near-native speeds and taking advantage of multiple cores with +shared memory. + +While Native Client provides OS independence, it still requires developers to +generate architecture-specific executable modules (**nexe**) for each hardware +platform. In addition to being inconvenient for the developer, +architecture-specific machine code is non-portable and not well suited to the +open web. The traditional method of application distribution on the web is a +self-contained bundle of HTML, CSS, JavaScript and resources (images, etc.) that +can be hosted on a server and run inside a web browser. This means that a +website created today should still work, on all platforms, years later. +Architecture-specific executables are clearly not a good fit for this +requirement. + +Therefore, today Native Client can only be used in applications and browser +extensions that are installed through the Chrome Web Store. Exposing Native +Client to the open web was deemed unacceptable as long as the technology is not +fully portable. + +PNaCl +===== + +PNaCl addresses the portability concern by splitting the compilation process +into two parts: compiling the source code to a portable bitcode format, and +translating this format to a host-specific executable. PNaCl enables developers +to distribute *portable executables* (**pexe**-s) that the hosting environment +(e.g. the Chrome browser) can translate to native code before executing. This +aligns Native Client with existing open web technologies like JavaScript. The +developer can simply distribute a **pexe** as part of an application along with +HTML, CSS and JavaScript, and the user's machine will be able to run it. In +other words, PNaCl combines the portability of existing web technologies with +the performance and security benefits of Native Client. + +With PNaCl, the developer generates a single **pexe** from his source code, +instead of a platform-specific **nexe** per architecture. The **pexe** provides +both architecture- and OS-independence. Since the **pexe** contains an abstract, +architecture-independent format, it does not have the portability problem +described in the previous section. Future versions of the hosting environment +should have no problem executing the **pexe**, even on new architectures. +Moreover, if an existing architecture is enhanced in the future, the developer's +code doesn't even have to be recompiled---in some cases the client-side +translation will be able to take advantage of the new capabilities +automatically. + +With the advent of PNaCl, the distribution limitations of Native Client can be +lifted. Specifically, a **pexe** can simply be part of a web application---it +does not have to be distributed through the Chrome Web Store. + +PNaCl is a new technology, so it still has a number of minor limitations when +compared to existing, non-portable Native Client; the next sections describe the +differences in detail. + +When to use PNaCl? +================== + +PNaCl is the preferred toolchain for Native Client and the only way to deploy +Native Client modules on the open web. Unless your project is considerably +limited by one of the factors described in the next section, use PNaCl. + +Beginning with version 31, the Chrome web browser supports translation of +**pexe** modules and their usage in web applications, without requiring the user +to install the application explicitly or install any browser plugins. Native +Client and PNaCl are open-source technologies, and our hope is that they will be +added to other hosting platforms in the future. + +When to use non-portable NaCl +============================= + +If controlled distribution through the web store is an important part of your +product plan, the benefits of PNaCl are less important. However, note that it's +still possible to use the PNaCl toolchain for distributing applications through +the web store, and enjoy conveniences such as not needing to explicitly compile +the application for all supported architectures. + +In addition, the following limitations apply to the initial release of PNaCl. If +any of these are critical for your application, use non-portable Native Client: + +* By its nature, PNaCl does not support architecture-specific instructions in + the application (*inline assembly*). Future editions of PNaCl will attempt to + mitigate this problem by introducing portable intrinsics for vector + operations. +* PNaCl only supports static linking with the ``newlib`` C standard library at + this time (a PNaCl port is provided by the NaCl SDK). Dynamic linking and + ``glibc`` are not supported. Work is under way to enable dynamic linking in + future versions of PNaCl. +* In the initial release, PNaCl does not support C++ exception handling. diff --git a/native_client_sdk/src/doc/rest-devsite-examples.rst b/native_client_sdk/src/doc/rest-devsite-examples.rst index 304f972cdb..325993c7b1 100644 --- a/native_client_sdk/src/doc/rest-devsite-examples.rst +++ b/native_client_sdk/src/doc/rest-devsite-examples.rst @@ -78,6 +78,24 @@ To external locations Plain links can be placed like this: http://google.com and also `like this <http://google.com>`_. +Definition lists +================ + +Can be used to define a group of related terms. Internal formatting is supported +within the definition. No special formatting needs to be done for the definition +name/title - it's handled by the devsite. + +Apple + The apple is the pomaceous fruit of the apple tree, species Malus domestica in + the rose family (**Rosaceae**). +Fig + The common fig (**Ficus carica**) is a species of flowering plant in the genus + Ficus, from the family Moraceae, known as the common fig (or just the fig), + anjeer (Iran, Pakistan), and dumur (Bengali). +Pear + The pear is any of several tree and shrub species of genus Pyrus /ˈpaɪrəs/, in + the family Rosaceae. + Notes and Admonitions ===================== @@ -126,6 +144,9 @@ For some code (like shell samples), we want to disable pretty-printing: By default ``:prettyprint:`` is ``1``. +For short inline code, use fixed-formatting like ``int x = 2;``. Note that this +won't get syntax-highlighted and may be line-wrapped, so keep it very short. + .. _link_for_section_heading: Section heading diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.dsc b/native_client_sdk/src/examples/demo/nacl_io/example.dsc index 4d1cf02770..65bb304366 100644 --- a/native_client_sdk/src/examples/demo/nacl_io/example.dsc +++ b/native_client_sdk/src/examples/demo/nacl_io/example.dsc @@ -21,7 +21,7 @@ ], 'DEST': 'examples/demo', 'NAME': 'nacl_io', - 'TITLE': 'Nacl IO Demo', + 'TITLE': 'NaCl IO Demo', 'GROUP': 'Demo', 'PERMISSIONS': [ 'unlimitedStorage' diff --git a/native_client_sdk/src/getting_started/part1/hello_tutorial.cc b/native_client_sdk/src/getting_started/part1/hello_tutorial.cc index ed69d51543..6f72e0c0eb 100644 --- a/native_client_sdk/src/getting_started/part1/hello_tutorial.cc +++ b/native_client_sdk/src/getting_started/part1/hello_tutorial.cc @@ -9,7 +9,7 @@ /// CreateModule() once to load the module code. After the code is loaded, /// CreateModule() is not called again. /// -/// Once the code is loaded, the browser than calls the CreateInstance() +/// Once the code is loaded, the browser calls the CreateInstance() /// method on the object returned by CreateModule(). It calls CreateInstance() /// each time it encounters an <embed> tag that references your NaCl module. /// @@ -32,8 +32,8 @@ /// module on the web page. The browser will ask the Module object to create /// a new Instance for each occurrence of the <embed> tag that has these /// attributes: -/// type="application/x-pnacl" /// src="hello_tutorial.nmf" +/// type="application/x-pnacl" /// To communicate with the browser, you must override HandleMessage() to /// receive messages from the browser, and use PostMessage() to send messages /// back to the browser. Note that this interface is asynchronous. @@ -46,15 +46,8 @@ class HelloTutorialInstance : public pp::Instance { virtual ~HelloTutorialInstance() {} /// Handler for messages coming in from the browser via postMessage(). The - /// @a var_message can contain anything: a JSON string; a string that encodes - /// method names and arguments; etc. For example, you could use - /// JSON.stringify in the browser to create a message that contains a method - /// name and some parameters, something like this: - /// var json_message = JSON.stringify({ "myMethod" : "3.14159" }); - /// nacl_module.postMessage(json_message); - /// On receipt of this message in @a var_message, you could parse the JSON to - /// retrieve the method name, match it to a function call, and then call it - /// with the parameter. + /// @a var_message can contain be any pp:Var type; for example int, string + /// Array or Dictinary. Please see the pp:Var documentation for more details. /// @param[in] var_message The message posted by the browser. virtual void HandleMessage(const pp::Var& var_message) { // TODO(sdk_user): 1. Make this function handle the incoming message. @@ -63,7 +56,7 @@ class HelloTutorialInstance : public pp::Instance { /// The Module class. The browser calls the CreateInstance() method to create /// an instance of your NaCl module on the web page. The browser creates a new -/// instance for each <embed> tag with type="application/x-nacl". +/// instance for each <embed> tag with type="application/x-pnacl". class HelloTutorialModule : public pp::Module { public: HelloTutorialModule() : pp::Module() {} diff --git a/native_client_sdk/src/getting_started/part1/index.html b/native_client_sdk/src/getting_started/part1/index.html index c3c76cf7cd..d4af2bbece 100644 --- a/native_client_sdk/src/getting_started/part1/index.html +++ b/native_client_sdk/src/getting_started/part1/index.html @@ -2,7 +2,7 @@ <html> <!-- - Copyright (c) 2012 The Native Client Authors. All rights reserved. + Copyright (c) 2013 The Native Client Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> @@ -52,7 +52,7 @@ function updateStatus(opt_message) { if (opt_message) statusText = opt_message; - var statusField = document.getElementById('status_field'); + var statusField = document.getElementById('statusField'); if (statusField) { statusField.innerHTML = statusText; } @@ -61,42 +61,35 @@ </head> <body onload="pageDidLoad()"> -<h1>Native Client Module HelloTutorial</h1> -<p> - <!-- TODO(eliben): PNaCl-ize: - Load the published .nexe. This includes the 'nacl' attribute which - shows how to load multi-architecture modules. Each entry in the "nexes" - object in the .nmf manifest file is a key-value pair: the key is the - instruction set architecture ('x86-32', 'x86-64', etc.); the value is a URL - for the desired NaCl module. + <h1>NaCl C++ Tutorial: Getting Started</h1> + <p> + <!-- + Load the published pexe. + Note: Since this module does not use any real-estate in the browser, its + width and height are set to 0. - Note: Since this NaCl module does not use any real-estate in the browser, - it's width and height are set to 0. + Note: The <embed> element is wrapped inside a <div>, which has both a 'load' + and a 'message' event listener attached. This wrapping method is used + instead of attaching the event listeners directly to the <embed> element to + ensure that the listeners are active before the NaCl module 'load' event + fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or + pp::Instance.PostMessage() (in C++) from within the initialization code in + your module. + --> + <div id="listener"> + <script type="text/javascript"> + var listener = document.getElementById('listener'); + listener.addEventListener('load', moduleDidLoad, true); + listener.addEventListener('message', handleMessage, true); + </script> - Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load' - and a 'message' event listener attached. This wrapping method is used - instead of attaching the event listeners directly to the <EMBED> element to - ensure that the listeners are active before the NaCl module 'load' event - fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or - pp::Instance.PostMessage() (in C++) from within the initialization code in - your NaCl module. - --> - <div id="listener"> - <script type="text/javascript"> - var listener = document.getElementById('listener'); - listener.addEventListener('load', moduleDidLoad, true); - listener.addEventListener('message', handleMessage, true); - </script> - - <embed - id="hello_tutorial" - width=0 height=0 - src="hello_tutorial.nmf" - type="application/x-pnacl" /> - </div> -</p> + <embed id="hello_tutorial" + width=0 height=0 + src="hello_tutorial.nmf" + type="application/x-pnacl" /> + </div> + </p> -<h2>Status</h2> -<div id="status_field">NO-STATUS</div> + <h2>Status <code id="statusField">NO-STATUS</code></h2> </body> </html> diff --git a/native_client_sdk/src/getting_started/part2/README b/native_client_sdk/src/getting_started/part2/README new file mode 100644 index 0000000000..96c97716f9 --- /dev/null +++ b/native_client_sdk/src/getting_started/part2/README @@ -0,0 +1,23 @@ +====================================== +C++ Tutorial: Getting Started (Part 2) +====================================== + +Please see the online documentation here: + + https://developers.google.com/native-client/devguide/tutorial + + +Part 2 of the tutorial is the same as part 1, except: + +* The SDK build system is now used. This simplifies supporting multiple NaCl + toolchains (e.g. PNaCl, newlib, GLibC). See $NACL_SDK_ROOT/README.Makefiles + for more information about the SDK Build system. + +* The example loads common.js, a JavaScript file that has common code used in + all of the SDK examples. + +* index.html has been simplified, and all JavaScript code has been moved to + separate .js files. This makes the example Content Security Policy + (CSP)-compliant. See + http://developer.chrome.com/apps/contentSecurityPolicy.html for more details. + CSP-compliance is required for Chrome Packaged apps. diff --git a/native_client_sdk/src/getting_started/part2/example.dsc b/native_client_sdk/src/getting_started/part2/example.dsc new file mode 100644 index 0000000000..9e10783cd6 --- /dev/null +++ b/native_client_sdk/src/getting_started/part2/example.dsc @@ -0,0 +1,20 @@ +{ + 'TOOLS': ['newlib', 'glibc', 'pnacl', 'win', 'linux'], + # Don't copy the packaged app files: manifest.json, etc. + 'NO_PACKAGE_FILES': True, + 'TARGETS': [ + { + 'NAME': 'part2', + 'TYPE': 'main', + 'SOURCES': ['hello_tutorial.cc'], + 'LIBS': ['ppapi_cpp', 'ppapi', 'pthread'], + } + ], + 'DATA': [ + 'example.js' + ], + 'DEST': 'getting_started', + 'NAME': 'part2', + 'TITLE': 'Getting Started: Part 2', + 'GROUP': 'Getting Started', +} diff --git a/native_client_sdk/src/getting_started/part2/example.js b/native_client_sdk/src/getting_started/part2/example.js new file mode 100644 index 0000000000..7a392a2c62 --- /dev/null +++ b/native_client_sdk/src/getting_started/part2/example.js @@ -0,0 +1,24 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This function is called by common.js when the NaCl module is +// loaded. +function moduleDidLoad() { + // Once we load, hide the plugin. In this example, we don't display anything + // in the plugin, so it is fine to hide it. + common.hideModule(); + + // After the NaCl module has loaded, common.naclModule is a reference to the + // NaCl module's <embed> element. + // + // postMessage sends a message to it. + common.naclModule.postMessage('hello'); +} + +// This function is called by common.js when a message is received from the +// NaCl module. +function handleMessage(message) { + var logEl = document.getElementById('log'); + logEl.textContent += message.data; +} diff --git a/native_client_sdk/src/getting_started/part2/hello_tutorial.cc b/native_client_sdk/src/getting_started/part2/hello_tutorial.cc new file mode 100644 index 0000000000..5261a06e46 --- /dev/null +++ b/native_client_sdk/src/getting_started/part2/hello_tutorial.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/var.h" + +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 + +class HelloTutorialInstance : public pp::Instance { + public: + explicit HelloTutorialInstance(PP_Instance instance) + : pp::Instance(instance) {} + virtual ~HelloTutorialInstance() {} + + virtual void HandleMessage(const pp::Var& var_message) { + // Ignore the message if it is not a string. + if (!var_message.is_string()) + return; + + // Get the string message and compare it to "hello". + std::string message = var_message.AsString(); + if (message == kHelloString) { + // If it matches, send our response back to JavaScript. + pp::Var var_reply(kReplyString); + PostMessage(var_reply); + } + } +}; + +class HelloTutorialModule : public pp::Module { + public: + HelloTutorialModule() : pp::Module() {} + virtual ~HelloTutorialModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new HelloTutorialInstance(instance); + } +}; + +namespace pp { + +Module* CreateModule() { + return new HelloTutorialModule(); +} + +} // namespace pp diff --git a/native_client_sdk/src/getting_started/part2/index.html b/native_client_sdk/src/getting_started/part2/index.html new file mode 100644 index 0000000000..2dd2f500a8 --- /dev/null +++ b/native_client_sdk/src/getting_started/part2/index.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright (c) 2013 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + <meta http-equiv="Pragma" content="no-cache"> + <meta http-equiv="Expires" content="-1"> + <title>{{title}}</title> + <script type="text/javascript" src="common.js"></script> + <script type="text/javascript" src="example.js"></script> +</head> +<!-- +For the SDK examples, we support several toolchains (e.g. PNaCl, newlib, +GLibC). In your own code, you'll likely just choose one toolchain (probably +PNaCl), and load that directly. + +Rather than have each example repeat the same module loading code for each +toolchain it supports, we set custom data attributes on the body. Those +attributes are read by common.js to determine which toolchains are supported +for the example. +--> +<body {{attrs}}> + <h1>{{title}}</h1> + <h2>Status: <code id="statusField">NO-STATUS</code></h2> + <!-- + Just as in part1, the <embed> element will be wrapped inside the <div> + element with the id "listener". In part1, the embed was specified in HTML, + here the common.js module creates a new <embed> element and adds it to the + <div> for us. + --> + <div id="listener"></div> + + <!-- + This element will be populated with the messages that come from the NaCl + module. See example.js. + --> + <div id="log"></div> +</body> +</html> diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc index 534e53a28d..5a2fc7a974 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc @@ -34,7 +34,6 @@ namespace nacl_io { MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount), is_readable_(false), - did_resize_(false), rows_(DEFAULT_TTY_ROWS), cols_(DEFAULT_TTY_COLS) { output_handler_.handler = NULL; @@ -100,15 +99,8 @@ Error MountNodeTty::Write(size_t offs, Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) { AUTO_LOCK(node_lock_); - did_resize_ = false; while (!is_readable_) { pthread_cond_wait(&is_readable_cond_, node_lock_.mutex()); - if (!is_readable_ && did_resize_) { - // If an async resize event occured then return the failure and - // set EINTR. - *out_bytes = 0; - return EINTR; - } } size_t bytes_to_copy = std::min(count, input_buffer_.size()); @@ -259,13 +251,6 @@ Error MountNodeTty::Ioctl(int request, char* arg) { cols_ = size->ws_col; } kill(getpid(), SIGWINCH); - - // Wake up any thread waiting on Read - { - AUTO_LOCK(node_lock_); - did_resize_ = true; - pthread_cond_broadcast(&is_readable_cond_); - } return 0; } case TIOCGWINSZ: { diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h index 8bf5b17304..c8070b9d5f 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h @@ -53,7 +53,6 @@ class MountNodeTty : public MountNodeCharDevice { std::deque<char> input_buffer_; bool is_readable_; - bool did_resize_; pthread_cond_t is_readable_cond_; struct termios termios_; diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/remove.c b/native_client_sdk/src/libraries/nacl_io/syscalls/remove.c index a816abbd89..a3a7bfb438 100644 --- a/native_client_sdk/src/libraries/nacl_io/syscalls/remove.c +++ b/native_client_sdk/src/libraries/nacl_io/syscalls/remove.c @@ -5,6 +5,14 @@ #include "nacl_io/kernel_intercept.h" #include "nacl_io/kernel_wrap.h" +#ifdef __GLIBC__ +// Glibc's remove(3) and unlink(2) entry points are not yet hooked up +// to the lower level IRT interfaces. Therefore the only way to intercept +// these calls is to override them here.. +// TODO(sbc): remove this once glibc plumbing is in place for remove/unlink + int remove(const char* path) { return ki_remove(path); } + +#endif diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc index 3dbb8eb61f..e2e416da76 100644 --- a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc @@ -74,7 +74,6 @@ class KernelProxyTest : public ::testing::Test { TEST_F(KernelProxyTest, FileLeak) { const size_t buffer_size = 1024; char filename[128]; - int file_num; int garbage[buffer_size]; MountMem* mount = (MountMem*)kp_.RootMount(); @@ -83,7 +82,7 @@ TEST_F(KernelProxyTest, FileLeak) { EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root)); EXPECT_EQ(0, root->ChildCount()); - for (file_num = 0; file_num < 4096; file_num++) { + for (int file_num = 0; file_num < 4096; file_num++) { sprintf(filename, "/foo%i.tmp", file_num++); FILE* f = fopen(filename, "w"); EXPECT_NE((FILE*)0, f); diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc index 4472d8c592..8f9957c7d7 100644 --- a/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc @@ -257,10 +257,12 @@ TEST_F(KernelWrapTest, read) { read(4567, NULL, 5678); } +#ifdef __GLIBC__ TEST_F(KernelWrapTest, remove) { EXPECT_CALL(mock, remove(StrEq("remove"))).Times(1); remove("remove"); } +#endif TEST_F(KernelWrapTest, rmdir) { EXPECT_CALL(mock, rmdir(StrEq("rmdir"))).Times(1); diff --git a/native_client_sdk/src/tools/run.py b/native_client_sdk/src/tools/run.py index a8b3ebc925..e2af359581 100755 --- a/native_client_sdk/src/tools/run.py +++ b/native_client_sdk/src/tools/run.py @@ -46,7 +46,7 @@ def main(args): dest='test_mode', action='store_true') parser.add_option('-p', '--port', help='Port to run server on. Default is 5103, ephemeral is 0.', - default=5103) + type='int', default=5103) options, args = parser.parse_args(args) if not args: parser.error('No executable given.') |