diff --git a/emcc b/emcc index 72380d6ae6ecb..bbf66151dcf85 100755 --- a/emcc +++ b/emcc @@ -1186,7 +1186,7 @@ try: lib_dirs.append(arg[2:]) newargs[i] = '' elif arg.startswith('-l'): - libs.append((i, arg[2:])) + libs.append((next_arg_index + 1 + i, arg[2:])) # -l libraries must be linked in last newargs[i] = '' elif arg.startswith('-Wl,'): # Multiple comma separated link flags can be specified. Create fake @@ -1499,6 +1499,9 @@ try: #if DEBUG: shutil.copyfile(temp_file, os.path.join(TEMP_DIR, 'to_opt.bc') # useful when LLVM opt aborts shared.Building.llvm_opt(temp_file, llvm_opts) + # Decide what we will link + linker_inputs = [val for _, val in sorted(temp_files + link_flags)] + # If we were just asked to generate bitcode, stop there if final_suffix not in JS_CONTAINING_SUFFIXES: if not specified_target: @@ -1522,10 +1525,9 @@ try: assert len(original_input_files) == 1 or not has_dash_c, 'fatal error: cannot specify -o with -c with multiple files' + str(sys.argv) + ':' + str(original_input_files) # We have a specified target (-o ), which is not JavaScript or HTML, and # we have multiple files: Link them - logging.debug('link: ' + str(temp_files) + specified_target) + logging.debug('link: ' + str(linker_inputs) + specified_target) # Sort arg tuples and pass the extracted values to link. - link_args = [f for (i, f) in sorted(temp_files)] - shared.Building.link(link_args, specified_target) + shared.Building.link(linker_inputs, specified_target) logging.debug('stopping at bitcode') exit(0) @@ -1547,7 +1549,7 @@ try: # First, combine the bitcode files if there are several. We must also link if we have a singleton .a if len(input_files) + len(extra_files_to_link) > 1 or \ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0][1]) in BITCODE_ENDINGS or suffix(temp_files[0][1]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0][1])): - linker_inputs = [val for _, val in sorted(temp_files + link_flags)] + extra_files_to_link + linker_inputs += extra_files_to_link logging.debug('linking: ' + str(linker_inputs)) shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents=len([temp for i, temp in temp_files if not temp.endswith(STATICLIB_ENDINGS)]) == 0) final = in_temp(target_basename + '.bc') @@ -1669,6 +1671,9 @@ try: logging.debug('applying pre/postjses') src = open(final).read() final += '.pp.js' + if WINDOWS: # Avoid duplicating \r\n to \r\r\n when writing out. + if pre_js: pre_js = pre_js.replace('\r\n', '\n') + if post_js: post_js = post_js.replace('\r\n', '\n') open(final, 'w').write(pre_js + src + post_js) if DEBUG: save_intermediate('pre-post') diff --git a/emrun b/emrun index e3596eed76e17..353021a0450e4 100755 --- a/emrun +++ b/emrun @@ -365,38 +365,51 @@ class HTTPHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): global page_exit_code, emrun_options, have_received_messages (_, _, path, query, _) = urlparse.urlsplit(self.path) - data = self.rfile.read(int(self.headers['Content-Length'])) - data = data.replace("+", " ") - data = unquote_u(data) - - # The user page sent a message with POST. Parse the message and log it to stdout/stderr. - is_stdout = False - is_stderr = False - seq_num = -1 - # The html shell is expected to send messages of form ^out^(number)^(message) or ^err^(number)^(message). - if data.startswith('^err^'): - is_stderr = True - elif data.startswith('^out^'): - is_stdout = True - if is_stderr or is_stdout: + if query.startswith('file='): # Binary file dump/upload handling. Requests to "stdio.html?file=filename" will write binary data to the given file. + data = self.rfile.read(int(self.headers['Content-Length'])) + filename = query[len('file='):] + dump_out_directory = 'dump_out' try: - i = data.index('^', 5) - seq_num = int(data[5:i]) - data = data[i+1:] + os.mkdir(dump_out_directory) except: pass - - is_exit = data.startswith('^exit^') - - if data == '^pageload^': # Browser is just notifying that it has successfully launched the page. + filename = os.path.join(dump_out_directory, os.path.normpath(filename)) + open(filename, 'wb').write(data) + print 'Wrote ' + str(len(data)) + ' bytes to file "' + filename + '".' have_received_messages = True - elif not is_exit: - log = browser_loge if is_stderr else browser_logi - self.server.handle_incoming_message(seq_num, log, data) - elif not emrun_options.serve_after_exit: - page_exit_code = int(data[6:]) - logv('Web page has quit with a call to exit() with return code ' + str(page_exit_code) + '. Shutting down web server. Pass --serve_after_exit to keep serving even after the page terminates with exit().') - self.server.shutdown() + else: + data = self.rfile.read(int(self.headers['Content-Length'])) + data = data.replace("+", " ") + data = unquote_u(data) + + # The user page sent a message with POST. Parse the message and log it to stdout/stderr. + is_stdout = False + is_stderr = False + seq_num = -1 + # The html shell is expected to send messages of form ^out^(number)^(message) or ^err^(number)^(message). + if data.startswith('^err^'): + is_stderr = True + elif data.startswith('^out^'): + is_stdout = True + if is_stderr or is_stdout: + try: + i = data.index('^', 5) + seq_num = int(data[5:i]) + data = data[i+1:] + except: + pass + + is_exit = data.startswith('^exit^') + + if data == '^pageload^': # Browser is just notifying that it has successfully launched the page. + have_received_messages = True + elif not is_exit: + log = browser_loge if is_stderr else browser_logi + self.server.handle_incoming_message(seq_num, log, data) + elif not emrun_options.serve_after_exit: + page_exit_code = int(data[6:]) + logv('Web page has quit with a call to exit() with return code ' + str(page_exit_code) + '. Shutting down web server. Pass --serve_after_exit to keep serving even after the page terminates with exit().') + self.server.shutdown() self.send_response(200) self.send_header("Content-type", "text/plain") @@ -930,7 +943,8 @@ def main(): if options.serve_root: serve_dir = os.path.abspath(options.serve_root) else: - serve_dir = os.path.dirname(os.path.abspath(file_to_serve)) + if file_to_serve == '.': serve_dir = os.path.abspath(file_to_serve) + else: serve_dir = os.path.dirname(os.path.abspath(file_to_serve)) url = os.path.relpath(os.path.abspath(file_to_serve), serve_dir) if len(cmdlineparams) > 0: url += '?' + '&'.join(cmdlineparams) diff --git a/emscripten-version.txt b/emscripten-version.txt index 5b3a48eab21e4..af3b687c7e180 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.21.10 +1.22.0 diff --git a/emscripten.py b/emscripten.py index faf41c409a1fb..47aea9d342e59 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1065,10 +1065,13 @@ def keyfunc(other): basic_vars = ['STACKTOP', 'STACK_MAX', 'tempDoublePtr', 'ABORT'] basic_float_vars = ['NaN', 'Infinity'] - if metadata.get('preciseI64MathUsed') or \ - forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32') or \ - forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32'): + if metadata.get('preciseI64MathUsed'): basic_vars += ['cttz_i8', 'ctlz_i8'] + else: + if forwarded_json['Functions']['libraryFunctions'].get('llvm_cttz_i32'): + basic_vars += ['cttz_i8'] + if forwarded_json['Functions']['libraryFunctions'].get('llvm_ctlz_i32'): + basic_vars += ['ctlz_i8'] if settings.get('DLOPEN_SUPPORT'): for sig in last_forwarded_json['Functions']['tables'].iterkeys(): diff --git a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css index 300680f9fcfae..5c4e19b435764 100644 --- a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css +++ b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css @@ -21,7 +21,9 @@ table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromefra margin-bottom:0 !important } -.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap} +.wy-table-responsive table td {white-space:nowrap} + +.wy-table-responsive table th{white-space:nowrap} a{color:#2980b9;text-decoration:none}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980b9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27ae60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#e74c3c !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}code,.rst-content tt{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:"Incosolata","Consolata","Monaco",monospace;color:#e74c3c;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px} .wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li { @@ -341,6 +343,14 @@ width:inherit; } + +/* HamishW - Attempt to wrap table columns/remove the "responsive" behaviour on some tables. */ +table.wrap-table-content td, table.wrap-table-content th { + white-space: normal; +} + + + /* HamishW - fix bullet lists inside arabic decimal lists not rendering properly */ /* .wy-plain-list-decimal li, .rst-content .section ol li, .rst-content ol.arabic li, article ol li .wy-plain-list-decimal ul .simple li { diff --git a/site/source/conf.py b/site/source/conf.py index 03d7178408160..c2eb431b365e5 100644 --- a/site/source/conf.py +++ b/site/source/conf.py @@ -171,7 +171,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = '/_static/Emscripten_logo_full.png' +html_logo = '_static/Emscripten_logo_full.png' # The name of an image file (within the static path) to use as favicon of the diff --git a/site/source/docs/api_reference/Filesystem-API.rst b/site/source/docs/api_reference/Filesystem-API.rst index e77f45777bca2..bc491fa06e16b 100644 --- a/site/source/docs/api_reference/Filesystem-API.rst +++ b/site/source/docs/api_reference/Filesystem-API.rst @@ -5,711 +5,714 @@ Filesystem API (wiki-import) ============================ .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -File I/O in emscripten is provided by the -`FS `__ -library. This same library is used internally for all of emscripten's -libc and libcxx file I/O. - -Emscripten deals predominantly with synchronous file I/O, so the -majority of the FS member functions offer a synchronous interface, with -errors being reported by raising exceptions of type ``FS.ErrnorError``. - -The file data in emscription is partioned by mounted filesystems, of -which several are provided to work with. By default, an instance of -`MEMFS `__ is mounted to ``/`` and instances of -`NODEFS `__ and `IDBFS `__ can be mounted to -other directories if your application needs to `persist -data `__. +File I/O in Emscripten is provided by the `FS `_ library. This same library is used internally for all of emscripten's libc and libcxx file I/O. + +Emscripten deals predominantly with synchronous file I/O, so the majority of the FS member functions offer a synchronous interface, with errors being reported by raising exceptions of type ``FS.ErrnorError``. + +The file data in emscription is partioned by mounted filesystems, of which several are provided to work with. By default, an instance of `MEMFS` is mounted to ``/`` and instances of `NODEFS` and `IDBFS` can be mounted to other directories if your application needs to `persist data `__. + Persistence ------------ +=========== -Applications being compiled with emscripten expect synchronous I/O, -therefore, emscripten itself must provide filesystems with completely -synchronous interfaces. However, due to JavaScript's event-driven -nature, most persistent storage options offer only asynchronous -interfaces. +Applications being compiled with Emscripten expect synchronous I/O, therefore, Emscripten itself must provide filesystems with completely synchronous interfaces. However, due to JavaScript's event-driven nature, most persistent storage options offer only asynchronous interfaces. -Because of this, emscripten offers multiple filesystems that can be -mounted with `FS.mount `__ to help -deal with persistence depending on the execution context. +Because of this, Emscripten offers multiple filesystems that can be mounted with :js:func:`FS.mount` to help deal with persistence depending on the execution context. MEMFS -~~~~~ +=========== -This is the default filesystem mounted at ``/`` when the runtime is -initialized. All files exist strictly in-memory, and any data written to -it is lost when the page is reloaded. +This is the default filesystem mounted at ``/`` when the runtime is initialized. All files exist strictly in-memory, and any data written to it is lost when the page is reloaded. NODEFS -~~~~~~ +=========== -NODEFS lets a program in node directly access files on the local -filesystem, as if the problem were running normally. See `this -test `__ -for an example. +NODEFS lets a program in node directly access files on the local filesystem, as if the problem were running normally. See `this test `__ for an example. Mount options -^^^^^^^^^^^^^ +------------- - root ``string`` Path to persist the data to on the local filesystem. -This filesystem is only for use when running inside of node. It uses -node's synchronous fs API to immediately persist any data written to -emscripten's filesystem to your local disk. +This filesystem is only for use when running inside of node. It uses node's synchronous fs API to immediately persist any data written to emscripten's filesystem to your local disk. IDBFS -~~~~~ +===== -This filesystem is only for use when running inside of the browser. Due -to the browser not offering any synchronous APIs for persistent storage, -by default all writes exist only temporarily in-memory. However, the -IDBFS filesystem implements the -`FS.syncfs `__ interface, which once -called will persist any operations to a backing IndexedDB instance. +This filesystem is only for use when running inside of the browser. Due to the browser not offering any synchronous APIs for persistent storage, by default all writes exist only temporarily in-memory. However, the IDBFS filesystem implements the :js:func`FS.syncfs` interface, which once called will persist any operations to a backing IndexedDB instance. Devices -------- +=========== + +Emscripten supports registering arbitrary device drivers composed of a device id and a set of unique stream callbacks. Once a driver has been registered with :js:func:`FS.registerDevice`, a device node (acting as an interface between the device and the filesystem) can be created to reference it with :js:func`FS.mkdev`. Any stream referencing the new node will inherit the stream callbacks registered for the device, making all of the high-level FS operations transparently interact with the device. -Emscripten supports registering arbitrary device drivers composed of a -device id and a set of unique stream callbacks. Once a driver has been -registered with `FS.registerDevice <#fsregisterdevicedev-ops>`__, a -device node (acting as an interface between the device and the -filesystem) can be created to reference it with -`FS.mkdev <#fsmkdevpath-mode-dev>`__. Any stream referencing the new -node will inherit the stream callbacks registered for the device, making -all of the high-level FS operations transparently interact with the -device. -FS.makedev(ma, mi) -^^^^^^^^^^^^^^^^^^ -Converts a major and minor number into a single unique integer. +.. js:function:: FS.makedev(ma, mi) -FS.registerDevice(dev, ops) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Converts a major and minor number into a single unique integer. + + :param ma: **HamishW** + :param mi: **HamishW** + :throws **HamishW**: -Registers a device driver for the specified id / callbacks. + + +.. js:function:: FS.registerDevice(dev, ops) + + Registers a device driver for the specified id / callbacks. + + :param dev: ``MEMFS`` ``NODEFS`` ``IDBFS`` + :param object ops: **HamishW** + :throws **HamishW**: + Setting up standard I/O devices -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Emscripten standard I/O works by going though the virtual -``/dev/stdin``, ``/dev/stdout`` and ``/dev/stderr`` devices. You can set -them up using your own I/O functions by calling -``FS.init(input_callback, output_callback, error_callback)`` (all -arguments optional). Note that all the configuration should be done -before the main ``run()`` method is executed, typically by implementing -``Module.preRun``, see :ref:`Interacting-with-code`. - -- The input callback will be called with no parameters whenever the - program attempts to read from ``stdin``. It should return an ASCII - character code when data is available, or ``null`` when it isn't. -- The output callback will be called with an ASCII character code - whenever the program writes to ``stdout``. It may also be called with - ``null`` to flush the output. -- The error callback is similar to the output one, except it is called - when data is written to ``stderr``. - -If any of the callbacks throws an exception, it will be caught and -handled as if the device malfunctioned. +------------------------------- + +Emscripten standard I/O works by going though the virtual ``/dev/stdin``, ``/dev/stdout`` and ``/dev/stderr`` devices. You can set them up using your own I/O functions by calling ``FS.init(input_callback, output_callback, error_callback)`` (all arguments optional). Note that all the configuration should be done before the main ``run()`` method is executed, typically by implementing ``Module.preRun``, see :ref:`Interacting-with-code`. + +- The input callback will be called with no parameters whenever the program attempts to read from ``stdin``. It should return an ASCII character code when data is available, or ``null`` when it isn't. +- The output callback will be called with an ASCII character code whenever the program writes to ``stdout``. It may also be called with ``null`` to flush the output. +- The error callback is similar to the output one, except it is called when data is written to ``stderr``. + +If any of the callbacks throws an exception, it will be caught and handled as if the device malfunctioned. By default: -- ``stdin`` will read from the terminal in command line engines and use - ``window.prompt()`` in browsers (in both cases, with line buffering). -- ``stdout`` will use a ``print`` function if one such is defined, - printing to the terminal in command line engines and to the browser - console in browsers that have a console (again, line-buffered). +- ``stdin`` will read from the terminal in command line engines and use ``window.prompt()`` in browsers (in both cases, with line buffering). +- ``stdout`` will use a ``print`` function if one such is defined, printing to the terminal in command line engines and to the browser console in browsers that have a console (again, line-buffered). - ``stderr`` will use the same output function as ``stdout``. + Filesystem ----------- +=========== + + +.. js:function:: FS.mount(type, opts, mountpoint) + + Mounts the FS object specified by ``type`` to the directory specified by ``mountpoint``. The ``opts`` objects is specific to each filesystem type. + + :param type: ``MEMFS`` ``NODEFS`` ``IDBFS`` + :param object opts: **HamishW** + :param string mountpoint: **HamishW** + :throws **HamishW**: -FS.mount(type, opts, mountpoint) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- type `MEMFS `__ `NODEFS `__ - `IDBFS `__ -- opts ``object`` -- mountpoint ``string`` -Mounts the FS object specified by ``type`` to the directory specified by -``mountpoint``. The ``opts`` objects is specific to each filesystem -type. +.. js:function:: FS.syncfs(populate, callback) -FS.syncfs(populate, callback) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Responsible for iterating and synchronizing all mounted filesystems in an asynchronous fashion. -- populate ``bool`` + The ``populate`` flag is used to control the intended direction of the underlying synchronization between Emscripten`s internal data, and the filesystem's persistent data. ``populate=true`` is used for initializing Emscripten's filesystem data with the data from the filesystem's persistent source, and ``populate=false`` is used to save emscripten's filesystem data to the filesystem's persistent source. -Responsible for iterating and synchronizing all mounted filesystems in -an asynchronous fashion. + For example: -The ``populate`` flag is used to control the intended direction of the -underlying synchronization between emscripten's internal data, and the -filesystem's persistent data. ``populate=true`` is used for initializing -emscripten's filesystem data with the data from the filesystem's -persistent source, and ``populate=false`` is used to save emscripten's -filesystem data to the filesystem's persistent source. + .. code:: javascript -Example -''''''' + function myAppStartup(callback) { + FS.mkdir('/data'); + FS.mount(IDBFS, {}, '/data'); -.. code:: javascript + FS.syncfs(true, function (err) { + // handle callback + }); + } - function myAppStartup(callback) { - FS.mkdir('/data'); - FS.mount(IDBFS, {}, '/data'); + function myAppShutdown(callback) { + FS.syncfs(function (err) { + // handle callback + }); + } - FS.syncfs(true, function (err) { - // handle callback - }); - } + An actual test implementing this functionality can be seen at https://github.com/kripken/emscripten/blob/master/tests/fs/test\_idbfs\_sync.c. - function myAppShutdown(callback) { - FS.syncfs(function (err) { - // handle callback - }); - } + .. note:: Currently, only the `IDBFS`_ filesystem implements the interfaces needed by this. All other filesystems are completely synchronous and don't require synchronization. -An actual test implementing this functionality can be seen at -https://github.com/kripken/emscripten/blob/master/tests/fs/test\_idbfs\_sync.c. + :param bool populate: ``true`` to initialize Emscripten's filesystem data with the data from the filesystem's persistent source, and ``false`` to save emscripten's filesystem data to the filesystem's persistent source. + :param callback: **HamishW** + :throws **HamishW**: -NOTE: Currently, only the `IDBFS `__ filesystem implements -the interfaces needed by this. All other filesystems are completely -synchronous and don't require synchronization. -FS.mkdir(path, mode) -^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.mkdir(path, mode) -- path ``string`` -- mode ``int`` default = 0777 + Creates a new directory node in the filesystem. For example: -Creates a new directory node in the filesystem. + .. code:: javascript -Example -''''''' + FS.mkdir('/data'); + + :param string path: The path name for the new directory node. + :param int mode: **HamishW** Link to mode values. The default is 0777. + :throws **HamishW**: -.. code:: javascript - FS.mkdir('/data'); +.. js:function:: FS.mkdev(path, mode, dev) -FS.mkdev(path, mode, dev) -^^^^^^^^^^^^^^^^^^^^^^^^^ + Creates a new device node in the filesystem referencing the device driver registered for ``dev``. For example: -- path ``string`` -- mode ``int`` default = 0777 -- dev ``int`` + .. code:: javascript -Creates a new device node in the filesystem referencing the device -driver registered for ``dev``. + var id = FS.makedev(64, 0); + FS.registerDevice(id, {}); + FS.mkdev('/dummy', id); -Example -''''''' + :param string path: The path name for the new device node. + :param int mode: **HamishW** Link to mode values. The default is 0777. + :param int dev: **HamishW**. + :throws **HamishW**: -.. code:: javascript - var id = FS.makedev(64, 0); - FS.registerDevice(id, {}); - FS.mkdev('/dummy', id); +.. js:function:: FS.symlink(oldpath, newpath) -FS.symlink(oldpath, newpath) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Creates a symlink node at ``newpath`` linking to ``oldpath``. For example: -- oldpath ``string`` -- newpath ``string`` + .. code:: javascript -Creates a symlink node at ``newpath`` linking to ``oldpath``. + FS.writeFile('file', 'foobar'); + FS.symlink('file', 'link'); -Example -''''''' + :param string oldpath: The path name of the file to link to. + :param string newpath: The path to the new symlink node to ``oldpath``. + :throws **HamishW**: -.. code:: javascript - FS.writeFile('file', 'foobar'); - FS.symlink('file', 'link'); -FS.rename(oldpath, newpath) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.rename(oldpath, newpath) -- oldpath ``string`` -- newpath ``string`` + Renames the node at ``oldpath`` to ``newpath``. For example: -Renames the node at ``oldpath`` to ``newpath``. + .. code:: javascript -Example -''''''' + FS.writeFile('file', 'foobar'); + FS.rename('file', 'newfile'); -.. code:: javascript + :param string oldpath: The old path name. + :param string newpath: The new path name + :throws **HamishW**: + - FS.writeFile('file', 'foobar'); - FS.rename('file', 'newfile'); +.. js:function:: FS.rmdir(path) -FS.rmdir(path) -^^^^^^^^^^^^^^ + Removes an empty directory located at ``path``. -- path ``string`` + Example -Removes an empty directory located at ``path``. + .. code:: javascript -Example -''''''' + FS.mkdir('data'); + FS.rmdir('data'); -.. code:: javascript + :param string path: Path of the directory to be removed. + :throws **HamishW**: - FS.mkdir('data'); - FS.rmdir('data'); -FS.unlink(path) -^^^^^^^^^^^^^^^ +.. js:function:: FS.unlink(path) -- path ``string`` + Unlinks the node at ``path`` (this was previously called + ``deleteFile``). + + .. COMMENT :: **HamishW** What does unlinking actually mean? + + For example: -Unlink the node at ``path``. (This was previously called -``deleteFile``.) + .. code:: javascript -Example -''''''' + FS.writeFile('/foobar.txt', 'Hello, world'); + FS.unlink('/foobar.txt'); -.. code:: javascript + :param string path: Path of the target node. + :throws **HamishW**: + - FS.writeFile('/foobar.txt', 'Hello, world'); - FS.unlink('/foobar.txt'); + +.. js:function:: FS.readlink(path) -FS.readlink(path) -^^^^^^^^^^^^^^^^^ + Gets the string value stored in the symbolic link at ``path``. For example: -- path ``string`` + .. code:: c -Returns the string value stored in the symbolic link at ``path``. + #include + #include -Example -''''''' + int main() { + EM_ASM( + FS.writeFile('file', 'foobar'); + FS.symlink('file', 'link'); + console.log(FS.readlink('link')); + ); + return 0; + } -.. code:: c + outputs - #include - #include + :: - int main() { - EM_ASM( - FS.writeFile('file', 'foobar'); - FS.symlink('file', 'link'); - console.log(FS.readlink('link')); - ); - return 0; - } + file + + :param string path: Path of the target file. + :returns: The string value stored in the symbolic link at ``path``. + :throws **HamishW**: + -outputs -:: +.. js:function:: FS.stat(path) - file + Gets a JavaScript object of stats for the node at ``path``. For example: -FS.stat(path) -^^^^^^^^^^^^^ + .. code:: c -- path ``string`` + #include + #include -Returns a JavaScript object of stats for the node at ``path``. + int main() { + EM_ASM( + FS.writeFile('file', 'foobar'); + console.log(FS.stat('file')); + ); + return 0; + } -Example -''''''' + outputs -.. code:: c + :: - #include - #include + { + dev: 1, + ino: 13, + mode: 33206, + nlink: 1, + uid: 0, + gid: 0, + rdev: 0, + size: 6, + atime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), + mtime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), + ctime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), + blksize: 4096, + blocks: 1 + } - int main() { - EM_ASM( - FS.writeFile('file', 'foobar'); - console.log(FS.stat('file')); - ); - return 0; - } + :param string path: Path of the target file. + :throws **HamishW**: -outputs -:: +.. js:function:: FS.lstat(path) - { - dev: 1, - ino: 13, - mode: 33206, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - size: 6, - atime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), - mtime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), - ctime: Mon Nov 25 2013 00:37:27 GMT-0800 (PST), - blksize: 4096, - blocks: 1 - } + Identical to :ref:`FS.stat`, However, if ``path`` is a symbolic link then the returned stats will be for the link itself, not the file that it links to. -FS.lstat(path) -^^^^^^^^^^^^^^ + :param string path: Path of the target file. + :throws **HamishW**: -- path ``string`` -Identical to ``FS.stat``, However, if ``path`` is a symbolic link then -the returned stats will be for the link itself, not the file that it -links to. +.. js:function:: FS.chmod(path, mode) -FS.chmod(path, mode) -^^^^^^^^^^^^^^^^^^^^ + Change the mode flags for ``path`` to ``mode``. For example: -- path ``string`` -- mode ``int`` + .. code:: javascript -Change the mode flags for ``path`` to ``mode``. + FS.writeFile('forbidden', 'can\'t touch this'); + FS.chmod('forbidden', 0000); -Example -''''''' + :param string path: Path of the target file. + :param int mode: **HamishW**. + :throws **HamishW**: -.. code:: javascript - FS.writeFile('forbidden', 'can\'t touch this'); - FS.chmod('forbidden', 0000); -FS.lchmod(path, mode) -^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.lchmod(path, mode) -- path ``string`` -- mode ``int`` + Identical to :ref:`FS.chmod`. However, if ``path`` is a symbolic link then the mode will be set on the link itself, not the file that it links to. -Identical to ``FS.chmod``. However, if ``path`` is a symbolic link then -the mode will be set on the link itself, not the file that it links to. + :param string path: Path of the target file. + :param int mode: **HamishW**. + :throws **HamishW**: -FS.fchmod(fd, mode) -^^^^^^^^^^^^^^^^^^^ -- fd ``int`` -- mode ``int`` +.. js:function:: FS.fchmod(fd, mode) -Identical to ``FS.chmod``. However, a raw file decriptor is supplied as -``fd``. + Identical to :ref:`FS.chmod`. However, a raw file descriptor is supplied as ``fd``. -FS.chown(path, uid, gid) -^^^^^^^^^^^^^^^^^^^^^^^^ + :param int fd: Descriptor of target file. + :param int mode: **HamishW**. + :throws **HamishW**: -- path ``string`` -- uid ``int`` -- gid ``int`` -Set ``uid`` and ``gid`` properties of the node at ``path``. -FS.lchown(path, uid, gid) -^^^^^^^^^^^^^^^^^^^^^^^^^ -- path ``string`` -- uid ``int`` -- gid ``int`` +.. js:function:: FS.chown(path, uid, gid) -Identical to ``FS.chown``. However, if path is a symbolic link then the -properties will be set on the link itself, not the file that it links -to. + Set ``uid`` and ``gid`` properties of the node at ``path``. -FS.fchown(fd, uid, gid) -^^^^^^^^^^^^^^^^^^^^^^^ + :param string path: Path of the target file. + :param int uid: **HamishW**. + :param int gid: **HamishW**. + :throws **HamishW**: -- fd ``int`` -- uid ``int`` -- gid ``int`` -Identical to ``FS.chown``. However, a raw file decriptor is supplied as -``fd``. -FS.truncate(path, len) -^^^^^^^^^^^^^^^^^^^^^^ -- path ``string`` -- len ``int`` +.. js:function:: FS.lchown(path, uid, gid) -Truncates a file to the specified length. + Identical to Identical to :ref:`FS.chown`. However, if path is a symbolic link then the properties will be set on the link itself, not the file that it links to. -Example -''''''' + :param string path: Path of the target file. + :param int uid: **HamishW**. + :param int gid: **HamishW**. + :throws **HamishW**: -.. code:: c - #include - #include - int main() { - EM_ASM( - FS.writeFile('file', 'foobar'); - FS.truncate('file', 3); - console.log(FS.readFile('file', { encoding: 'utf8' })); - ); - return 0; - } +.. js:function:: FS.fchown(fd, uid, gid) -outputs + Identical to :ref:`FS.chown`. However, a raw file descriptor is supplied as ``fd``. -:: + :param int fd: Descriptor of target file. + :param int uid: **HamishW**. + :param int gid: **HamishW**. + :throws **HamishW**: - foo + -FS.ftruncate(fd, len) -^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.truncate(path, len) -- fd ``int`` -- len ``int`` + Truncates a file to the specified length. For example: -Truncates the file identified by the file descriptor to the specified -length. -FS.utime(path, atime, mtime) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. code:: c -- path ``string`` -- atime ``int`` -- mtime ``int`` + #include + #include -Change the timestamps of the file located at ``path``. + int main() { + EM_ASM( + FS.writeFile('file', 'foobar'); + FS.truncate('file', 3); + console.log(FS.readFile('file', { encoding: 'utf8' })); + ); + return 0; + } -FS.open(path, flags, [mode]) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + outputs -- path ``string`` -- flags ``sring`` -- mode ``int`` default = 0666 + :: -Opens a file with the specified flags. ``flags`` can be: + foo + + :param string path: Path of the file to be truncated. + :param int len: The truncation length for the file. + :throws ERRNO_CODES.EINVAL: + :throws ERRNO_CODES.EPERM: + :throws ERRNO_CODES.EISDIR: + + + +.. js:function:: FS.ftruncate(fd, len) -- 'r' - Open file for reading. -- 'r+' - Open file for reading and writing. -- 'w' - Open file for writing. -- 'wx' - Like 'w' but fails if path exists. -- 'w+' - Open file for reading and writing. The file is created if it - does not exist or truncated if it exists. -- 'wx+' - Like 'w+' but fails if path exists. -- 'a' - Open file for appending. The file is created if it does not - exist. -- 'ax' - Like 'a' but fails if path exists. -- 'a+' - Open file for reading and appending. The file is created if it - does not exist. -- 'ax+' - Like 'a+' but fails if path exists. + Truncates the file identified by the ``fd`` to the specified length (``len``). -``mode`` specifies the permissions for the file, and are only used if -the file is created. + :param int fd: Descriptor of file to be truncated. + :param int len: The truncation length for the file. + :throws ERRNO_CODES.EBADF: + :throws ERRNO_CODES.EINVAL: + :throws ERRNO_CODES.EPERM: + :throws ERRNO_CODES.EISDIR: -Returns a stream object. -FS.close(stream) -^^^^^^^^^^^^^^^^ +.. js:function:: FS.utime(path, atime, mtime) -- stream ``object`` + Change the timestamps of the file located at ``path``. Note that in the current implementation the stored timestamp is a single value, the maximum of ``atime`` and ``mtime``. + + :param string path: The path of the file to update. + :param int atime: The file modify time. + :param int mtime: The file access time. -Closes the file stream. + .. COMMENT :: **HamishW** what is the format of the time? Seconds since unix/posix start time in 1970? + -FS.llseek(stream, offset, whence) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.open(path, flags [, mode]) -- stream ``object`` -- offset ``int`` -- whence ``int`` + Opens a file with the specified flags. ``flags`` can be: -Repositions the offset of the stream ``offset`` bytes, relative to the -``whence`` parameter. + .. _fs-read-and-write-flags: + + - 'r' - Open file for reading. + - 'r+' - Open file for reading and writing. + - 'w' - Open file for writing. + - 'wx' - Like 'w' but fails if path exists. + - 'w+' - Open file for reading and writing. The file is created if it does not exist or truncated if it exists. + - 'wx+' - Like 'w+' but fails if path exists. + - 'a' - Open file for appending. The file is created if it does not exist. + - 'ax' - Like 'a' but fails if path exists. + - 'a+' - Open file for reading and appending. The file is created if it does not exist. + - 'ax+' - Like 'a+' but fails if path exists. -When can be SEEK\_SET (0), SEEK\_CUR(1) or SEEK\_END(2); + + :param string path: The path of the file to open. + :param string flags: Read and write :ref:`flags `. + :param mode: Permissions for the file. This is only used if the file is created. Default is 0666. + :returns: A stream object. -FS.read(stream, buffer, offset, length, position) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. COMMENT:: **HamishW** What mode/settings does 0666 map to? We need a list to possible mode values. -- stream ``object`` -- buffer ``ArrayBufferView`` -- offset ``int`` -- length ``int`` -- position ``int`` + -Read ``length`` bytes from the stream, storing them into ``buffer`` -starting at ``offset``. By default, reading starts from the stream's -current offset, however, a specific offset can be specified with the -``position`` argument. +.. js:function:: FS.close(stream) -Example -''''''' + Closes the file stream. + + :param object stream: The stream to be closed. -.. code:: javascript - var stream = FS.open('abinaryfile', 'r'); - var buf = new Uint8Array(4); - FS.read(stream, buf, 0, 4, 0); - FS.close(stream); -FS.write(stream, buffer, offset, length, position) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.llseek(stream, offset, whence) -- stream ``object`` -- buffer ``ArrayBufferView`` -- offset ``int`` -- length ``int`` -- position ``int`` + Repositions the offset of the stream ``offset`` bytes, relative to the ``whence`` parameter. -Write ``length`` bytes from ``buffer``, starting at ``offset``. By -default, writing starts from the stream's current offset, however, a -specific offset can be specified with the ``position`` argument. + :param object stream: The stream for which the offset is to be repositioned. + :param int offset: The offset (in bytes) relative to ``whence``. + :param int whence: SEEK\_SET (0), SEEK\_CUR(1) or SEEK\_END(2); -Example -''''''' + .. COMMENT :: **HamishW** I don't understand the whence parameter. Need to follow up and check test code. + -.. code:: javascript +.. js:function:: FS.read(stream, buffer, offset, length [, position]) - var data = new Uint8Array(32); - var stream = FS.open('dummy', 'w+'); - FS.write(stream, data, 0, data.length, 0); - FS.close(stream); + Read ``length`` bytes from the stream, storing them into ``buffer`` starting at ``offset``. + + By default, reading starts from the stream's current offset, however, a specific offset can be specified with the ``position`` argument. For example: -FS.readFile(path, opts) -^^^^^^^^^^^^^^^^^^^^^^^ + .. code:: javascript -- path ``string`` -- opts ``object`` -- flags ``string`` default = 'r' -- encoding ``string`` default = 'binary' + var stream = FS.open('abinaryfile', 'r'); + var buf = new Uint8Array(4); + FS.read(stream, buf, 0, 4, 0); + FS.close(stream); + + :param object stream: The stream to read from. + :param ArrayBufferView buffer: The buffer to store the read data. + :param int offset: The offset within ``buffer`` to store the data. + :param int length: The length of data to write in ``buffer``. + :param int position: The offset within the stream to read. By default this is the stream's current offset. + :throws ERRNO_CODES.EINVAL: Reading from an invalid position or length + :throws ERRNO_CODES.EBADF: + :throws ERRNO_CODES.ESPIPE: + :throws ERRNO_CODES.EISDIR: + :throws ERRNO_CODES.EINVAL: + + + +.. js:function:: FS.write(stream, buffer, offset, length[, position]) + + Writes ``length`` bytes from ``buffer``, starting at ``offset``. + + By default, writing starts from the stream's current offset, however, a specific offset can be specified with the ``position`` argument. For example: -Slurps the entire file at ``path`` and returns it either as a string, or -a new Uint8Array buffer (``encoding`` = 'binary'). + .. code:: javascript -FS.writeFile(path, data, opts) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + var data = new Uint8Array(32); + var stream = FS.open('dummy', 'w+'); + FS.write(stream, data, 0, data.length, 0); + FS.close(stream); -- path ``string`` -- data ``ArrayBufferView`` -- opts ``object`` -- flags ``string`` default = 'w' -- encoding ``string`` default = 'utf8' + :param object stream: The stream to write to. + :param ArrayBufferView buffer: The buffer to write. + :param int offset: The offset within ``buffer`` to write. + :param int length: The length of data to write. + :param int position: The offset within the stream to write. By default this is the stream's current offset. + :throws ERRNO_CODES.EINVAL: Reading from an invalid position or length + :throws ERRNO_CODES.EBADF: + :throws ERRNO_CODES.ESPIPE: + :throws ERRNO_CODES.EISDIR: + :throws ERRNO_CODES.EINVAL: + + .. COMMENT:: Need to check if Throws should be recorded, and if so, what should be said. **HamishW** -Writes the entire contents of ``data`` to the file at ``path``. ``data`` -is treated either as a string (``encoding`` = 'utf8'), or as an -ArrayBufferView (``encoding`` = 'binary'). -Example -''''''' + +.. js:function:: FS.readFile(path, opts) -.. code:: javascript + Reads the entire file at ``path`` and returns it as a ``string`` (encoding is 'utf8'), or as a new ``Uint8Array`` buffer (encoding is `binary'). - FS.writeFile('file', 'foobar'); - var contents = FS.readFile('file', { encoding: 'utf8' }); + :param string path: The file to read. + :param object opts: + + - **encoding** (*string*) + Defines the encoding used to return the file contents: 'binary' | 'utf8' . The default is 'binary' + - **flags** (*string*) + Read flags, as defined in :js:func:`FS.open`. The default is 'r'. + + :returns: The file as a ``string`` or ``Uint8Array`` buffer, depending on the encoding. -FS.createLazyFile(parent, name, url, canRead, canWrite) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Creates a file that will be loaded lazily on first access from a given -URL or local filesystem path, and returns a reference to it. WARNING: -Firefox and Chrome have recently disabled synchronous binary XHRs, which -means this cannot work for Javascript in regular HTML pages (but it -works within WebWorkers). -:: +.. js:function:: FS.writeFile(path, data, opts) - * `(string|object) parent`: The parent folder, either as a path (e.g. `'/usr/lib'`) or an object previously returned from a `FS.createFolder()` or `FS.createPath()` call. - * `string name`: The name of the new file. - * `string url`: In the browser, this is the URL whose contents will be returned when this file is accessed. In a command line engine, this will be the local (real) filesystem path from where the contents will be loaded. Note that writes to this file are virtual. - * `bool canRead`: Whether the file should have read permissions set from the program's point of view. - * `bool canWrite`: Whether the file should have write permissions set from the program's point of view. + Writes the entire contents of ``data`` to the file at ``path``. + + The value of ``opts`` determines whether ``data`` is treated either as a string (``encoding`` = 'utf8'), or as an ``ArrayBufferView`` (``encoding`` = 'binary'). For example: -Example -''''''' + .. code:: javascript -.. code:: javascript + FS.writeFile('file', 'foobar'); + var contents = FS.readFile('file', { encoding: 'utf8' }); + + :param string path: The file to which to write ``data``. + :param ArrayBufferView data: The data to write. + :param object opts: + + - **encoding** (*string*) + 'binary' | 'utf8' . The default is 'utf8' + - **flags** (*string*) + Write flags, as defined in :js:func:`FS.open`. The default is 'w'. - FS.createLazyFile('/', 'foo', 'other/page.htm', true, false); - FS.createLazyFile('/', 'bar', '/get_file.php?name=baz', true, true); -FS.createPreloadedFile(parent, name, url, canRead, canWrite) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. js:function:: FS.createLazyFile(parent, name, url, canRead, canWrite) + + Creates a file that will be loaded lazily on first access from a given URL or local filesystem path, and returns a reference to it. + + .. warning:: Firefox and Chrome have recently disabled synchronous binary XHRs, which means this cannot work for JavaScript in regular HTML pages (but it works within WebWorkers). + + Example + + .. code:: javascript + + FS.createLazyFile('/', 'foo', 'other/page.htm', true, false); + FS.createLazyFile('/', 'bar', '/get_file.php?name=baz', true, true); + + + :param parent: The parent folder, either as a path (e.g. `'/usr/lib'`) or an object previously returned from a `FS.createFolder()` or `FS.createPath()` call. + :type parent: string/object + :param string name: The name of the new file. + :param string url: In the browser, this is the URL whose contents will be returned when this file is accessed. In a command line engine, this will be the local (real) filesystem path from where the contents will be loaded. Note that writes to this file are virtual. + :param bool canRead: Whether the file should have read permissions set from the program's point of view. + :param bool canWrite: Whether the file should have write permissions set from the program's point of view. + :returns: A reference to the new file. + :throws ERRNO_CODES.EIO: + :throws: if there is an invalid range or URL, or if synchronous binary XHRs have been disabled. + + + +.. js:function:: FS.createPreloadedFile(parent, name, url, canRead, canWrite) + + Preloads a file asynchronously. You should call this in ``preRun``, and then ``run()`` will be delayed until all preloaded files are ready. This is how ``--preload-file`` works in *emcc*. + + :param parent: The parent folder, either as a path (e.g. `'/usr/lib'`) or an object previously returned from a `FS.createFolder()` or `FS.createPath()` call. + :type parent: string/object + :param string name: The name of the new file. + :param string url: In the browser, this is the URL whose contents will be returned when this file is accessed. In a command line engine, this will be the local (real) filesystem path from where the contents will be loaded. Note that writes to this file are virtual. + :param bool canRead: Whether the file should have read permissions set from the program's point of view. + :param bool canWrite: Whether the file should have write permissions set from the program's point of view. + -Preloads a file asychronously. You should call this in preRun, and then -run() will be delayed until all preloaded files are ready. This is how -``--preload-file`` works in emcc. File types ----------- +=========== + +Emscripten's filesystem supports regular files, directories, symlinks, character devices, block devices and sockets. In a similar manner to most Unix systems, all of these file types are able to be operated on with the higher-level FS operations such as :js:func:`FS.read` :js:func:`FS.write`. + + +.. js:function:: FS.isFile(mode) + + Tests if the ``mode`` bitmask represents a file. + + + :param mode: A bitmask of possible file properties. + :returns: ``true`` if the ``mode`` bitmask represents a file. + :rtype: bool + + +.. js:function:: FS.isDir(mode) + + Tests if the ``mode`` bitmask represents a directory. -Emscripten's filesystem supports regular files, directories, symlinks, -character devices, block devices and sockets. In a similar manner to -most Unix systems, all of these file types are able to be operated on -with the higher-level FS operations such as -`FS.read <#fsreadstream-buffer-offset-length-position>`__ and -`FS.write <#fswritestream-buffer-offset-length-position-canown>`__. + :returns: ``true`` if the ``mode`` bitmask represents a directory. + :rtype: bool -FS.isFile(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^^ -Returns true if the mode bitmask represents a file. -FS.isDir(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.isLink(mode) -Returns true if the mode bitmask represents a directory. + Tests if the ``mode`` bitmask represents a symlink. -FS.isLink(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^^ + :param mode: A bitmask of possible file properties. + :returns: ``true`` if the ``mode`` bitmask represents a symlink. + :rtype: bool -Returns true if the mode bitmask represents a symlink. -FS.isChrdev(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.isChrdev(mode) -Returns true if the mode bitmask represents a character device. + Tests if the ``mode`` bitmask represents a character device. -FS.isBlkdev(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ + :param mode: A bitmask of possible file properties. + :returns: ``true`` if the ``mode`` bitmask represents a character device. + :rtype: bool -Returns true if the mode bitmask represents a block device. -FS.isSocket(node \|\| mode) -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. js:function:: FS.isBlkdev(mode) + + Tests if the ``mode`` bitmask represents a block device. + + :param mode: A bitmask of possible file properties. + :returns: ``true`` if the ``mode`` bitmask represents a block device. + :rtype: bool + + +.. js:function:: FS.isSocket(mode) + + Tests if the ``mode`` bitmask represents a socket. + + :param mode: A bitmask of possible file properties. + :returns: ``true`` if the ``mode`` bitmask represents a socket. + :rtype: bool -Returns true if the mode bitmask represents a socket. Paths ------ +======= + -FS.cwd() -^^^^^^^^ +.. js:function:: FS.cwd() -Return the current working directory. + Gets the current working directory. -FS.lookupPath(path, opts) -^^^^^^^^^^^^^^^^^^^^^^^^^ + :returns: The current working directory. + + -- path ``string`` -- opts ``object`` -- parent ``bool`` default = false -- follow ``bool`` default = false +.. js:function:: FS.lookupPath(path, opts) -Lookups up the incoming path and returns an object of the format: + Lookups up the incoming path and returns an object containing both the resolved path and node. + + The ``opts`` allow you to specify whether the object or it's parent component, and whether a symlink or the item it points to are returned. For example: :: + + var lookup = FS.lookupPath(path, { parent: true }); + + :param string path: The incoming path. + :param object opts: Options for the path: + + - **parent** (*bool*) + If true, stop resolving the path once the next to the last component is reached. + For example, for the path ``/foo/bar`` with ``{ parent: true }``, would return receive back an object representing ``/foo``. The default is ``false``. + - **follow** (*bool*) + If true, follow the last component if it is a symlink. + For example, consider a symlink ``/foo/symlink`` that links to ``/foo/notes.txt``. if ``{ follow: true }``, an object representing ``/foo/notes.txt`` would be returned. If ``{ follow: false }`` an object representing the symlink file would be returned. The default is ``false``. -:: + :returns: an object with the the format: + + .. code-block:: JavaScript - { - path: resolved_path, - node: resolved_node - } + { + path: resolved_path, + node: resolved_node + } + :throws ERRNO_CODES.ELOOP: Lookup caught in a loop (recursive lookup is too deep or there are too many consecutive symlinks). -The ``parent`` option says to stop resolving the path once the next to -the last component is reached. For example, for the path ``/foo/bar`` -with ``{ parent: true }``, would return receive back an object -representing ``/foo``. -The ``follow`` option says whether to follow the last component in the -case that is is a symlink. To illustrate, let's say there exists a -symlink ``/foo/symlink`` that links to ``/foo/notes.txt``. If -``/foo/symlink`` is looked up with ``{ follow: false }`` an object -representing the symlink file itself would be returned. However if -``{ follow: true }`` is passed, an object representing -``/foo/notes.txt`` would be returned. -FS.getPath(node) -^^^^^^^^^^^^^^^^ +.. js:function:: FS.getPath(node) -Takes in a node object and return the absolute path to it, accounting -for mounts. + Gets the absolute path to ``node``, accounting for mounts. + + :param node: The current node. + :returns: The absolute path to ``node``. diff --git a/site/source/docs/api_reference/advanced-apis.rst b/site/source/docs/api_reference/advanced-apis.rst index 704579a8ae52a..b8f2b90650c47 100644 --- a/site/source/docs/api_reference/advanced-apis.rst +++ b/site/source/docs/api_reference/advanced-apis.rst @@ -1,6 +1,6 @@ -========================================== -Advanced APIs (ready-for-review) -========================================== +============= +Advanced APIs +============= This section lists APIs that are not suitable for general use, but which may be useful to developers in some circumstances. These include APIs that are difficult or complicated to use, or which are intended primarily for Emscripten developers. @@ -34,6 +34,8 @@ allocate() =========== ``allocate()`` is documented in `preamble.js `_ and marked as *internal* because it is difficult to use (it has been optimized for multiple syntaxes to save space in generated code). Normally developers should instead allocate memory using ``_malloc()``, initialize it with :js:func:`setValue`, etc., but this may be useful for advanced developers in certain cases. + +.. todo:: **HamishW** It would be useful to have proper documentation of ``allocate()`` here. This has been deferred in the short term. Module.Runtime @@ -41,5 +43,5 @@ Module.Runtime ``Module.Runtime`` gives access to low-level runtime functionality. Some of these, for example ``Runtime.stackSave()`` and ``Runtime.stackRestore()`` may be useful for advanced users. -.. todo:: **HamishW** It would be useful to expand on what is offered by Module.Runtime +.. todo:: **HamishW** It would be useful to expand on what is offered by ``Module.Runtime``. This has been deferred. diff --git a/site/source/docs/api_reference/device-orientation-axes.png b/site/source/docs/api_reference/device-orientation-axes.png new file mode 100644 index 0000000000000..8e1af990acb51 Binary files /dev/null and b/site/source/docs/api_reference/device-orientation-axes.png differ diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 9b96292634e1c..e7ae8eecca574 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -1,8 +1,8 @@ .. _emscripten-h: -================================ -Emscripten.h (ready-for-review) -================================ +============ +Emscripten.h +============ This page documents the public C++ APIs provided by `emscripten.h `_. diff --git a/site/source/docs/api_reference/html5.h.rst b/site/source/docs/api_reference/html5.h.rst index e12b753cdbc2d..6d4d37c26eb4b 100644 --- a/site/source/docs/api_reference/html5.h.rst +++ b/site/source/docs/api_reference/html5.h.rst @@ -1,14 +1,16 @@ -============================ -html5.h (ready-for-review) -============================ +======= +html5.h +======= -This page documents the C++ APIs provided by `html5.h `_. +The C++ APIs in `html5.h `_ define the Emscripten low-level glue bindings to interact with HTML5 events from native code. -.. tip:: The C++ APIs map closely to their equivalent HTML5 JavaScript APIs. The HTML5 specifications listed below provide additional detailed reference "over and above" the information provided in this document. +.. tip:: The C++ APIs map closely to their :ref:`equivalent HTML5 JavaScript APIs `. The HTML5 specifications listed below provide additional detailed reference "over and above" the information provided in this document. In addition, the :ref:`test-example-code-html5-api` can be reviewed to see how the code is used. -These APIs define the Emscripten low-level glue bindings for interfacing with the following HTML5 APIs: +.. _specifications-html5-api: + +The HTML5 specifications for APIs that are mapped by **html5.h** include: - `DOM Level 3 Events: Keyboard, Mouse, Mouse Wheel, Resize, Scroll, Focus `_. - `Device Orientation Events for gyro and accelerometer `_. @@ -146,42 +148,42 @@ Most functions in this API return a result of type :c:data:`EMSCRIPTEN_RESULT`. This type is used to return the result of most functions in this API. Positive values denote success, while zero and negative values signal failure. Possible values are listed below. -.. c:macro:: EMSCRIPTEN_RESULT_SUCCESS + .. c:macro:: EMSCRIPTEN_RESULT_SUCCESS - The operation succeeded. + The operation succeeded. -.. c:macro:: EMSCRIPTEN_RESULT_DEFERRED + .. c:macro:: EMSCRIPTEN_RESULT_DEFERRED - The requested operation cannot be completed now for :ref:`web security reasons`, and has been deferred for completion in the next event handler. - -.. c:macro:: EMSCRIPTEN_RESULT_NOT_SUPPORTED + The requested operation cannot be completed now for :ref:`web security reasons`, and has been deferred for completion in the next event handler. + + .. c:macro:: EMSCRIPTEN_RESULT_NOT_SUPPORTED - The given operation is not supported by this browser or the target element. This value will be returned at the time the callback is registered if the operation is not supported. + The given operation is not supported by this browser or the target element. This value will be returned at the time the callback is registered if the operation is not supported. -.. c:macro:: EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED + .. c:macro:: EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED - The requested operation could not be completed now for :ref:`web security reasons`. It failed because the user requested the operation not be deferred. + The requested operation could not be completed now for :ref:`web security reasons`. It failed because the user requested the operation not be deferred. -.. c:macro:: EMSCRIPTEN_RESULT_INVALID_TARGET + .. c:macro:: EMSCRIPTEN_RESULT_INVALID_TARGET - The operation failed because the specified target element is invalid. + The operation failed because the specified target element is invalid. -.. c:macro:: EMSCRIPTEN_RESULT_UNKNOWN_TARGET + .. c:macro:: EMSCRIPTEN_RESULT_UNKNOWN_TARGET - The operation failed because the specified target element was not found. + The operation failed because the specified target element was not found. -.. c:macro:: EMSCRIPTEN_RESULT_INVALID_PARAM + .. c:macro:: EMSCRIPTEN_RESULT_INVALID_PARAM - The operation failed because an invalid parameter was passed to the function. + The operation failed because an invalid parameter was passed to the function. -.. c:macro:: EMSCRIPTEN_RESULT_FAILED + .. c:macro:: EMSCRIPTEN_RESULT_FAILED - Generic failure result message, returned if no specific result is available. + Generic failure result message, returned if no specific result is available. -.. c:macro:: EMSCRIPTEN_RESULT_NO_DATA + .. c:macro:: EMSCRIPTEN_RESULT_NO_DATA - The operation failed because no data is currently available. + The operation failed because no data is currently available. @@ -199,14 +201,14 @@ Defines .. c:macro:: DOM_KEY_LOCATION - The location of the key on the keyboard; one of the :c:data:`DOM_KEY_LOCATION_XXX values `. + The location of the key on the keyboard; one of the values below. -.. c:macro:: DOM_KEY_LOCATION_STANDARD - DOM_KEY_LOCATION_LEFT - DOM_KEY_LOCATION_RIGHT - DOM_KEY_LOCATION_NUMPAD + .. c:macro:: DOM_KEY_LOCATION_STANDARD + DOM_KEY_LOCATION_LEFT + DOM_KEY_LOCATION_RIGHT + DOM_KEY_LOCATION_NUMPAD - Locations of the key on the keyboard. + Locations of the key on the keyboard. Struct ------ @@ -716,8 +718,18 @@ Struct double beta double gamma - The orientation of the device in terms of the transformation from a coordinate frame fixed on the Earth to a coordinate frame fixed in the device. - + The `orientation `_ of the device in terms of the transformation from a coordinate frame fixed on the Earth to a coordinate frame fixed in the device. + + The image (source: `dev.opera.com `_) and definitions below illustrate the co-ordinate frame: + + - :c:type:`~EmscriptenDeviceOrientationEvent.alpha`: the rotation of the device around the Z axis. + - :c:type:`~EmscriptenDeviceOrientationEvent.beta`: the rotation of the device around the X axis. + - :c:type:`~EmscriptenDeviceOrientationEvent.gamma`: the rotation of the device around the Y axis. + + .. image:: device-orientation-axes.png + :target: https://developer.mozilla.org/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes#Device_Orientation_API + :alt: Image of device showing X, Y, Z axes + .. c:member:: EM_BOOL absolute diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index 13c5d58cd1c04..02e3e5eeadb6c 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -1,6 +1,6 @@ -======================================================= -preamble.js (ready-for-review) -======================================================= +=========== +preamble.js +=========== The JavaScript APIs in `preamble.js `_ provide programmatic access for interacting with the compiled C code, including: calling compiled C functions, accessing memory, converting pointers to JavaScript ``Strings`` and ``Strings`` to pointers (with different encodings/formats), and other convenience functions. @@ -36,7 +36,7 @@ Calling compiled C functions from JavaScript .. note:: - ``ccall`` uses the C stack for temporary values. If you pass a string then it is only "alive" until the call is complete. If the code being called saves the pointer to be used later, it may point to invalid data. - - If you need a string to live forever, you can create it, for example, using ``malloc`` and :js:func:`writeStringToMemory`. However, you must later delete it manually! + - If you need a string to live forever, you can create it, for example, using ``_malloc`` and :js:func:`writeStringToMemory`. However, you must later delete it manually! - LLVM optimizations can inline and remove functions, after which you will not be able to call them. Similarly, function names minified by the *Closure Compiler* are inaccessible. In either case, the solution is to add the functions to the ``EXPORTED_FUNCTIONS`` list when you invoke *emcc* : :: @@ -79,7 +79,7 @@ Calling compiled C functions from JavaScript .. note:: - ``cwrap`` uses the C stack for temporary values. If you pass a string then it is only "alive" until the call is complete. If the code being called saves the pointer to be used later, it may point to invalid data. - - If you need a string to live forever, you can create it, for example, using ``malloc`` and :js:func:`writeStringToMemory`. However, you must later delete it manually! + - If you need a string to live forever, you can create it, for example, using ``_malloc`` and :js:func:`writeStringToMemory`. However, you must later delete it manually! - LLVM optimizations can inline and remove functions, after which you will not be able to "wrap" them. Similarly, function names minified by the *Closure Compiler* are inaccessible. In either case, the solution is to add the functions to the ``EXPORTED_FUNCTIONS`` list when you invoke *emcc* : :: @@ -109,7 +109,7 @@ Accessing memory .. note:: - :js:func:`setValue` and :js:func:`getValue` only do *aligned* writes and reads. - - The ``type`` is an LLVM IR type (one of ``i8``, ``i16``, ``i32``, ``i64``, ``float``, ``double``, or a pointer type like ``i8*`` or just *), not JavaScript types as used in :js:func:`ccall` or :js:func:`cwrap`. This is a lower-level operation, and we do need to care what specific type is being used. + - The ``type`` is an LLVM IR type (one of ``i8``, ``i16``, ``i32``, ``i64``, ``float``, ``double``, or a pointer type like ``i8*`` or just ``*``), not JavaScript types as used in :js:func:`ccall` or :js:func:`cwrap`. This is a lower-level operation, and we do need to care what specific type is being used. :param ptr: A pointer (number) representing the memory address. :param value: The value to be stored @@ -125,7 +125,7 @@ Accessing memory .. note:: - :js:func:`setValue` and :js:func:`getValue` only do *aligned* writes and reads! - - The ``type` is an LLVM IR type (one of ``i8``,``i16``,``i32``,``i64``,``float``,``double`, or a pointer type like `i8*` or just *), not JavaScript types as used in :js:func:`ccall` or :js:func:`cwrap`. This is a lower-level operation, and we do need to care what specific type is being used. + - The ``type`` is an LLVM IR type (one of ``i8``, ``i16``, ``i32``, ``i64``, ``float``, ``double``, or a pointer type like ``i8*`` or just ``*``), not JavaScript types as used in :js:func:`ccall` or :js:func:`cwrap`. This is a lower-level operation, and we do need to care what specific type is being used. :param ptr: A pointer (number) representing the memory address. :param type: An LLVM IR type as a string (see "note" above). @@ -313,9 +313,7 @@ Stack trace Type accessors for Typed Arrays Mode 2 ========================================== -When using :ref:`typed-arrays-mode-2` a type array buffer is used to represent memory, with different views into it giving access to the different types. The views for accessing different types of memory are listed below. - -.. COMMENT (not rendered): **HamishW** Link to TO TYPED ARRAYS MODE2 DOCUMENTATION when this is ported +When using :ref:`typed-arrays-mode-2` a typed array buffer (``ArrayBuffer``) is used to represent memory, with different views into it giving access to the different types. The views for accessing different types of memory are listed below. .. js:data:: HEAP8 diff --git a/site/source/docs/contributing/AUTHORS.rst b/site/source/docs/contributing/AUTHORS.rst index 2aab2cf82a464..ed6e62e78349c 100644 --- a/site/source/docs/contributing/AUTHORS.rst +++ b/site/source/docs/contributing/AUTHORS.rst @@ -1,10 +1,12 @@ +.. _emscripten-authors: + ============================ AUTHORS (ready-for-review) ============================ The `AUTHORS `_ file lists everyone who has contributed to Emscripten. -.. note :: Authors must add themselves to the `AUTHORS `_ file (**incoming** branch) before :doc:`contributing `. This act licenses their changes under the project’s :doc:`open source licenses (MIT/LLVM) `. Note that the developer retains copyright. +.. note :: Authors must add themselves to the `AUTHORS `_ file (**incoming** branch) before :doc:`contributing `. This act licenses their changes under the project’s :ref:`open source licenses (MIT/LLVM) `. Note that the developer retains copyright. The contributors for releases up to Emscripten |release| inclusive (|today|) are listed below. diff --git a/site/source/docs/contributing/building_from_source/Getting-started-on-Mac-OS-X.rst b/site/source/docs/contributing/building_from_source/Getting-started-on-Mac-OS-X.rst index 376a6580ce911..51e4f45d8b08c 100644 --- a/site/source/docs/contributing/building_from_source/Getting-started-on-Mac-OS-X.rst +++ b/site/source/docs/contributing/building_from_source/Getting-started-on-Mac-OS-X.rst @@ -84,6 +84,8 @@ Note for `homebrew `__ users: By default, git will clone the emscripten 'incoming' branch, which is the branch where the newest developments of Emscripten occur. If you want to use a more stable branch, switch to the 'master' branch: - cd ~/emscripten - git checkout master +.. _getting-started-on-osx-install-python2: + 10. Setup 'python2': (this step is needed to workaround a bug reported in `#763 `__) - In terminal, type 'python2 --version'. If you get a "command not found", type the following: :: diff --git a/site/source/docs/contributing/contributing.rst b/site/source/docs/contributing/contributing.rst index 6a18452c52aa8..6ee17a8158894 100644 --- a/site/source/docs/contributing/contributing.rst +++ b/site/source/docs/contributing/contributing.rst @@ -1,8 +1,8 @@ .. _contributing: -================================================ -Contributing (ready-for-review) -================================================ +============ +Contributing +============ Anyone can contribute to Emscripten — if you find it useful and want to help improve the project, follow the suggestions below. Feel free to file :ref:`bug reports `, :ref:`join the discussion ` and share your own ideas with the community! @@ -25,7 +25,7 @@ Branches of interest Submitting patches -===================== +================== Patches should be submitted as *pull requests* to the **incoming** branch. diff --git a/site/source/docs/getting_started/downloads.rst b/site/source/docs/getting_started/downloads.rst index 26139da587ada..5909d8d36bd58 100644 --- a/site/source/docs/getting_started/downloads.rst +++ b/site/source/docs/getting_started/downloads.rst @@ -1,76 +1,83 @@ +.. _sdk-download-and-install: + ====================================================== -Download and install (under-construction) +Download and install (ready-for-review) ====================================================== +.. note:: The *Emscripten SDK* provides the whole Emscripten toolchain (*Clang*, *Python*, *Node.js* and *Visual Studio* integration) in a single easy-to-install package, with integrated support for :ref:`updating to newer SDKs ` as they are released. -.. note:: The *Emscripten SDK* provides the whole Emscripten toolchain (*Clang*, *Python*, *Node.js* and *Visual Studio* integration) in a single easy-to-install package, with integrated support for updating to newer Emscripten versions as they are released. - -.. tip:: If you are :doc:`contributing <../contributing/contributing>` to Emscripten you should :ref:`set up Emscripten from source `. - +.. tip:: If you are :doc:`contributing <../contributing/contributing>` to Emscripten (or if you wish to build 32bit versions of the SDK) you should :ref:`set up Emscripten from source `. -Downloads -============== -To get started with Emscripten development, grab one of the SDK packages below: +SDK Downloads +================== +Download one of the SDK installers below to get started with Emscripten development. The Windows NSIS installers are the easiest to set up, while the portable SDKs can be moved between computers and do not require administration privileges. Windows ----------- +------- -Emscripten SDK Web Installer is a NSIS installer that always gets you the latest Emscripten SDK from the web. +- `Emscripten SDK Web Installer `_ (emsdk-1.21.0-web-64bit.exe) + An NSIS installer which fetches and installs the latest Emscripten SDK from the web. To :ref:`install `, download and open the file, then follow the installer prompts. -- `emsdk-1.21.0-web-64bit.exe `_ -- ?32 bit +- `Emscripten SDK Offline Installer `_ (emsdk-1.21.0-full-64bit.exe) + An NSIS installer that bundles together the current Emscripten toolchain as an offline-installable package. To :ref:`install `, download and open the file, then follow the installer prompts. -Emscripten SDK Offline Installer is a NSIS installer that bundles together the Emscripten toolchain as an offline-installable package. +- `Portable Emscripten SDK for Windows `_ (emsdk-1.21.0-portable-64bit.zip) + A zipped package of the SDK that does not require system installation privileges. To install, follow :ref:`these ` instructions. +Linux and Mac OS X +------------------ + +- `Portable Emscripten SDK for Linux and OS X `_ (emsdk-portable.tar.gz) + A tar.gz archive package of the SDK that does not require system installation privileges. To install, follow :ref:`the general instructions ` and :ref:`platform specific notes `. -- `emsdk-1.21.0-full-64bit.exe `_ -- ?32 bit -Portable Emscripten SDK is a zipped package of the Emscripten SDK that does not require system installation privileges. Just unzip and go! +.. _sdk-installation-instructions: -- `emsdk-1.21.0-portable-64bit.zip `_ -- 32bit? +Installation instructions +========================= +Check the relevant section below for instructions on installing your selected package. Then check the :ref:`Platform-specific notes ` at the end of the section to address any further prerequisites that exist for your system. +.. _windows-installation_instructions-NSIS: -Linux and Mac OS X -------------------- - -Emscripten SDK is available as a portable web-installer for Linux and OS X. This does not require system installation privileges. Just unzip and go! +Windows: Installing using an NSIS installer +-------------------------------------------- -- `emsdk-portable.tar.gz `_ +The NSIS installers register the Emscripten SDK as a 'standard' Windows application. To install the SDK, download an NSIS .exe file, double-click on it, and run through the installer to perform the installation. +After the installer finishes, the full Emscripten toolchain will be available in the directory that was chosen during the installation, and no other steps are necessary. If your system has *Visual Studio 2010* installed, the :term:`vs-tool` MSBuild plugin will be automatically installed as well. -Package installation instructions for Mac OSX and Windows -=========================================================== -Check the relevant section below for what to do with the package you just downloaded, then check the Platform-specific notes at the end of the section to find out about and address any further prerequisites that exist for your system. +.. _all-os-installation_instructions-portable-SDK: -Windows: Installing using an NSIS installer --------------------------------------------- +Windows, OSX and Linux: Installing the Portable SDK +---------------------------------------------------- -The NSIS installers register the Emscripten SDK as a 'standard' Windows application. To install the SDK, download an NSIS .exe file (see above), double-click on it, and run through the installer to perform the installation. After the installer finishes, the full Emscripten toolchain will be available in the directory that was chosen during the installation, and no other steps are necessary. If your system has Visual Studio 2010 installed, the vs-tool MSBuild plugin will be automatically installed as well. +The *Portable Emscripten SDK* is a no-installer version of the SDK package. It is identical to the NSIS installer, except that it does not interact with the Windows registry. This allows Emscripten to be used on a computer without administrative privileges, and means that the installation to be migrated from one location (directory or computer) to another by simply copying/zipping up the directory contents. +If you want to use the *Portable Emscripten SDK*, the initial setup process is as follows: -Windows, OSX and Linux: Installing the Portable SDK --------------------------------------------------------- +1. Download and unzip the portable SDK package to a directory of your choice. This directory will contain the Emscripten SDK. +#. Open a command prompt to the directory of the SDK and run the following :ref:`emsdk ` commands to get the latest SDK tools and set them as :term:`active `. Note that on Mac OS X, invoke the tool with **./emsdk** instead of **emsdk**: :: -The Portable Emscripten SDK is a no-installer version of the SDK package. It is identical to the NSIS installer, except that it does not interact with the Windows registry. This allows Emscripten to be used on a computer without administrative privileges, and enables us to migrate the installation from one location (directory or computer) to another by just copying/zipping up the directory contents. + # Fetch the latest registry of available tools. + emsdk update + + # Download and install the latest SDK tools. + emsdk install latest -If you want to use the Portable Emscripten SDK, the initial setup process is as follows: + # Make the "latest" SDK "active" + emsdk activate latest -1. Download and unzip the portable SDK package to a directory of your choice (see above). This directory will contain the Emscripten SDK. -#. Open a command prompt to the directory of the SDK. -#. Run ``emsdk update`` (``./emsdk update`` on OSX). This will fetch the latest registry of available tools. -#. Run ``emsdk install latest`` (``./emsdk install latest`` on OSX). This will download and install the latest SDK tools. -#. Run ``emsdk activate latest`` (``./emsdk activate latest`` on OSX). This will set up the necessary paths to point to the SDK correctly. +Whenever you change the location of the Portable SDK (e.g. take it to another computer), re-run the final command: ``emsdk activate latest`` -Whenever you change the location of the Portable SDK (e.g. take it to another computer), re-run step 5. +.. tip:: The instructions above can also be used to get new SDKs, as they are released. +.. _platform-notes-installation_instructions-portable-SDK: Platform-specific notes ---------------------------- @@ -78,121 +85,69 @@ Platform-specific notes Mac OS X ++++++++ -- On OSX (and Linux), the git tool will not be installed automatically. Git is not a required core component, and is only needed if you want to use one of the development branches **emscripten-incoming** or **emscripten-master** directly, instead of the fixed releases. To install git on OSX, you can +- *Git* is not installed automatically. Git is only needed if you want to use tools from one of the development branches **emscripten-incoming** or **emscripten-master** directly. To install git on OSX: - 1. Install XCode, and in XCode, install XCode Command Line Tools. This will provide git to the system PATH. For more help on this step, see http://stackoverflow.com/questions/9329243/xcode-4-4-command-line-tools - 2. Install git directly from http://git-scm.com/ - -- Also, on OSX, *Java* is not bundled with the Emscripten SDK. After installing emscripten via emsdk, typing 'emcc --help' should pop up a OSX dialog "Java is not installed. To open Java, you need a Java SE 6 runtime. Would you like to install one now?" that will automatically download a Java runtime to the system. -- Emscripten requires the command line tool 'python2' to be present on OSX. On default OSX installations, this does not exist. To manually work around this issue, see step 10 at :doc:`Getting-started-on-Mac-OS-X` - - -Linux -++++++++ - -- On Linux, prebuilt binaries of tools are not available. Installing a tool will automatically clone and build that tool from the sources inside **emsdk** directory. Emsdk does not interact with Linux package managers on the behalf of the user, nor does it install any tools to the system. All file changes are done inside the ``emsdk/`` directory. -- Because *emsdk* builds software from the source on Linux, the system must have a working compiler environment available. -- Emsdk does not provide *Python*, *node.js* or *Java* on Linux. The user is expected to install these beforehand with the system package manager. - - - -SDK concepts -============== - -The Emscripten SDK is effectively a small package manager for tools that are used in conjunction with Emscripten. The following glossary highlights the important concepts to help understanding the internals of the SDK. - -Tool - The basic unit of software bundled in the SDK. A Tool has a name and a version. For example, 'clang-3.2-32bit' is a Tool that contains the 32-bit version of the Clang v3.2 compiler. - -SDK - A set of tools. For example, 'sdk-1.5.6-32bit' is an SDK consisting of the tools clang-3.2-32bit, node-0.10.17-32bit, python-2.7.5.1-32bit and emscripten-1.5.6. - -Active Tool/SDK - Emscripten stores compiler configuration in a user-specific file **~/.emscripten**. This file points to paths for Emscripten, Python, Clang and so on. If the file ~/.emscripten is configured to point to a Tool in a specific directory, then that tool is denoted as being **active**. The Emscripten Command Prompt always gives access to the currently active Tools. This mechanism allows switching between different SDK versions easily. - -emsdk - This is the name of the manager script that Emscripten SDK is accessed through. Most operations are of the form ``emsdk command``. To access the *emsdk* script, launch the Emscripten Command Prompt. + 1. Install XCode and the XCode Command Line Tools. This will provide *git* to the system PATH. For more help on this step, see `this stackoverflow post `_. + 2. Install git directly from http://git-scm.com/. +- *Java* is not bundled with the Emscripten SDK. After installing Emscripten via :ref:`emsdk `, typing ``emcc --help`` should pop up a dialog which will automatically download a Java Runtime to the system: :: + Java is not installed. To open Java, you need a Java SE 6 runtime. + Would you like to install one now? -SDK maintenance -============================ +- The *python2* command line tool is not present on OSX by default. To manually work around this issue, follow step 10 in :ref:`Getting-started-on-Mac-OS-X ` -The following tasks are common with the Emscripten SDK: -How do I work the emsdk utility? - Run ``emsdk help`` or just ``emsdk`` to get information about all available commands. - -How do I check the installation status and version of the SDK and tools? - To get a list of all currently installed tools and SDK versions, and all available tools, run ``emsdk list``. *A line will be printed for each tool/SDK that is available for installation.* The text ``INSTALLED`` will be shown for each tool that has already been installed. If a tool/SDK is currently active, a star (\*) will be shown next to it. Run ``emsdk_env.bat`` (Windows) or ``source ./emsdk_env.sh`` (Linux and OSX) to set up the environment for the calling terminal. - -How do I install a tool/SDK version? - Run the command ``emsdk install `` to download and install a new tool or an SDK version. - -How do I remove a tool or an SDK? - Run the command ``emsdk uninstall `` to delete the given tool or SDK from the local harddrive completely. - -How do I check for updates to the Emscripten SDK? - The command ``emsdk update`` will fetch package information for all new tools and SDK versions. After that, run ``emsdk install `` to install a new version. +Linux +++++++++ -How do I change the currently active SDK version? - You can toggle between different tools and SDK versions by running ``emsdk activate ``. Activating a tool will set up ``~/.emscripten`` to point to that particular tool. - -How do I install an old Emscripten compiler version? - Emsdk contains a history of old compiler versions that you can use to maintain your migration path. Type ``emsdk list --old`` to get a list of archived tool and SDK versions, and ``emsdk install `` to install it. +.. note:: Pre-built binaries of tools are not available on Linux. Installing a tool will automatically clone and build that tool from the sources inside **emsdk** directory. *Emsdk* does not interact with Linux package managers on the behalf of the user, nor does it install any tools to the system. All file changes are done inside the **emsdk/** directory. - On Windows, you can directly install an old SDK version by using one of the archived offline NSIS installers. See the `Archived releases`_ section down below. - - .. COMMENT HamishW This is new for MDN. Check if really should belong here. I think may already be up the top too. - -How do I track the latest Emscripten development with the SDK? - A common and supported use case of the Emscripten SDK is to enable the workflow where you directly interact with the github repositories. This allows you to obtain new features and latest fixes immediately as they are pushed to the github repository, without having to wait for release to be tagged. You do not need a github account or a fork of Emscripten to do this. To switch to using the latest upstream git development branch ``incoming``, run the following: +- The system must have a working compiler environment available (because *emsdk* builds software from the source). +- *Python*, *node.js* or *Java* are not provided by *emsdk*. The user is expected to install these beforehand with the *system package manager*. +- *Git* is not installed automatically. Git is only needed if you want to use tools from one of the development branches **emscripten-incoming** or **emscripten-master**. - :: +.. todo:: **HamishW** Add instructions for installing Git on Linux. - emsdk install git-1.8.3 # Install git. Skip if the system already has it. - emsdk install sdk-incoming-64bit # Clone+pull the latest kripken/emscripten/incoming. - emsdk activate sdk-incoming-64bit # Set the incoming SDK as the currently active one. - If you want to use the upstream stable branch ``master``, then replace ``-incoming-`` with ``-master-`` above. - - .. COMMENT HamishW This is new for MDN. Check if really should belong here. +.. _updating-the-emscripten-sdk: - -How do I use my own Emscripten github fork with the SDK? - It is also possible to use your own fork of the Emscripten repository via the SDK. This is achieved with standard git machinery, so there if you are already acquainted with working on multiple remotes in a git clone, these steps should be familiar to you. This is useful in the case when you want to make your own modifications to the Emscripten toolchain, but still keep using the SDK environment and tools. To set up your own fork as the currently active Emscripten toolchain, first install the ``sdk-incoming`` SDK like shown in the previous section, and then run the following commands in the emsdk directory: +Updating the SDK +================ - :: +.. tip:: You only need to install the SDK once! After that you can update to the latest SDK at any time using :ref:`SDK Package Manager (emsdk) `. - cd emscripten/incoming - # Add a git remote link to your own repository. - git remote add myremote https://github.com/mygituseraccount/emscripten.git - # Obtain the changes in your link. - git fetch myremote - # Switch the emscripten-incoming tool to use your fork. - git checkout -b myincoming --track myremote/incoming +Type the following (omitting comments) on the :ref:`Emscripten Command Prompt `: :: - In this way you can utilize the Emscripten SDK tools while using your own git fork. You can switch back and forth between remotes via the ``git checkout`` command as usual. + # Fetch the latest registry of available tools. + emsdk update + # Download and install the latest SDK tools. + emsdk install latest + # Set up the compiler configuration to point to the "latest" SDK. + emsdk activate latest - .. COMMENT HamishW This is new for MDN. Check if really should belong here. +The package manager can do many other maintenance tasks, ranging from fetching specific old versions of the SDK through to using the :ref:`versions of the tools on Github ` (or even your own fork). Check out all the possibilities in the :ref:`emsdk_howto`. +.. _downloads-uninstall-the-sdk: - Uninstalling the Emscripten SDK ======================================================== -If you installed the SDK using a NSIS installer on Windows, launch 'Control Panel' -> 'Uninstall a program' -> 'Emscripten SDK'. +If you installed the SDK using a NSIS installer on Windows, launch: **Control Panel -> Uninstall a program -> Emscripten SDK**. If you want to remove a Portable SDK, just delete the directory containing the Portable SDK. +It is also possible to :ref:`remove specific SDKs using emsdk `. +.. _archived-nsis-windows-sdk-releases: + Archived releases ================= -You can always install old SDK and compiler toolchains via the latest emsdk. If you need to fall back to an old version, download the Portable SDK version and use that to install a previous version of a tool. All old tool versions are available by typing `emsdk list --old`. +You can always install old SDK and compiler toolchains via the latest :ref:`emsdk `. If you need to fall back to an old version, download the Portable SDK version and use that to install a previous version of a tool. All old tool versions are available by typing ``emsdk list --old``. -On Windows, you can install one of the **old versions** via an offline NSIS installer: +On Windows, you can also install one of the **old versions** via an offline NSIS installer: - `emsdk-1.16.0-full-64bit.exe `_ (first stable fastcomp release) - `emsdk-1.13.0-full-32bit.exe `_ (a unstable first fastcomp release with Clang 3.3) @@ -208,3 +163,4 @@ On Windows, you can install one of the **old versions** via an offline NSIS inst A snapshot of all tagged releases (not SDKs) can be found in `emscripten/releases `_. + diff --git a/site/source/docs/index.rst b/site/source/docs/index.rst index a1866cb79bae8..5c2e0b4fbd64d 100644 --- a/site/source/docs/index.rst +++ b/site/source/docs/index.rst @@ -14,6 +14,7 @@ Documentation Home (under-construction) packaging/index contributing/index api_reference/index + tools_reference/index site/index diff --git a/site/source/docs/introducing_emscripten/bug_reports.rst b/site/source/docs/introducing_emscripten/bug_reports.rst index 32828a943b1b0..de177d5026131 100644 --- a/site/source/docs/introducing_emscripten/bug_reports.rst +++ b/site/source/docs/introducing_emscripten/bug_reports.rst @@ -1,8 +1,8 @@ .. _bug-reports: -========================================= -Bug Reporting (ready-for-review) -========================================= +============= +Bug Reporting +============= All bugs should be filed in the GitHub `main `_ Emscripten repository `Issue Tracker `_. @@ -18,15 +18,17 @@ Please supply as much relevant information as possible, including: Fastcomp LLVM-Backend and Clang bugs -===================================== +==================================== -:doc:`LLVM-Backend` bugs may instead be posted to the appropriate `Emscripten LLVM fork `_ or `Emscripten Clang fork `_ **if you are certain** that the bug is specific to these repositories. If uncertain, bugs must be posted to the `main repository `_. +:ref:`LLVM Backend ` bugs may instead be posted to the appropriate `Emscripten LLVM fork `_ or `Emscripten Clang fork `_ **if you are certain** that the bug is specific to these repositories. If uncertain, bugs must be posted to the `main repository `_. Pull requests must (of course) go to the proper repository. +.. _site-and-documentation-bug-reports: + Site and documentation bugs -======================== +=========================== Documentation (site) bugs should be filed in the same `Issue Tracker `_. @@ -37,6 +39,3 @@ Include relevant information including: - Suggestions for a possible solution. .. tip:: The `Page bug `_ link on the bottom-right of every page opens the Issue Tracker pre-seeded with the current page URL and title. - - - diff --git a/site/source/docs/introducing_emscripten/community.rst b/site/source/docs/introducing_emscripten/community.rst index e52b9165f7e8e..1657a3e99a710 100644 --- a/site/source/docs/introducing_emscripten/community.rst +++ b/site/source/docs/introducing_emscripten/community.rst @@ -1,6 +1,6 @@ -=========================================== -Community (ready-for-review) -=========================================== +========= +Community +========= Welcome to the Emscripten community! @@ -8,9 +8,9 @@ Welcome to the Emscripten community! .. _contact: Get in touch -=========================================== +============ -The best way to contact us is to use either the *mailing list* or *IRC*. +The best ways to contact us for support are the *mailing list* and the *IRC* channel. Ask questions, share your ideas, or just join the conversation. - Mailing list: `emscripten-discuss `_ - IRC: **#emscripten** on `irc.mozilla.org `_ @@ -24,7 +24,7 @@ Emscripten also has an *unofficial* presence on social media: Report a bug -============= +============ :ref:`Bug reports ` can be posted in the GitHub `Issue Tracker `_. @@ -33,7 +33,7 @@ Report a bug Blogs -========================= +===== Get the latest official Emscripten news on the blogs: `Developer blog (azakai) `_ and `Mozilla blog `_. @@ -43,6 +43,6 @@ In addition, other interesting blogs and demos are regularly shared on Twitter b Contribute -============ +========== Anyone can contribute to Emscripten. We've got some ideas to get you started on our :ref:`contributing` page. diff --git a/site/source/docs/introducing_emscripten/index.rst b/site/source/docs/introducing_emscripten/index.rst index 3a624dad3b325..1cced84271482 100644 --- a/site/source/docs/introducing_emscripten/index.rst +++ b/site/source/docs/introducing_emscripten/index.rst @@ -12,4 +12,3 @@ Introducing Emscripten (under-construction) bug_reports release_notes Talks-and-Publications - searching_site diff --git a/site/source/docs/introducing_emscripten/searching_site.rst b/site/source/docs/introducing_emscripten/searching_site.rst deleted file mode 100644 index 7730d01f94373..0000000000000 --- a/site/source/docs/introducing_emscripten/searching_site.rst +++ /dev/null @@ -1,5 +0,0 @@ -Searching this site (under-construction) -========================================= - -.. warning:: - Under Construction: diff --git a/site/source/docs/site/about.rst b/site/source/docs/site/about.rst index dd5feeab7c8ca..41e7c3967c89f 100644 --- a/site/source/docs/site/about.rst +++ b/site/source/docs/site/about.rst @@ -1,48 +1,65 @@ =============================== -About site (under-construction) +About site (ready-for-review) =============================== -The site is built using `Sphinx `_ (1.2.2), the (Python) open source tool used to create the official Python documentation, along with many other documentation sites. This is a very mature and stable tool, and was selected for, among other reasons, its support for defining API items and linking to them from code. - -The site uses a custom theme, which is based on the `Read the docs theme `_ - +The site is built using `Sphinx `_ (1.2.2), the open source tool used to create the official Python documentation and many other sites. This is a very mature and stable tool, and was selected for, among other reasons, its support for defining API items and linking to them from code. +The site uses a custom theme, which is based on the :ref:`read-the-docs-theme`. Page management markup ============================ .. warning:: This site is still under construction and includes both new content and content from the wiki. - To make it easy to manage documents during early review, "status" markup has been added to documents. You can search on this text in order to find articles which have questions or issues. At the end of the project a search on any of these should return "nothing" +To make it easy to manage documents while the site is being created, "status" markup has been added to the document titles. You can search on this text in order to find articles which have questions or issues (e.g. on `ready for review `_): + + - **wiki import** : The page has been imported automatically from the wiki. It has not been checked. When it is actively being worked on the article is next moved to *under construction*. + - **under construction** : The page is being worked on. It is still incomplete and not *ready for review*. + - **ready for review** : The page is ready for review. :ref:`contact` if you find any problems. + - **placeholder** : The page is a placeholder for a possible topic. The topic may not end up being created in the final build. + - If there is no header, the page is assumed to be published. + +In addition there is some markup in the body of the documents: -- "wiki-import" in the heading: The page has been imported automatically from the wiki - and not been checked. This is moved to "under construction" when the article is being properly reviewed. -- "under-construction" in the heading: The page is being worked on. Incomplete and not ready to review -- "placeholder" in the heading: The page is not being worked on, and may not even exist in the final build. Even if it exists it may not exist in the current location. -- "ready-for-review" in the heading - page is ready for review. -- "REMOVE FROM FINAL BUILDS" in the heading - page is a scratchpad or temporary file during development. To be removed/moved before publishing. -- If there is no header, the page is assumed to be published. -- "HamishW" in the body of the document - this is a specific question or issue with the document at that point + - **HamishW** : This is a specific question or issue with the document at this point. -You can find documents in each type using Search: e.g. on "under review". +By the end of the project all articles should be published and all of this page management markup removed. This section of the "About" page will then be removed. +.. todo:: **HamishW** Delete this whole section at the end of the project. At that point there should only be HamishW markup for possible Todos. + Note the search link immediately above too - this is to the kripken site and may need to change if the site moves. -Writing articles +Reporting bugs +============== + +Please :ref:`report documentation bugs ` as you would any other Emscripten bug. Help :ref:`fix them ` by updating existing documents or by creating new ones. + + +Searching the site ================== -TBD :doc:`placholder-to-give-me-warning-to-update` - +Searching returns only topics which contain **all** the specified keywords. + +.. tip:: Always start by searching for *single* words like "interacting" or "compiling". Generally this will be enough to find the relevant document. If not, you can refine the search by adding additional terms. + +Note that searches that include characters like "-" and "+" will not work. There is no support for logical operators. + + +.. _building-the-site: + Building the site ================== -The site sources are in the Emscripten repo, *incoming* branch, `/site `_ directory. Changes should be committed to the incoming branch. +The site sources are in the Emscripten *incoming* branch, `site `_ directory. Changes should be committed to the incoming branch. + +The site is published to the **kripken/emscripten-site** *gh-pages* branch (Github pages). -The site is published to the *gh-pages* branch as part of a site build. make html --------- -The site can be build from source on Ubuntu and Windows by navigating to the */emscripten/site* directory and using the command: :: +The site can be built from source on Ubuntu and Windows by navigating to the */emscripten/site* directory and using the command: :: + make clean make html Installing Sphinx @@ -53,19 +70,120 @@ Notes for installing Sphinx are provided `here `_. This section only attempts to highlight specific styles and features used on this site. + + The :ref:`building-the-site` section explains how to find the sources for articles and build the site. + +Site content is written using :term:`reStructured text`. We recommend you read the following articles to understand the syntax: + +* `reStructured text primer `_ +* `Sphinx Domains `_ (define and link to code items). +* `Inline markup `_ + + + + + +Style guide +----------- -Changes to the sphinx_rtd_theme theme -======================================= +This section has a few very brief recommendations to help authors use common style. + +.. tip:: We need you coding and writing content, not stuck writing perfect prose! Just do your best, and then :ref:`ask for editorial review `. + +**Spelling:** Where possible use US-English spelling. + +**Avoid idiomatic expressions**: These can be particularly confusing to non-native speakers (for example "putting your foot in your mouth" actually means to "say something embarrassing"). + +**Emphasis:** + + - **Bold** : use for file names, and UI/menu instructions (for example: "Press **OK** to do something") + - *Italic* : use for tool names - e.g. *Clang*, *emcc*, *Closure Compiler* + - ``monotype`` : use for inline code (where you can't link to the API reference) and for demonstrating tool command line options. + - otherwise emphasis should be used sparingly + + +**Lists**: Use a colon on the lead-in to the list. Capitalize the first letter and use a full-stop for each item. + + +How to link to a document or heading +------------------------------------- + +To link to a page, first define a globally unique reference before the page title (e.g. ``_my-page-reference``) then link to it using the `ref `_ role as shown: :: + + .. _my-page-reference: + + My Page Title + ============= + + This is the text of the section. + + To link to page use either of the options below: + ref:`my-reference-label` - the link text is the heading name after the reference + ref:`some text ` - the link text is "some text" + +This is a better approach than linking to documents using the *:doc:* role, because the links do not get broken if the articles are moved. + +This approach is also recommended for linking to arbitrary headings in the site. + +Note also that there are a number of other roles that are useful for linking - including `Sphinx Domains `_ for linking to code items, and **term** for linking to glossary terms. + + + +Recommended section/heading markup +------------------------------------- + +reStructured text `defines `_ section headings using a separate line of punctuation characters after (and optionally before) the heading text. The line of characters must be at least as long as the heading. For example: :: + + A heading + ========= + +Different punctuation characters are used to specify nested sections. Although the system does not mandate which punctuation character is used for each nested level, it is important to be consistent. The recommended heading levels are: :: + + ======================================= + Page title (top and bottom bars of "=") + ======================================= + + Level 1 heading (single bar of "=" below) + ========================================= + + Level 2 heading (single bar of "-" below) + ----------------------------------------- + + Level 3 heading (single bar of "+" below) + +++++++++++++++++++++++++++++++++++++++++ + + Level 4 heading (single bar of "~" below) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Working in markdown +------------------- + +New articles may be authored and discussed on the `wiki `_ using Markdown syntax before being included in the documentation set. The easiest way to convert these to restructured text is to use a tool like `Pandoc `_. + +.. note:: The *get_wiki.py* tool (**/site/source/get_wiki.py**) can be used to automate getting a snapshot of the wiki. It clones the wiki and calls *pandoc* on each file. The output is copied to a folder **wiki_static**. The tool also adds a heading, a note stating that the file is a "wiki snapshot", and fixes up links marked as "inline code" to matching links in the API Reference. + + +.. _read-the-docs-theme: + +Read the docs theme +=================== The site uses a modification of the `Read the docs theme `_ (this can be found in the source at */emscripten/site/source/_themes/emscripten_sphinx_rtd_theme*). @@ -90,3 +208,8 @@ The main changes to the original theme are listed below. - Changed to support 4 levels of depth in sidebar toc. - Centred theme. Made sidebar reach bottom of page using absolute positioning. + +Site license +============ + +The site is licensed under the same :ref:`emscripten-license` as the rest of Emscripten. Contributors to the site should add themselves to :ref:`emscripten-authors`. \ No newline at end of file diff --git a/site/source/docs/site/glossary.rst b/site/source/docs/site/glossary.rst new file mode 100644 index 0000000000000..6d0b0a3b69c88 --- /dev/null +++ b/site/source/docs/site/glossary.rst @@ -0,0 +1,55 @@ +=============================== +Glossary (under-construction) +=============================== + + + +.. glossary:: + :sorted: + + vs-tool + Visual Studio 2010 plugin to integrate MinGW, Clang and Emscripten to the VS IDE. Automatically added by the Emscripten SDK NSIS Installer if Visual Studio 2010 is present on the target system. Note, at time of writing this only supports Visual Studio 2010. + + +.. todo:: **HamishW** Is there a link we can put for the version support? Should remove the "Note, at time of writing" when fixed. + + +SDK Terms +========= + +The following terms are used when referring to the SDK and :ref:`emsdk`: + +.. glossary:: + + emsdk + The :ref:`emsdk ` management script is used to control which SDK and tools are present and :term:`active ` on an installation. Most operations are of the form ``emsdk command``. To access the *emsdk* script, launch the *Emscripten Command Prompt*. + + Tool + The basic unit of software bundled in the :term:`SDK`. A Tool has a name and a version. For example, **clang-3.2-32bit** is a tool that contains the 32-bit version of the *Clang* v3.2 compiler. Other tools include *Emscripten*, *Java*, *Git*, *Node*, etc. + + SDK + A set of :term:`tools `. For example, **sdk-1.5.6-32bit** is an SDK consisting of the tools: clang-3.2-32bit, node-0.10.17-32bit, python-2.7.5.1-32bit and emscripten-1.5.6. + + There are a number of different packages of the Emscripten SDKs including the :term:`Portable Emscripten SDK` and :term:`Windows NSIS Installer Emscripten SDK`. SDKs can be downloaded from :ref:`here `. + + Active Tool/SDK + The :term:`emsdk` can store multiple versions of :term:`tools ` and :term:`SDKs `. The active tools/SDK is the set of tools that are used by default on the *Emscripten Command Prompt*. This compiler configuration is stored in a user-specific persistent file (**~/.emscripten**) and can be changed using *emsdk*. + + Portable Emscripten SDK + A portable, no-installer, version of the SDK package. It is identical to the :term:`NSIS SDK installer `, except that it does not interact with the Windows registry. This allows Emscripten to be used on a computer without administrative privileges, and means that the installation to be migrated from one location (directory or computer) to another by simply copying/zipping up the directory contents. + + Windows NSIS Installer Emscripten SDK + A Windows NSIS installer of the Emscripten SDK. This registers the Emscripten SDK as a ‘standard’ Windows application. allow it to be installed and removed from Windows like any other app. + + + + + +Site / Sphinx +============== + +.. glossary:: + :sorted: + + reStructured text + Markup language used to define content on this site. See the `reStructured text primer `_. \ No newline at end of file diff --git a/site/source/docs/site/index.rst b/site/source/docs/site/index.rst index baabba6baa2d9..dbcb41cb7c2c9 100644 --- a/site/source/docs/site/index.rst +++ b/site/source/docs/site/index.rst @@ -6,5 +6,5 @@ Site Links (under-construction) :maxdepth: 1 about - + glossary diff --git a/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst b/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst index 1c7ef82ec9acd..5fc9fd5f30c21 100644 --- a/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst +++ b/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst @@ -35,3 +35,36 @@ After installing the vs-tool plugin, a new 'Emscripten' platform will appear to Note: If you copied the Emscripten platform properties from the Win32 platform, be sure to go and clean up any leftover Win32-specific #defines and other configuration from the Emscripten platform! + +Raw HTML for toggle text +========================= + +There is also a good example of a Sphinx plugin that could add this directive: http://scopatz.github.io/hiddencode/ + +.. raw:: html + + Installation instructions1 + + + +.. raw:: html + + +Some text that probably belongs in installing SDK from source. +======================================================================== + +This was cut from an SDK installation topic: + +"Run ``emsdk_env.bat`` (Windows) or ``source ./emsdk_env.sh`` (Linux and OSX) to set up the environment for the calling terminal." from topic "How do I check the installation status and version of the SDK and tools?". I think this is part of manual setup and doesn't belong here. \ No newline at end of file diff --git a/site/source/docs/tools_reference/emcmdprompt.rst b/site/source/docs/tools_reference/emcmdprompt.rst new file mode 100644 index 0000000000000..5a0573436418b --- /dev/null +++ b/site/source/docs/tools_reference/emcmdprompt.rst @@ -0,0 +1,23 @@ +.. _emcmdprompt: + +=================================================================== +Emscripten Command Prompt (emcmdprompt.bat) (ready-for-review) +=================================================================== + + +Purpose +============================================ + +The *Emscripten Command Prompt* is a Windows command prompt which has been configured with the current :term:`active ` settings for Emscripten development. + +The prompt is launched by executing **emcmdprompt.bat** using the normal Windows mechanisms (for example, type "Emscripten" in the Windows 8 start screen and then open, double-clicking in Windows Explorer, etc.). + + +Command line syntax +============================================ + +The tool is not intended to be run from the command line. + + + + diff --git a/site/source/docs/tools_reference/emsdk.rst b/site/source/docs/tools_reference/emsdk.rst new file mode 100644 index 0000000000000..466848c1f09bf --- /dev/null +++ b/site/source/docs/tools_reference/emsdk.rst @@ -0,0 +1,229 @@ +.. _emsdk: + +===================================================== +Emscripten SDK Manager (emsdk) (ready-for-review) +===================================================== + +**The Emscripten SDK management script (** ``emsdk`` **) is used to perform all SDK maintenance. You only need to "install" the SDK once; after that emsdk can do all further updates!** + +Purpose +============================================ + +With *emsdk* you can download, install or remove *any* :term:`SDK` or :term:`Tool`, ranging from the very first, through to the :ref:`bleeding edge updates ` still on Github. Most operations are of the form ``emsdk command``. To access the *emsdk*, launch the :ref:`Emscripten Command Prompt `. + +This document provides the command syntax, and a :ref:`set of guides ` explaining how to perform both common and advanced maintenance operations. + + +Command line syntax +============================================ + +**emsdk** [**help** [**--old**] | **list** | **update** | **install** ** | **uninstall** ** | **activate** **] + + +Arguments +--------- + + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + :class: wrap-table-content + + * - Command + - Description + * - ``list [--old]`` + - Lists all current SDKs and tools and their installation status. With the ``--old`` parameter, historical versions are also shown. + * - ``update`` + - Fetches the latest list of all available tools and SDKs (but does not install them) + * - ``install `` + - Downloads and installs the :ref:`specified tool or SDK `. + * - ``uninstall `` + - Removes the :ref:`specified tool or SDK ` from the disk. + * - ``activate `` + - Sets the :ref:`specified tool or SDK ` as the default tool in the system environment. + * - ``help`` + - Lists all supported commands. The same list is output if no command is specified. + +.. note:: For Mac OSX the commands are called with **./emsdk** and **./emcmdprompt.bat** respectively. + +Note that **emcmdprompt.bat** is also displayed as an option in the ``emsdk help``. This is not intended to be called through the command line. See :ref:`emcmdprompt` for more information. + + +.. _emsdk-specified-tool-sdk: + +Tools and SDK targets +------------------------ + +The ```` given above as a command argument is one of the targets listed using ``emsdk list`` (or ``emsdk list --old``). + +Note that some of the tools and SDK names include *master* or *incoming*: these targets are used to clone and pull the very latest versions from the Emscripten incoming and master branches. + +Finally, you can specify a target of ``latest`` to grab the most current SDK. + +.. todo:: **HamishW** emcmdprompt.bat does not appear to work. Need to check with Jukka + + + +SDK manager concepts +============================== + +The SDK contains a number of different :term:`tools `, including *Clang*, *Emscripten*, *Java*, *Git*, *Node*, etc. The *emsdk* can fetch the different versions of all these tools and also specific SDKs. These are put into different directories under the main SDK installation folder, grouped by tool and version. + +A user-specific file (**~/.emscripten**) stores the active "compiler configuration"; the :term:`active ` configuration is the specific set of tools that are used by default if Emscripten in called on the :ref:`Emscripten Command Prompt `. Users can call *emsdk* with the ``activate`` argument to make a specific tool or SDK active. + + +.. _emsdk_howto: + +"How to" guides +========================= + +The following topics explain how to perform both common and advanced maintenance operations, ranging from installing the latest SDK through to installing your own fork from Github. + +.. note:: The examples below show the commands for Windows and Linux. The commands are the same on Mac OSX, but you need to replace **emsdk** with **./emsdk**. + +.. _emsdk-get-latest-sdk: + +How do I just get the latest SDK? +------------------------------------------------------------------------------------------------ +Use the ``update`` argument to fetch the current registry of available tools, and then the ``latest`` target to get the most recent SDK: :: + + # Fetch the latest registry of available tools. + emsdk update + + # Download and install the latest SDK tools. + emsdk install latest + + # Set up the compiler configuration to point to the "latest" SDK. + emsdk activate latest + + + +How do I use emsdk? +-------------------------------- + +Use ``emsdk help`` or just ``emsdk`` to get information about all available commands. + + +How do I check which versions of the SDK and tools are installed? +------------------------------------------------------------------------------------------------ + +To get a list of all currently installed tools and SDK versions (and all available tools) run: :: + + emsdk list + +A line will be printed for each tool/SDK that is available for installation. The text ``INSTALLED`` will be shown for each tool that has already been installed. If a tool/SDK is currently active, a star (\*) will be shown next to it. + + +How do I install a tool/SDK version? +------------------------------------ + +Use the ``install`` argument to download and install a new tool or an SDK version: :: + + emsdk install + + +.. _emsdk-remove-tool-sdk: + +How do I remove a tool or an SDK? +---------------------------------------------------------------- + +Use the ``uninstall`` argument to delete a given tool or SDK from the local computer: :: + + emsdk uninstall + + +See :ref:`downloads-uninstall-the-sdk` if you need to completely remove Emscripten from your system. + + + + +How do I check for updates to the Emscripten SDK? +---------------------------------------------------------------- + +First use the ``update`` command to fetch package information for all new tools and SDK versions. Then use ``install `` to install a new version: :: + + # Fetch the latest registry of available tools. + emsdk update + + # Download and install the specified new version. + emsdk install + + +How do I change the currently active SDK version? +---------------------------------------------------------------- + +Toggle between different tools and SDK versions using the :term:`activate ` command. This will set up ``~/.emscripten`` to point to that particular tool: :: + + emsdk activate + + +How do I install an old Emscripten compiler version? +---------------------------------------------------------------- + +*Emsdk* contains a history of old compiler versions that you can use to maintain your migration path. Use the ``list --old`` argument to get a list of archived tool and SDK versions, and ``install `` to install it: :: + + emsdk list --old + emsdk install + +On Windows, you can directly install an old SDK version by using one of the :ref:`archived offline NSIS installers `. + + + +.. _emsdk-master-or-incoming-sdk: + +How do I track the latest Emscripten development with the SDK? +------------------------------------------------------------------------------------------------ + +It is also possible to use the latest and greatest versions of the tools on the Github repositories! This allows you to obtain new features and latest fixes immediately as they are pushed to Github, without having to wait for release to be tagged. **No Github account or a fork of Emscripten is required.** + +To switch to using the latest upstream git development branch ``incoming``, run the following: + +:: + + # Install git. Skip if the system already has it. + emsdk install git-1.8.3 + + # Clone+pull the latest kripken/emscripten/incoming. + emsdk install sdk-incoming-64bit + + # Set the incoming SDK as the active. + emsdk activate sdk-incoming-64bit + +If you want to use the upstream stable branch ``master``, then replace ``-incoming-`` with ``-master-`` above. + +.. note:: On Windows, *git* may fail with the error message: + + :: + + Unable to find remote helper for 'https' when cloning a repository with https:// url. + + The workaround is to uninstall git from *emsdk* (``emsdk uninstall git-1.8.3``) and install `Git for Windows `_. This issue is reported `here `_. + +.. todo:: **HamishW** Check whether the bug (https://github.com/juj/emsdk/issues/13) is fixed and remove the above note if it is. + + +How do I use my own Emscripten Github fork with the SDK? +---------------------------------------------------------------- + +It is also possible to use your own fork of the Emscripten repository via the SDK. This is useful in the case when you want to make your own modifications to the Emscripten toolchain, but still keep using the SDK environment and tools. + +The way this works is that you first install the ``sdk-incoming`` SDK as in the :ref:`previous section `. Then you use familiar git commands to replace this branch with the information from your own fork: + +:: + + cd emscripten/incoming + + # Add a git remote link to your own repository. + git remote add myremote https://github.com/mygituseraccount/emscripten.git + + # Obtain the changes in your link. + git fetch myremote + + # Switch the emscripten-incoming tool to use your fork. + git checkout -b myincoming --track myremote/incoming + +You can switch back and forth between remotes via the ``git checkout`` command as usual. + + + + diff --git a/site/source/docs/tools_reference/index.rst b/site/source/docs/tools_reference/index.rst new file mode 100644 index 0000000000000..9c871ad1d946f --- /dev/null +++ b/site/source/docs/tools_reference/index.rst @@ -0,0 +1,15 @@ +.. _tools-reference: + +======================================= +Tools Reference (under-construction) +======================================= + +This section provides reference for the main :term:`tools ` in the Emscripten toolchain. + + +.. toctree:: + :maxdepth: 1 + + emsdk + emcmdprompt + diff --git a/site/source/home_page_layout.html b/site/source/home_page_layout.html index c5340550f4617..388c531c6c244 100644 --- a/site/source/home_page_layout.html +++ b/site/source/home_page_layout.html @@ -1,27 +1,25 @@ -

Compile native code to the web

- ./_static/Emscripten_logo_full.png -

Emscripten takes LLVM bytecode generated from C/C++ and compiles it into asm.js (a highly optimisable strict subset of JavaScript). This can be run on the web without plugins.

+

Emscripten is an LLVM-based project that compiles C/C++ into highly-optimizable JavaScript in asm.js format. This lets you run C/C++ on the web at near-native speed, without plugins.

diff --git a/site/source/index.rst b/site/source/index.rst index 39b91857e92d8..df25dee3a31bb 100644 --- a/site/source/index.rst +++ b/site/source/index.rst @@ -14,10 +14,8 @@ News ==== +- `Massive `_ is a new asm.js benchmark comprised of Emscripten-compiled C/C++ codebases. Please test and give `feedback! `_ - `Unity `_ blogs about WebGL support and launches `two public demos `_ (April 29, 2014). See the `Mozilla Blog `_ for more information. -- The new :doc:`fastcomp/LLVM backend ` has been merged to master and is present in the latest SDK release. -- `Unreal Engine 4 `_ ported to the web using Emscripten (Mar 19, 2014 ). There is `more information `_ on the Mozilla blog. - @@ -31,7 +29,8 @@ News docs/compiling/index docs/packaging/index docs/contributing/index - docs/api_reference/index + docs/api_reference/index + docs/tools_reference/index wiki_static/index docs/site/about @@ -47,4 +46,4 @@ News * Introduction * Quickstart Signpost - with prominent link to "Getting Started" Tutorial * Signposts for: News, Top Demos, Contibuting, Github Project - * (Possibly) Signposts to: Twitter feed, Github issues (new, resolved) \ No newline at end of file + * (Possibly) Signposts to: Twitter feed, Github issues (new, resolved) diff --git a/src/compiler.js b/src/compiler.js index a86af011f0f97..2a98b129f44f2 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -319,9 +319,29 @@ try { } } } catch(err) { - printErr('Internal compiler error in src/compiler.js! Please raise a bug report at https://github.com/kripken/emscripten/issues/ with a log of the build and the input files used to run. Exception message: ' + err + ' | ' + err.stack); - if (ENVIRONMENT_IS_NODE) process.exit(1); - else throw err; + if (err.indexOf('Aborting compilation due to previous errors') != -1) { + // Compiler failed on user error, print out the error message. + printErr(err + ' | ' + err.stack); + } else { + // Compiler failed on internal compiler error! + printErr('Internal compiler error in src/compiler.js! Please raise a bug report at https://github.com/kripken/emscripten/issues/ with a log of the build and the input files used to run. Exception message: ' + err + ' | ' + err.stack); + } + + if (ENVIRONMENT_IS_NODE) { + // Work around a node.js bug where stdout buffer is not flushed at process exit: + // Instead of process.exit() directly, wait for stdout flush event. + // See https://github.com/joyent/node/issues/1669 and https://github.com/kripken/emscripten/issues/2582 + // Workaround is based on https://github.com/RReverser/acorn/commit/50ab143cecc9ed71a2d66f78b4aec3bb2e9844f6 + process['stdout']['once']('drain', function () { + process['exit'](1); + }); + console.log(' '); // Make sure to print something to force the drain event to occur, in case the stdout buffer was empty. + // Work around another node bug where sometimes 'drain' is never fired - make another effort + // to emit the exit status, after a significant delay (if node hasn't fired drain by then, give up) + setTimeout(function() { + process['exit'](1); + }, 500); + } else throw err; } //var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] }); diff --git a/src/emrun_postjs.js b/src/emrun_postjs.js index 9d84e761cdece..8bcea9a99e94a 100644 --- a/src/emrun_postjs.js +++ b/src/emrun_postjs.js @@ -18,3 +18,12 @@ function emrun_register_handlers() { post('^pageload^'); } emrun_register_handlers(); + +// POSTs the given binary data represented as a (typed) array data back to the emrun-based web server. +// To use from C code, call e.g. EM_ASM_({emrun_file_dump("file.dat", HEAPU8.subarray($0, $0 + $1));}, my_data_pointer, my_data_pointer_byte_length); +function emrun_file_dump(filename, data) { + var http = new XMLHttpRequest(); + Module['print']('Dumping out file "' + filename + '" with ' + data.length + ' bytes of data.'); + http.open("POST", "stdio.html?file=" + filename, true); + http.send(data); +} diff --git a/src/jsifier.js b/src/jsifier.js index 1f6440dd150c2..c8714380dfdd7 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1308,7 +1308,7 @@ function JSify(data, functionsOnly) { return ret; } var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); - var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32'); + var ret = asmCoercion('___cxa_find_matching_catch(' + catchTypeArray +')', 'i32'); if (USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + makeVarDef(item.assignTo) + '$1 = tempRet0;'; item.assignTo = null; diff --git a/src/library.js b/src/library.js index 6c84e590a38fe..40d7e0648b003 100644 --- a/src/library.js +++ b/src/library.js @@ -4004,13 +4004,19 @@ LibraryManager.library = { // We'll do that here, instead, to keep things simpler. __cxa_find_matching_catch__deps: ['__resumeException', '__cxa_last_thrown_exception', '__cxa_exception_header_size'], - __cxa_find_matching_catch: function(thrown, throwntype) { - if (thrown == -1) thrown = ___cxa_last_thrown_exception; + __cxa_find_matching_catch: function() { + var thrown = ___cxa_last_thrown_exception; + if (!thrown) { + // just pass through the null ptr + {{{ makeStructuralReturn([0, 0]) }}}; + } var header = thrown - ___cxa_exception_header_size; - if (throwntype == -1) throwntype = {{{ makeGetValue('header', 0, 'void*') }}}; - var typeArray = Array.prototype.slice.call(arguments, 2); - - assert(throwntype); + var throwntype = {{{ makeGetValue('header', 0, 'void*') }}}; + if (!throwntype) { + // just pass through the thrown ptr + {{{ makeStructuralReturn(['thrown', 0]) }}}; + } + var typeArray = Array.prototype.slice.call(arguments); var pointer = Module['___cxa_is_pointer_type'](throwntype); // can_catch receives a **, add indirection diff --git a/src/library_browser.js b/src/library_browser.js index 41ccf8fac693a..ac5e9c2473dc9 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -676,6 +676,27 @@ mergeInto(LibraryManager.library, { } }, +#if ASYNCIFY + emscripten_wget__deps: ['emscripten_async_resume'], + emscripten_wget: function(url, file) { + var _url = Pointer_stringify(url); + var _file = Pointer_stringify(file); + asm.setAsync(); + Module['noExitRuntime'] = true; + FS.createPreloadedFile( + PATH.dirname(_file), + PATH.basename(_file), + _url, true, true, + _emscripten_async_resume, + _emscripten_async_resume + ); + }, +#else + emscripten_wget: function(url, file) { + throw 'Please compile your program with -s ASYNCIFY=1 in order to use asynchronous operations like emscripten_wget'; + }, +#endif + emscripten_async_wget: function(url, file, onload, onerror) { var _url = Pointer_stringify(url); var _file = Pointer_stringify(file); diff --git a/src/library_fs.js b/src/library_fs.js index ae89571537b60..097cd5c9d3838 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -832,6 +832,9 @@ mergeInto(LibraryManager.library, { readlink: function(path) { var lookup = FS.lookupPath(path); var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(ERRNO_CODES.ENOENT); + } if (!link.node_ops.readlink) { throw new FS.ErrnoError(ERRNO_CODES.EINVAL); } diff --git a/src/postamble.js b/src/postamble.js index 7fd4eb1951505..a2ce89947308a 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -190,10 +190,9 @@ function exit(status) { }, 500); } else if (ENVIRONMENT_IS_SHELL && typeof quit === 'function') { quit(status); - } else { - // no proper way to exit with a return code, throw an exception to halt the current execution - throw new ExitStatus(status); } + // if we reach here, we must throw an exception to halt the current execution + throw new ExitStatus(status); } Module['exit'] = Module.exit = exit; diff --git a/src/settings.js b/src/settings.js index 2c98062c7d865..3f55d5c3235d3 100644 --- a/src/settings.js +++ b/src/settings.js @@ -297,8 +297,8 @@ var EXCEPTION_CATCHING_WHITELIST = []; // Enables catching exception in the lis var ASYNCIFY = 0; // Whether to enable asyncify transformation // This allows to inject some async functions to the C code that appear to be sync // e.g. emscripten_sleep -var ASYNCIFY_FUNCTIONS = ['emscripten_sleep']; // Functions that call any funcion in the list, directly or indirectly - // will be transfromed +var ASYNCIFY_FUNCTIONS = ['emscripten_sleep', // Functions that call any funcion in the list, directly or indirectly + 'emscripten_wget']; // will be transfromed var ASYNCIFY_WHITELIST = ['qsort', // Functions in this list are never considered async, even if they appear in ASYNCIFY_FUNCTIONS 'trinkle', // In the asyncify transformation, any function that calls a function pointer is considered async '__toread', // This whitelist is useful when a function is known to be sync diff --git a/src/shell.js b/src/shell.js index 7f556fb9fde39..71efd202cd82e 100644 --- a/src/shell.js +++ b/src/shell.js @@ -70,7 +70,7 @@ if (ENVIRONMENT_IS_NODE) { globalEval(read(f)); }; - Module['thisProgram'] = process['argv'][1]; + Module['thisProgram'] = process['argv'][1].replace(/\\/g, '/'); Module['arguments'] = process['argv'].slice(2); if (typeof module !== 'undefined') { diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index e54ad9c891ab1..b1a4e10ff782b 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -382,11 +382,24 @@ float emscripten_random(void); */ /* - * Load file from url in asynchronous way. In addition to - * fetching the URL from the network, the contents are - * prepared so that the data is usable in IMG_Load and - * so forth (we asynchronously do the work to make the - * browser decode the image or audio and so forth). + * Load file from url in *synchronous* way, for the asynchronous + * version, see the emscripten_async_wget function below. + * + * In addition to fetching the URL from the network, + * the contents are prepared so that the data is usable + * in IMG_Load and * so forth. + * + * This function is blocking, it won't return until all + * operations are finished. You can then open and read + * the file if it succeeded. + * + * To use this function, you will need to compile your + * application with the linker flag `-s ASYNCIFY=1` + */ +void emscripten_wget(const char* url, const char* file); + +/* + * Asynchronous version of emscripten_wget. * When file is ready then 'onload' callback will called. * If any error occurred 'onerror' will called. * The callbacks are called with the file as their argument. diff --git a/tests/cases/ctlz_alone_fastcomp.ll b/tests/cases/ctlz_alone_fastcomp.ll new file mode 100644 index 0000000000000..ec3ec13a93d7d --- /dev/null +++ b/tests/cases/ctlz_alone_fastcomp.ll @@ -0,0 +1,19 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128" +target triple = "asmjs-unknown-emscripten" + +@.str = private unnamed_addr constant [18 x i8] c"hello, world %d!\0A\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 @llvm.ctlz.i32(i32 109, i1 0) + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %call) + ret i32 0 +} + +declare i32 @printf(i8*, ...) + +declare i32 @llvm.ctlz.i32(i32, i1) + diff --git a/tests/cases/ctlz_alone_fastcomp.txt b/tests/cases/ctlz_alone_fastcomp.txt new file mode 100644 index 0000000000000..e2f98d5c41b14 --- /dev/null +++ b/tests/cases/ctlz_alone_fastcomp.txt @@ -0,0 +1 @@ +hello, world 25! diff --git a/tests/core/test_exceptions_convert.cpp b/tests/core/test_exceptions_convert.cpp new file mode 100644 index 0000000000000..08938ef5c9e05 --- /dev/null +++ b/tests/core/test_exceptions_convert.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +namespace +{ + struct TestEnum + { + enum type + { + Zero, + One + }; + }; + + // An input operator a-la-boost date_time. This input operator will catch + // anything and rethrow if the exception mask for the input stream is set to + // throw on failure. + std::istream& operator>>(std::istream& in, TestEnum::type& value) + { + try { + std::string raw; + if (not (in >> raw)) { return in; } + if (raw == "Zero") { value = TestEnum::Zero; return in; } + if (raw == "One") { value = TestEnum::One; return in; } + + // The boost input operator uses it's own facet for input which can + // throw, so we simulate something failing by just throwing an exception + // directly. + throw std::exception(); + } + catch (...) { + const std::ios_base::iostate exception_mask = in.exceptions(); + if (std::ios_base::failbit & exception_mask) { + try { in.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + in.setstate(std::ios_base::failbit); + } + } + return in; + } +} + +int main() +{ + try { + // Show that the input operator works. + std::istringstream iss("One"); + TestEnum::type value = TestEnum::Zero; + + // We expect this to work. + iss >> value; + if (iss.fail()) { + std::cout + << "Failed to convert 'One' to TestEnum::type... fail" + << std::endl; + } + else { + std::cout + << "Successfully converted 'One' to TestEnum::type: " << value + << "... ok" << std::endl; + } + } + catch (...) { + std::cout + << "Unknown exception caught converting 'One' to TestEnum... fail" + << std::endl; + } + + try { + // Show that invalid input set the fail bit on the input stream and no + // exception is thrown, since we did not enable them on the stream. + std::istringstream iss("Two"); + TestEnum::type value = TestEnum::Zero; + + // We expect this to fail. + iss >> value; + if (iss.fail()) { + std::cout + << "Failed to convert 'Two' to TestEnum::type... ok" + << std::endl; + } + else { + std::cout + << "Successfully converted 'Two' to TestEnum::type: " << value + << "... fail" << std::endl; + } + } + catch (...) { + std::cout + << "Unknown exception caught converting 'Two' to TestEnum... fail" + << std::endl; + } + + try { + // Show that setting the input stream to throw on failure currently + // results in a JS exception being emitted. + std::istringstream iss("Three"); + TestEnum::type value = TestEnum::Zero; + + // Tell the stream to throw on failure. + iss.exceptions(std::ios_base::failbit); + + // We expect this to fail. + iss >> value; + if (iss.fail()) { + std::cout + << "No exception thrown; Failed to convert 'Three' to TestEnum::type..." + "fail" << std::endl; + } + else { + std::cout + << "Successfully converted 'Three' to TestEnum::type: " << value + << "... fail" << std::endl; + } + } + catch(const std::ios_base::failure& ex) { + std::cout << "Caught exception: " << ex.what() << "... ok" << std::endl; + } + catch (...) { + std::cout + << "Unknown exception caught converting 'Three' to TestEnum... fail" + << std::endl; + } + + return 0; +} + diff --git a/tests/core/test_exceptions_convert.txt b/tests/core/test_exceptions_convert.txt new file mode 100644 index 0000000000000..fca657ce4e8c1 --- /dev/null +++ b/tests/core/test_exceptions_convert.txt @@ -0,0 +1,3 @@ +Successfully converted 'One' to TestEnum::type: 1... ok +Failed to convert 'Two' to TestEnum::type... ok +Unknown exception caught converting 'Three' to TestEnum... fail diff --git a/tests/hello_world_exit.c b/tests/hello_world_exit.c index 8932caf2dc6af..1c72f2d1d57b7 100644 --- a/tests/hello_world_exit.c +++ b/tests/hello_world_exit.c @@ -1,15 +1,22 @@ -#include -#include +#include +#include +#include int main(int argc, char **argv) { printf("argc: %d\n", argc); for(int i = 0; i < argc; ++i) { printf("argv[%d]: %s\n", i, argv[i]); } + + // Dump a file to local filesystem with emrun. + EM_ASM(emrun_file_dump("test.dat", HEAPU8.subarray(0, 128));); + EM_ASM(emrun_file_dump("heap.dat", HEAPU8)); + if (argc <= 1) exit(1); printf("hello, world!\n"); fprintf(stderr, "hello, error stream!\n"); + exit(100); } diff --git a/tests/sdl_canvas_alpha.png b/tests/sdl_canvas_alpha.png index fb9d61651fa5f..7fdcd211ca18b 100644 Binary files a/tests/sdl_canvas_alpha.png and b/tests/sdl_canvas_alpha.png differ diff --git a/tests/sockets/test_sockets_echo_client.c b/tests/sockets/test_sockets_echo_client.c index 48c031a4c54ef..af01311d5f21f 100644 --- a/tests/sockets/test_sockets_echo_client.c +++ b/tests/sockets/test_sockets_echo_client.c @@ -44,8 +44,10 @@ void finish(int result) { } #ifdef __EMSCRIPTEN__ REPORT_RESULT(); -#endif + emscripten_force_exit(result); +#else exit(result); +#endif } void main_loop() { diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 16abbfdd8070f..1b82b1e45b13f 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -118,7 +118,7 @@ def process(filename): self.filename = final def run(self, args): - return run_js(self.filename, engine=self.engine, args=args, stderr=PIPE, full_output=True) + return run_js(self.filename, engine=self.engine, args=args, stderr=PIPE, full_output=True, assert_returncode=None) # Benchmarkers try: diff --git a/tests/test_browser.py b/tests/test_browser.py index 281e5852fe991..65cec3e504f9d 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -756,7 +756,7 @@ def test_glgears_proxy_jstarget(self): self.run_browser('test.html', None, '/report_result?0') def test_sdl_canvas_alpha(self): - self.btest('sdl_canvas_alpha.c', reference='sdl_canvas_alpha.png', reference_slack=9) + self.btest('sdl_canvas_alpha.c', reference='sdl_canvas_alpha.png', reference_slack=11) def test_sdl_key(self): for defines in [[], ['-DTEST_EMSCRIPTEN_SDL_SETEVENTHANDLER']]: @@ -1947,3 +1947,7 @@ def test_codemods(self): self.btest(path_from_root('tests', 'codemods.cpp'), expected='121378', args=[opts, '--shell-file', 'shell.html', '--js-transform', fixer, '-s', 'PRECISE_F32=1']) # proper polyfill was enstated, then it was replaced by the fix so 0 is returned all the time, hence a different result here self.btest(path_from_root('tests', 'codemods.cpp'), expected='2', args=[opts, '--shell-file', 'shell.html', '--js-transform', fixer, '-s', 'PRECISE_F32=2']) # we should remove the calls to the polyfill ENTIRELY here, on the clientside, so we should NOT see any calls to fround here, and result should be like double + def test_wget(self): + with open(os.path.join(self.get_dir(), 'test.txt'), 'w') as f: + f.write('emscripten') + self.btest(path_from_root('tests', 'test_wget.c'), expected='1', args=['-s', 'ASYNCIFY=1']) diff --git a/tests/test_core.py b/tests/test_core.py index bf33b8ef1b5db..8542428500681 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1478,6 +1478,13 @@ def test_exceptions_virtual_inheritance(self): self.do_run_from_file(src, output) + def test_exceptions_convert(self): + if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp') + Settings.DISABLE_EXCEPTION_CATCHING = 0 + test_path = path_from_root('tests', 'core', 'test_exceptions_convert') + src, output = (test_path + s for s in ('.cpp', '.txt')) + self.do_run_from_file(src, output) + def test_exceptions_multi(self): Settings.DISABLE_EXCEPTION_CATCHING = 0 test_path = path_from_root('tests', 'core', 'test_exceptions_multi') @@ -4564,8 +4571,8 @@ def test_env(self): src = open(path_from_root('tests', 'env', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'env', 'output.txt'), 'r').read() self.do_run(src, [ - expected.replace('{{{ THIS_PROGRAM }}}', './this.program'), # spidermonkey, v8 - expected.replace('{{{ THIS_PROGRAM }}}', self.get_dir() + '/src.cpp.o.js') # node, can find itself properly + expected.replace('{{{ THIS_PROGRAM }}}', os.path.join(self.get_dir(), 'src.cpp.o.js').replace('\\', '/')), # node, can find itself properly + expected.replace('{{{ THIS_PROGRAM }}}', './this.program') # spidermonkey, v8 ]) def test_environ(self): @@ -4573,8 +4580,8 @@ def test_environ(self): src = open(path_from_root('tests', 'env', 'src-mini.c'), 'r').read() expected = open(path_from_root('tests', 'env', 'output-mini.txt'), 'r').read() self.do_run(src, [ - expected.replace('{{{ THIS_PROGRAM }}}', './this.program'), # spidermonkey, v8 - expected.replace('{{{ THIS_PROGRAM }}}', self.get_dir() + '/src.cpp.o.js') # node, can find itself properly + expected.replace('{{{ THIS_PROGRAM }}}', os.path.join(self.get_dir(), 'src.cpp.o.js').replace('\\', '/')), # node, can find itself properly + expected.replace('{{{ THIS_PROGRAM }}}', './this.program') # spidermonkey, v8 ]) def test_systypes(self): diff --git a/tests/test_other.py b/tests/test_other.py index b3f6954b77fc3..e815be87270f2 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1046,7 +1046,7 @@ def test_multiply_defined_libsymbols_2(self): self.assertContained('result: 62', run_js(os.path.join(self.get_dir(), 'a.out.js'))) - def test_link_group_asserts(self): + def test_link_group(self): lib_src_name = os.path.join(self.get_dir(), 'lib.c') open(lib_src_name, 'w').write('int x() { return 42; }') @@ -1078,6 +1078,35 @@ def test(lib_args, err_expected): test(['-Wl,--end-group', lib_name, '-Wl,--start-group'], '--end-group without --start-group') test(['-Wl,--start-group', lib_name, '-Wl,--end-group'], None) + def test_link_group_bitcode(self): + one = open('1.c', 'w').write(r''' +int f(void); +int main() { + f(); + return 0; +} + ''') + two = open('2.c', 'w').write(r''' +#include +int f() { + printf("Hello\n"); + return 0; +} + ''') + + Popen([PYTHON, EMCC, '-o', '1.o', '1.c']).communicate() + Popen([PYTHON, EMCC, '-o', '2.o', '2.c']).communicate() + Popen([PYTHON, EMAR, 'crs', '2.a', '2.o']).communicate() + Popen([PYTHON, EMCC, '-o', 'out.bc', '-Wl,--start-group', '2.a', '1.o', '-Wl,--end-group']).communicate() + Popen([PYTHON, EMCC, 'out.bc']).communicate() + self.assertContained('Hello', run_js('a.out.js')) + + # link using -l syntax, ensure ordering works (group-related, but not exactly testing of groups; ordering was introduced for groups, and broke this) + Popen([PYTHON, EMCC, '-o', 'out.bc', '-L.', '-l2', '1.o']).communicate() + Popen([PYTHON, EMCC, 'out.bc']).communicate() + self.assertContained('Hello', run_js('a.out.js')) + + def test_circular_libs(self): def tmp_source(name, code): file_name = os.path.join(self.get_dir(), name) @@ -2379,6 +2408,16 @@ def test_quoted_js_lib_key(self): Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '--js-library', 'lib.js']).communicate() self.assertContained('hello, world!', run_js(os.path.join(self.get_dir(), 'a.out.js'))) + def test_EMCC_BUILD_DIR(self): + # EMCC_BUILD_DIR env var contains the dir we were building in, when running the js compiler (e.g. when + # running a js library). We force the cwd to be src/ for technical reasons, so this lets you find out + # where you were. + open('lib.js', 'w').write(r''' +printErr('dir was ' + process.env.EMCC_BUILD_DIR); +''') + out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.cpp'), '--js-library', 'lib.js'], stderr=PIPE).communicate() + self.assertContained('dir was ' + os.path.normpath(self.get_dir()), err) + def test_float_h(self): process = Popen([PYTHON, EMCC, path_from_root('tests', 'float+.c')], stdout=PIPE, stderr=PIPE) out, err = process.communicate() @@ -3443,6 +3482,31 @@ def test(name): del os.environ['EMCC_FORCE_STDLIBS'] del os.environ['EMCC_ONLY_FORCED_STDLIBS'] + def test_only_force_stdlibs_2(self): + open('src.cpp', 'w').write(r''' +#include +#include + +int main() +{ + try { + throw std::exception(); + std::cout << "got here" << std::endl; + } + catch (const std::exception& ex) { + std::cout << "Caught exception: " << ex.what() << std::endl; + } +} +''') + try: + os.environ['EMCC_FORCE_STDLIBS'] = 'libc,libcxxabi,libcxx' + os.environ['EMCC_ONLY_FORCED_STDLIBS'] = '1' + Popen([PYTHON, EMXX, 'src.cpp']).communicate() + self.assertContained('Caught exception: std::exception', run_js('a.out.js', stderr=PIPE)) + finally: + del os.environ['EMCC_FORCE_STDLIBS'] + del os.environ['EMCC_ONLY_FORCED_STDLIBS'] + def test_strftime_zZ(self): open('src.cpp', 'w').write(r''' #include diff --git a/tests/test_wget.c b/tests/test_wget.c new file mode 100644 index 0000000000000..824f69d742e3f --- /dev/null +++ b/tests/test_wget.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +int main() +{ + const char * file = "/test.txt"; + emscripten_wget(file , file); + FILE * f = fopen(file, "r"); + int result = 0; + if(f) { +#define BUFSIZE 1024 + char buf[BUFSIZE]; + fgets(buf, BUFSIZE, f); + buf[BUFSIZE-1] = 0; + for(int i = 0; i < BUFSIZE; ++i) + buf[i] = tolower(buf[i]); + if(strstr(buf, "emscripten")) + result = 1; + fclose(f); + } + REPORT_RESULT(); + return 0; +} diff --git a/tools/asm_module.py b/tools/asm_module.py index a1aecdda3ce11..4b88bba672639 100644 --- a/tools/asm_module.py +++ b/tools/asm_module.py @@ -44,7 +44,7 @@ def __init__(self, filename): # funcs self.funcs_js = self.js[self.start_funcs:self.end_funcs] - self.funcs = set([m.group(2) for m in js_optimizer.func_sig.finditer(self.funcs_js)]) + self.funcs = set([m.group(1) for m in js_optimizer.func_sig.finditer(self.funcs_js)]) #print 'funcs', self.funcs # tables and exports diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 2fad08b3f4a08..396184acdf4bb 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -19,7 +19,7 @@ def path_from_root(*pathelems): DEBUG = os.environ.get('EMCC_DEBUG') -func_sig = re.compile('( *)function ([_\w$]+)\(') +func_sig = re.compile('function ([_\w$]+)\(') import_sig = re.compile('var ([_\w$]+) *=[^;]+;') class Minifier: @@ -43,7 +43,8 @@ def minify_shell(self, shell, minify_whitespace, source_map=False): shell = shell.replace('0.0', '13371337') # avoid uglify doing 0.0 => 0 # Find all globals in the JS functions code - self.globs = [m.group(2) for m in func_sig.finditer(self.js)] + + self.globs = [m.group(1) for m in func_sig.finditer(self.js)] temp_file = temp_files.get('.minifyglobals.js').name f = open(temp_file, 'w') @@ -208,7 +209,7 @@ def split_funcs(js): if i < len(parts)-1: func += '\n}\n' # last part needs no } m = func_sig.search(func) if m: - ident = m.group(2) + ident = m.group(1) else: if know_generated: continue # ignore whitespace ident = 'anon_%d' % i @@ -276,7 +277,7 @@ def write_chunk(chunk, i): (['--debug'] if source_map else []) + passes, filenames) #print [' '.join(command) for command in commands] - cores = min(cores, filenames) + cores = min(cores, len(filenames)) if len(chunks) > 1 and cores >= 2: # We can parallelize if DEBUG: print >> sys.stderr, 'splitting up js optimization into %d chunks of size %d, using %d cores (total: %.2f MB)' % (len(chunks), chunk_size, cores, total_size/(1024*1024.)) diff --git a/tools/jsrun.py b/tools/jsrun.py index 6b7e295bd60f0..660aaeec922b7 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -21,12 +21,16 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo if type(engine) is not list: engine = [engine] command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args - proc = Popen( - command, - stdin=stdin, - stdout=stdout, - stderr=stderr, - cwd=cwd) + try: + if cwd is not None: os.environ['EMCC_BUILD_DIR'] = os.getcwd() + proc = Popen( + command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd) + finally: + if cwd is not None: del os.environ['EMCC_BUILD_DIR'] timeout = 15*60 if check_timeout else None if TRACK_PROCESS_SPAWNS: logging.info('Blocking on process ' + str(proc.pid) + ': ' + str(command) + (' for ' + str(timeout) + ' seconds' if timeout else ' until it finishes.')) diff --git a/tools/system_libs.py b/tools/system_libs.py index 01b8ec0e40b09..6922727216049 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -460,8 +460,10 @@ def create_gl(): # Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking # for unresolved symbols in your project files, which can speed up linking, but if you do not have - # the proper list of actually needed libraries, errors can occur. - if os.environ.get('EMCC_ONLY_FORCED_STDLIBS'): + # the proper list of actually needed libraries, errors can occur. See below for how we must + # export all the symbols in deps_info when using this option. + only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS') + if only_forced: temp_files = [] # Scan symbols @@ -496,6 +498,14 @@ def add_back_deps(need): for symbols in symbolses: add_back_deps(symbols) + # If we are only doing forced stdlibs, then we don't know the actual symbols we need, + # and must assume all of deps_info must be exported. Note that this might cause + # warnings on exports that do not exist. + if only_forced: + for key, value in deps_info.iteritems(): + for dep in value: + shared.Settings.EXPORTED_FUNCTIONS.append('_' + dep) + all_needed = set() for symbols in symbolses: all_needed.update(symbols.undefs)