From 907dc042ac6bae58a708837780cec799ba0d121a Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Mon, 14 Aug 2017 20:02:04 +0300 Subject: [PATCH 01/24] Added new option "Module.scriptDirectory" that allows customizing the URL where .wasm, .mem and some other files are located (defaults to the same location as .js file) --- ChangeLog.markdown | 21 +++++++++--------- site/source/docs/api_reference/module.rst | 22 ++++++++++-------- src/preamble.js | 4 ++++ src/shell.js | 27 +++++++++++++++++++++++ 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/ChangeLog.markdown b/ChangeLog.markdown index 8c10b374fb5f..5c1697674fde 100644 --- a/ChangeLog.markdown +++ b/ChangeLog.markdown @@ -10,6 +10,7 @@ Not all changes are documented here. In particular, new features, user-oriented Current trunk code ------------------ - Updated to libc++'s "v2" ABI, which provides better alignment for string data and other improvements. This is an ABI-incompatible change, so bitcode files from previous versions will not be compatible. + - Added new option "Module.scriptDirectory" that allows customizing the URL where .wasm, .mem and some other files are located (defaults to the same location as .js file) - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see - Emscripten: https://github.com/kripken/emscripten/compare/1.37.13...incoming - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.37.13...incoming @@ -768,7 +769,7 @@ v1.34.5: 8/18/2015 - Fixed some OpenAL alGetSource get calls (#3669) - Fixed issues with building the optimizer on 32-bit Windows (#3673) - Increased optimizer stack size on Windows to 10MB (#3679) - - Added support for passing multiple input files to opt, to speed up optimization and linking in opt. + - Added support for passing multiple input files to opt, to speed up optimization and linking in opt. - Full list of changes: - Emscripten: https://github.com/kripken/emscripten/compare/1.34.4...1.34.5 - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.34.4...1.34.5 @@ -1187,7 +1188,7 @@ v1.29.2: 1/16/2015 ------------------- - Fixed an issue with embind compilation in LLVM 3.5. - Fixed an issue with SDL audio queueing stability, which would queue audio too eagerly and cause stutter in some applications (#3122, #3124) - - Enabled native JS optimizer to be built automatically on Windows, requires VS2012 or VS2013. + - Enabled native JS optimizer to be built automatically on Windows, requires VS2012 or VS2013. - Improve error message to reflect the fact that DLOPEN_SUPPORT is currently not available (#2365) - Improve SIMD load and store support. - Upgraded SDL2 port to version 3. @@ -1460,7 +1461,7 @@ v1.23.1: 8/26/2014 - Removed the support for old discontinued Mozilla Audio Data API in src/library_sdl.js. - Removed the support for using Web Audio ScriptProcessorNode to stream audio. - Improved SDL audio streaming by using the main rAF() callback instead of a separate setTimeout() callback to schedule the audio data. - - Deprecated compiling without typed arrays support. + - Deprecated compiling without typed arrays support. - Migrated to using musl PRNG functions. Fixes reported bugs about the quality of randomness (#2341) - Improved SIMD support for the experimental Ecmascript SIMD spec. - Full list of changes: @@ -1830,7 +1831,7 @@ v1.17.0: 5/6/2014 v1.16.0: 4/16/2014 ------------------ - - Removed browser warnings message in VFS library about replacing __proto__ performance issue. + - Removed browser warnings message in VFS library about replacing __proto__ performance issue. - Full list of changes: - Emscripten: https://github.com/kripken/emscripten/compare/1.15.1...1.16.0 - Emscripten-LLVM: no changes. @@ -1839,7 +1840,7 @@ v1.16.0: 4/16/2014 v1.15.1: 4/15/2014 ------------------ - Added support for SDL2 touch api. - - Added new user-controllable emdind-related define #define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES, which allows optimizing embind for minimal size when std::type_info is not needed. + - Added new user-controllable emdind-related define #define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES, which allows optimizing embind for minimal size when std::type_info is not needed. - Fixed issues with CMake support where CMAKE_AR and CMAKE_RANLIB were not accessible from CMakeLists.txt files. - Full list of changes: - Emscripten: https://github.com/kripken/emscripten/compare/1.15.0...1.15.1 @@ -1995,7 +1996,7 @@ v1.11.0: 2/14/2014 v1.10.4: 2/10/2014 ------------------ - Added support for legacy GL emulation in fastcomp. - - Deprecated the --split-js compiler option. This is not supported in fastcomp. + - Deprecated the --split-js compiler option. This is not supported in fastcomp. - Full list of changes: https://github.com/kripken/emscripten/compare/1.10.3...1.10.4 v1.10.3: 2/9/2014 @@ -2225,7 +2226,7 @@ v1.7.3: 11/12/2013 - Converted return value of emscripten_get_now() from float to double, to not lose precision in the function call. - Added support for joysticks in SDL via the Gamepad API - Full list of changes: https://github.com/kripken/emscripten/compare/1.7.2...1.7.3 - + v1.7.2: 11/9/2013 ------------------ - The compiler now always generates a .js file that contains the generated source code even when compiling to a .html file. @@ -2237,7 +2238,7 @@ v1.7.2: 11/9/2013 - Fixed some mappings with SDL keyboard codes. - Added a new command line parameter --no-heap-copy to compiler and file packager that can be used to optimize VFS memory usage at startup. - Updated libcxx to revision 194185, 2013-11-07. - - Improvements to various library support. + - Improvements to various library support. - Full list of changes: https://github.com/kripken/emscripten/compare/1.7.1...1.7.2 v1.7.1: 10/24/2013 @@ -2310,7 +2311,7 @@ v1.6.0: 9/21/2013 - Enable support for %[] pattern in scanf. - Added dependency tracking support to linked .js files in CMake toolchain. - The hex prefix 0x is now properly handled in sscanf (#1632). - - Simplify internal compiler operations by removing the internal framework.js. + - Simplify internal compiler operations by removing the internal framework.js. - Full list of changes: https://github.com/kripken/emscripten/compare/1.5.9...1.6.0 v1.5.9: 9/15/2013 @@ -2505,7 +2506,7 @@ v1.3.3: 3/23/2013 v1.3.2: 3/22/2013 ------------------ - - Fix issues with fgets. + - Fix issues with fgets. - Add support for non-fullscreen pointer lock. - Improve OpenAL support. - Full list of changes: https://github.com/kripken/emscripten/compare/1.3.1...1.3.2 diff --git a/site/source/docs/api_reference/module.rst b/site/source/docs/api_reference/module.rst index d7081f66da08..d226cf0b3eed 100644 --- a/site/source/docs/api_reference/module.rst +++ b/site/source/docs/api_reference/module.rst @@ -4,7 +4,7 @@ Module object ============= -``Module`` is a global JavaScript object with attributes that Emscripten-generated code calls at various points in its execution. +``Module`` is a global JavaScript object with attributes that Emscripten-generated code calls at various points in its execution. Developers can provide an implementation of ``Module`` to control the execution of code. For example, to define how notification messages from Emscripten are displayed, developers implement the :js:attr:`Module.print` attribute. @@ -20,7 +20,7 @@ Developers can provide an implementation of ``Module`` to control the execution Creating the Module object ========================== -Use emcc's :ref:`pre-js option` to add JavaScript code that defines (or extends) the ``Module`` object with the behaviour you need. +Use emcc's :ref:`pre-js option` to add JavaScript code that defines (or extends) the ``Module`` object with the behaviour you need. When generating only JavaScript (as opposed to HTML), no ``Module`` object is created by default, and the behaviour is entirely defined by the developer. For example, creating a ``Module`` object with the following code will cause all notifications from the program to be calls to ``alert()``. @@ -43,13 +43,13 @@ When generating HTML, Emscripten creates a ``Module`` object with default method Affecting execution =================== -The following ``Module`` attributes affect code execution. +The following ``Module`` attributes affect code execution. .. js:attribute:: Module.print Called when something is printed to standard output (stdout) - + .. js:attribute:: Module.printErr Called when something is printed to standard error (stderr) @@ -63,8 +63,8 @@ The following ``Module`` attributes affect code execution. .. js:attribute:: Module.preInit A function (or array of functions) that must be called before global initializers run, but after basic initialization of the JavaScript runtime. This is typically used for :ref:`File System operations `. - - + + .. js:attribute:: Module.preRun An array of functions to call right before calling ``run()``, but after defining and setting up the environment, including global initializers. This is useful, for example, to set up directories and files using the :ref:`Filesystem-API` — as this needs to happen after the FileSystem API has been loaded, but before the program starts to run. @@ -92,10 +92,14 @@ The following ``Module`` attributes affect code execution. .. js:attribute:: Module.filePackagePrefixURL This is the "prefix" URL for a preloaded data file that is hosted separately from its JavaScript and HTML files (it includes the full path up to, but not including, the data file). See :ref:`packaging-files-data-file-location` for more information. - + .. js:attribute:: Module.locateFile - If set, this method will be called when the runtime needs to load a file, such as a ``.wasm`` WebAssembly file, ``.mem`` memory init file, or a file generated by the file packager. The function receives the URL, and should return the actual URL. This lets you host file packages or the ``.mem`` file etc. on a different location than the current directory (which is the default expectation), for example if you want to host them on a CDN. Note that ``locateFile`` is sort of a generalization of ``Module.filePackagePrefixURL``. + If set, this method will be called when the runtime needs to load a file, such as a ``.wasm`` WebAssembly file, ``.mem`` memory init file, or a file generated by the file packager. The function receives the URL, and should return the actual URL. This lets you host file packages or the ``.mem`` file etc. on a different location than the current directory (which is the default expectation), for example if you want to host them on a CDN. Note that ``locateFile`` is sort of a generalization of ``Module.*PrefixURL``. + +.. js:attribute:: Module.scriptDirectory + + Defaults to current directory of ``.js`` file and is used for ``Module.*PrefixURL`` if any of those are not specified explicitly, allows customizing the URL where .wasm, .mem and some other files are located, ``/`` should be present at the end if not empty. .. js:attribute:: Module.logReadFiles @@ -137,7 +141,7 @@ The generated program is able to detect its execution environment by checking th However, sometimes it may be needed to override the detected environment: a typical use case would be module bundlers (like webpack): they are executed by nodejs but the final output is for browser. -In order to do that, you can dictate your preferred execution environment by setting the ``Module.ENVIRONMENT`` variable to one of those allowed values: +In order to do that, you can dictate your preferred execution environment by setting the ``Module.ENVIRONMENT`` variable to one of those allowed values: ``WEB`` diff --git a/src/preamble.js b/src/preamble.js index 5bda57adfa6c..e17e3431d03a 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -2090,6 +2090,10 @@ function integrateWasmJS() { wasmTextFile = Module['locateFile'](wasmTextFile); wasmBinaryFile = Module['locateFile'](wasmBinaryFile); asmjsCodeFile = Module['locateFile'](asmjsCodeFile); + } else { + wasmTextFile = Module['scriptDirectory'] + wasmTextFile; + wasmBinaryFile = Module['scriptDirectory'] + wasmBinaryFile; + asmjsCodeFile = Module['scriptDirectory'] + asmjsCodeFile; } // utilities diff --git a/src/shell.js b/src/shell.js index e3b230b0bb1a..a288eab54a67 100644 --- a/src/shell.js +++ b/src/shell.js @@ -72,6 +72,33 @@ if (!ENVIRONMENT_IS_PTHREAD) PthreadWorkerInit = {}; var currentScriptUrl = (typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined; #endif +if (typeof Module['locateFile'] !== 'function') { + // `/` should be present at the end if `Module['scriptDirectory']` is not empty + if (!Module['scriptDirectory']) { + if (ENVIRONMENT_IS_NODE) { + Module['scriptDirectory'] = __dirname + '/'; + } else if (ENVIRONMENT_IS_WEB && !document.currentScript.src.startsWith('blob:')) { + Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; + } else if (ENVIRONMENT_IS_WORKER) { + Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; + } else { + Module['scriptDirectory'] = ''; + } + } + if (!Module['memoryInitializerPrefixURL']) { + Module['memoryInitializerPrefixURL'] = Module['scriptDirectory']; + } + if (!Module['pthreadMainPrefixURL']) { + Module['pthreadMainPrefixURL'] = Module['scriptDirectory']; + } + if (!Module['cdInitializerPrefixURL']) { + Module['cdInitializerPrefixURL'] = Module['scriptDirectory']; + } + if (!Module['filePackagePrefixURL']) { + Module['filePackagePrefixURL'] = Module['scriptDirectory']; + } +} + if (ENVIRONMENT_IS_NODE) { // Expose functionality in the same simple way that the shells work // Note that we pollute the global namespace here, otherwise we break in node From deb852086fe5dc28aafb9344dd5062d1ee59f088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 12 Oct 2017 20:48:07 +0300 Subject: [PATCH 02/24] Add test case for the failing scenario where file is loaded from a relative path. (cherry picked from commit 6afe133) --- tests/test_other.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_other.py b/tests/test_other.py index 965e2b701f39..be3f7878b97f 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7993,3 +7993,10 @@ def test_single_file(self): assert expect_wast == os.path.exists('a.out.wast') if should_run_js: self.assertContained('hello, world!', run_js('a.out.js')) + + # Tests that Emscripten-compiled applications can be run from a relative path with node command line that is different than the current working directory. + def test_node_js_run_from_different_directory(self): + os.mkdir('subdir') + Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js'), '-O3']).communicate() + ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0] + assert 'hello, world!' in ret From 011fe85df86a89be2a17e233f89671ca2c13cce7 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 13 Oct 2017 01:04:08 +0300 Subject: [PATCH 03/24] Added test case for browser --- tests/test_browser.py | 44 +++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/tests/test_browser.py b/tests/test_browser.py index 6de108e73ddc..59c9cee7b363 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -129,7 +129,7 @@ def test_emscripten_log(self): Popen([PYTHON, EMCC, src, '--pre-js', path_from_root('src', 'emscripten-source-map.min.js'), '-g', '-o', 'page.html', '-s', 'DEMANGLE_SUPPORT=1']).communicate() self.run_browser('page.html', None, '/report_result?1') - + def build_native_lzma(self): lzma_native = path_from_root('third_party', 'lzma.js', 'lzma-native') if os.path.isfile(lzma_native) and os.access(lzma_native, os.X_OK): return @@ -150,10 +150,10 @@ def test_preload_file(self): absolute_src_path2 = os.path.join(self.get_dir(), '.somefile.txt').replace('\\', '/') open(absolute_src_path2, 'w').write('''load me right before running the code please''') - + absolute_src_path3 = os.path.join(self.get_dir(), 'some@file.txt').replace('\\', '/') open(absolute_src_path3, 'w').write('''load me right before running the code please''') - + def make_main(path): print('make main at', path) path = path.replace('\\', '\\\\').replace('"', '\\"') # Escape tricky path name for use inside a C string. @@ -184,7 +184,7 @@ def make_main(path): ("./somefile.txt@file.txt", "file.txt"), ("./somefile.txt@./file.txt", "file.txt"), ("somefile.txt@/file.txt", "file.txt"), - ("somefile.txt@/", "somefile.txt"), + ("somefile.txt@/", "somefile.txt"), (absolute_src_path + "@file.txt", "file.txt"), (absolute_src_path + "@/file.txt", "file.txt"), (absolute_src_path + "@/", "somefile.txt"), @@ -274,7 +274,7 @@ def make_main_two_files(path1, path2, nonexistingpath): print(srcpath) Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--preload-file', srcpath, '--exclude-file', '*/.*', '-o', 'page.html']).communicate() self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1') - + # Should still work with -o subdir/.. make_main('somefile.txt') # absolute becomes relative @@ -576,12 +576,12 @@ def test(): Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']).communicate() shutil.move('test.data','missing.data'); self.run_browser('test.html', '', '/report_result?1') - + # test unknown protocol should go through xhr.onerror setup("unknown_protocol://"); Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']).communicate() self.run_browser('test.html', '', '/report_result?1') - + # test wrong protocol and port setup("https://localhost:8800/"); Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--shell-file', 'on_window_error_shell.html', '--preload-file', 'data.txt', '-o', 'test.html']).communicate() @@ -1162,7 +1162,7 @@ def test_glfw_joystick(self): def test_webgl_context_attributes(self): - # Javascript code to check the attributes support we want to test in the WebGL implementation + # Javascript code to check the attributes support we want to test in the WebGL implementation # (request the attribute, create a context and check its value afterwards in the context attributes). # Tests will succeed when an attribute is not supported. open(os.path.join(self.get_dir(), 'check_webgl_attributes_support.js'), 'w').write(''' @@ -1193,17 +1193,17 @@ def test_webgl_context_attributes(self): } }); ''') - + # Copy common code file to temporary directory filepath = path_from_root('tests/test_webgl_context_attributes_common.c') temp_filepath = os.path.join(self.get_dir(), os.path.basename(filepath)) shutil.copyfile(filepath, temp_filepath) - - # perform tests with attributes activated + + # perform tests with attributes activated self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglut', '-lGLEW']) self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lSDL', '-lGLEW']) self.btest('test_webgl_context_attributes_glfw.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglfw', '-lGLEW']) - + # perform tests with attributes desactivated self.btest('test_webgl_context_attributes_glut.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-lGL', '-lglut', '-lGLEW']) self.btest('test_webgl_context_attributes_sdl.c', '1', args=['--js-library', 'check_webgl_attributes_support.js', '-lGL', '-lSDL', '-lGLEW']) @@ -1447,7 +1447,7 @@ def test_glfw_minimal(self): def test_glfw_time(self): self.btest('test_glfw_time.c', '1', args=['-s', 'USE_GLFW=3', '-lglfw', '-lGL']) - + def test_egl(self): open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read())) @@ -3635,7 +3635,7 @@ def test_asmfs_mkdir_create_unlink_rmdir(self): def test_asmfs_dirent_test_readdir(self): self.btest('dirent/test_readdir.c', expected='0', args=['-s', 'ASMFS=1', '-s', 'USE_PTHREADS=1', '-s', 'FETCH_DEBUG=1']) - def test_asmfs_dirent_test_readdir_empty(self): + def test_asmfs_dirent_test_readdir_empty(self): self.btest('dirent/test_readdir_empty.c', expected='0', args=['-s', 'ASMFS=1', '-s', 'USE_PTHREADS=1', '-s', 'FETCH_DEBUG=1']) def test_asmfs_unistd_close(self): @@ -3720,3 +3720,19 @@ def test_single_file_worker_js(self): open('test.html', 'w').write('') self.run_browser('test.html', None, '/report_result?0') assert os.path.exists('test.js') and not os.path.exists('test.worker.js') + + # Tests that Emscripten-compiled applications can be run from a relative path in browser that is different than the address of the current page + def test_node_js_run_from_different_directory(self): + src = open(path_from_root('tests', 'browser_test_hello_world.c')).read() + open('test.c', 'w').write(self.with_report_result(src)) + Popen([PYTHON, EMCC, 'test.c', '-o', 'test.html', '-O3']).communicate() + + if not os.path.exists('subdir'): + os.mkdir('subdir') + shutil.move('test.js', os.path.join('subdir', 'test.js')) + shutil.move('test.html.mem', os.path.join('subdir', 'test.html.mem')) + src = open('test.html').read() + # Force mem file to be loaded by JS and make sure JS is loaded from subdirectory + open('test-subdir.html', 'w').write(src.replace('var memoryInitializer', 'return;var memoryInitializer').replace('test.js', 'subdir/test.js')) + + self.run_browser('test-subdir.html', None, '/report_result?0') From ffb2f567dcd2022794fcdd0449ad46f856594bfc Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 2 Nov 2017 11:28:58 +0200 Subject: [PATCH 04/24] More fixes after rebasing against `incoming` that includes #5296 --- src/shell.js | 2 ++ tests/test_browser.py | 2 +- tests/test_other.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shell.js b/src/shell.js index a288eab54a67..399a6688b8bf 100644 --- a/src/shell.js +++ b/src/shell.js @@ -72,6 +72,7 @@ if (!ENVIRONMENT_IS_PTHREAD) PthreadWorkerInit = {}; var currentScriptUrl = (typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined; #endif +#if !SUPPORT_BASE64_EMBEDDING if (typeof Module['locateFile'] !== 'function') { // `/` should be present at the end if `Module['scriptDirectory']` is not empty if (!Module['scriptDirectory']) { @@ -98,6 +99,7 @@ if (typeof Module['locateFile'] !== 'function') { Module['filePackagePrefixURL'] = Module['scriptDirectory']; } } +#endif if (ENVIRONMENT_IS_NODE) { // Expose functionality in the same simple way that the shells work diff --git a/tests/test_browser.py b/tests/test_browser.py index 59c9cee7b363..0a8d6350b1ca 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3733,6 +3733,6 @@ def test_node_js_run_from_different_directory(self): shutil.move('test.html.mem', os.path.join('subdir', 'test.html.mem')) src = open('test.html').read() # Force mem file to be loaded by JS and make sure JS is loaded from subdirectory - open('test-subdir.html', 'w').write(src.replace('var memoryInitializer', 'return;var memoryInitializer').replace('test.js', 'subdir/test.js')) + open('test-subdir.html', 'w').write(src.replace('var meminitXHR', '//var meminitXHR').replace('meminitXHR.', '//meminitXHR.').replace('test.js', 'subdir/test.js')) self.run_browser('test-subdir.html', None, '/report_result?0') diff --git a/tests/test_other.py b/tests/test_other.py index be3f7878b97f..8cd8795c65a6 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7996,7 +7996,8 @@ def test_single_file(self): # Tests that Emscripten-compiled applications can be run from a relative path with node command line that is different than the current working directory. def test_node_js_run_from_different_directory(self): - os.mkdir('subdir') + if not os.path.exists('subdir'): + os.mkdir('subdir') Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js'), '-O3']).communicate() ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0] assert 'hello, world!' in ret From 027380d881542b3cde9f32362224aecce25f23d7 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Tue, 21 Nov 2017 09:39:23 +0200 Subject: [PATCH 05/24] Make sure `Module['scriptDirectory']` is always defined, even if with empty string. Some redundant checks removed. --- emcc.py | 2 +- src/Fetch.js | 8 ++++---- src/library_debugger_toolkit.js | 3 +-- src/library_pthread.js | 4 ++-- src/postamble.js | 2 +- src/shell.js | 6 ++++-- tools/file_packager.py | 14 +++++++------- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/emcc.py b/emcc.py index b7f27bfb3df1..901d82eb8b93 100755 --- a/emcc.py +++ b/emcc.py @@ -2491,7 +2491,7 @@ def generate_html(target, options, js_target, target_basename, var memoryInitializer = '%s'; if (typeof Module['locateFile'] === 'function') { memoryInitializer = Module['locateFile'](memoryInitializer); - } else if (Module['memoryInitializerPrefixURL']) { + } else { memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer; } Module['memoryInitializerRequestURL'] = memoryInitializer; diff --git a/src/Fetch.js b/src/Fetch.js index e7b8477c704c..91bae21f0c64 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -114,7 +114,7 @@ var Fetch = { // either via Module.locateFile() function, or via Module.pthreadMainPrefixURL string. If neither // of these are passed, then the default URL 'pthread-main.js' relative to the main html file is loaded. if (typeof Module['locateFile'] === 'function') fetchJs = Module['locateFile'](fetchJs); - else if (Module['pthreadMainPrefixURL']) fetchJs = Module['pthreadMainPrefixURL'] + fetchJs; + else fetchJs = Module['pthreadMainPrefixURL'] + fetchJs; Fetch.worker = new Worker(fetchJs); Fetch.worker.onmessage = function(e) { Module['print']('fetch-worker sent a message: ' + e.filename + ':' + e.lineno + ': ' + e.message); @@ -557,15 +557,15 @@ function emscripten_start_fetch(fetch, successcb, errorcb, progresscb) { } else if (fetchAttrNoDownload) { __emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, reportError); } else if (fetchAttrPersistFile) { - __emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performCachedXhr); + __emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performCachedXhr); } else { - __emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performUncachedXhr); + __emscripten_fetch_load_cached_data(Fetch.dbInstance, fetch, reportSuccess, performUncachedXhr); } } else if (!fetchAttrNoDownload) { if (fetchAttrPersistFile) { __emscripten_fetch_xhr(fetch, cacheResultAndReportSuccess, reportError, reportProgress); } else { - __emscripten_fetch_xhr(fetch, reportSuccess, reportError, reportProgress); + __emscripten_fetch_xhr(fetch, reportSuccess, reportError, reportProgress); } } else { #if FETCH_DEBUG diff --git a/src/library_debugger_toolkit.js b/src/library_debugger_toolkit.js index 29cb532aecaa..cb245e29a9cf 100644 --- a/src/library_debugger_toolkit.js +++ b/src/library_debugger_toolkit.js @@ -445,10 +445,9 @@ var CyberDWARFHeapPrinter = function(cdFileLocation) { } function initialize_debugger(cb) { - var cdFile; if (typeof Module['locateFile'] === 'function') { cdFileLocation = Module['locateFile'](cdFileLocation); - } else if (Module['cdInitializerPrefixURL']) { + } else { cdFileLocation = Module['cdInitializerPrefixURL'] + cdFileLocation; } if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { diff --git a/src/library_pthread.js b/src/library_pthread.js index 77a6329e191a..10e257302e5d 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -258,7 +258,7 @@ var LibraryPThread = { // either via Module.locateFile() function, or via Module.pthreadMainPrefixURL string. If neither // of these are passed, then the default URL 'pthread-main.js' relative to the main html file is loaded. if (typeof Module['locateFile'] === 'function') pthreadMainJs = Module['locateFile'](pthreadMainJs); - else if (Module['pthreadMainPrefixURL']) pthreadMainJs = Module['pthreadMainPrefixURL'] + pthreadMainJs; + else pthreadMainJs = Module['pthreadMainPrefixURL'] + pthreadMainJs; var worker = new Worker(pthreadMainJs); worker.onmessage = function(e) { @@ -1089,7 +1089,7 @@ var LibraryPThread = { #endif }, - // The profiler setters are defined twice, here in asm.js so that they can be #ifdeffed out + // The profiler setters are defined twice, here in asm.js so that they can be #ifdeffed out // without having to pay the impact of a FFI transition for a no-op in non-profiling builds. emscripten_conditional_set_current_thread_status__asm: true, emscripten_conditional_set_current_thread_status__sig: 'vii', diff --git a/src/postamble.js b/src/postamble.js index 2b4a04334ad2..1b332e8f9b07 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -41,7 +41,7 @@ if (memoryInitializer) { #endif if (typeof Module['locateFile'] === 'function') { memoryInitializer = Module['locateFile'](memoryInitializer); - } else if (Module['memoryInitializerPrefixURL']) { + } else { memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer; } if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { diff --git a/src/shell.js b/src/shell.js index 3b7506f273b4..a52005b113e4 100644 --- a/src/shell.js +++ b/src/shell.js @@ -72,10 +72,10 @@ if (!ENVIRONMENT_IS_PTHREAD) PthreadWorkerInit = {}; var currentScriptUrl = (typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined; #endif -#if !SUPPORT_BASE64_EMBEDDING if (typeof Module['locateFile'] !== 'function') { // `/` should be present at the end if `Module['scriptDirectory']` is not empty if (!Module['scriptDirectory']) { +#if !SUPPORT_BASE64_EMBEDDING if (ENVIRONMENT_IS_NODE) { Module['scriptDirectory'] = __dirname + '/'; } else if (ENVIRONMENT_IS_WEB && !document.currentScript.src.startsWith('blob:')) { @@ -85,6 +85,9 @@ if (typeof Module['locateFile'] !== 'function') { } else { Module['scriptDirectory'] = ''; } +#else + Module['scriptDirectory'] = ''; +#endif } if (!Module['memoryInitializerPrefixURL']) { Module['memoryInitializerPrefixURL'] = Module['scriptDirectory']; @@ -99,7 +102,6 @@ if (typeof Module['locateFile'] !== 'function') { Module['filePackagePrefixURL'] = Module['scriptDirectory']; } } -#endif if (ENVIRONMENT_IS_NODE) { // Expose functionality in the same simple way that the shells work diff --git a/tools/file_packager.py b/tools/file_packager.py index 6dbea91d0e27..7539aff854b4 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -106,7 +106,7 @@ jsoutput = None no_closure = False force = True -# If set to True, IndexedDB (IDBFS in library_idbfs.js) is used to locally cache VFS XHR so that subsequent +# If set to True, IndexedDB (IDBFS in library_idbfs.js) is used to locally cache VFS XHR so that subsequent # page loads can read the data from the offline cache instead. use_preload_cache = False indexeddb_name = 'EM_PRELOAD_CACHE' @@ -170,7 +170,7 @@ mode = leading at_position = arg.replace('@@', '__').find('@') # position of @ if we're doing 'src@dst'. '__' is used to keep the index same with the original if they escaped with '@@'. uses_at_notation = (at_position != -1) # '@@' in input string means there is an actual @ character, a single '@' means the 'src@dst' notation. - + if uses_at_notation: srcpath = arg[0:at_position].replace('@@', '@') # split around the @ dstpath = arg[at_position+1:].replace('@@', '@') @@ -223,7 +223,7 @@ def has_hidden_attribute(filepath): if sys.platform != 'win32': return False - + try: attrs = ctypes.windll.kernel32.GetFileAttributesW(unicode(filepath)) assert attrs != -1 @@ -237,7 +237,7 @@ def has_hidden_attribute(filepath): def should_ignore(fullname): if has_hidden_attribute(fullname): return True - + for p in excluded_patterns: if fnmatch.fnmatch(fullname, p): return True @@ -279,7 +279,7 @@ def add(mode, rootpathsrc, rootpathdst): new_data_files.append(file_) data_files = [file_ for file_ in new_data_files if not os.path.isdir(file_['srcpath'])] if len(data_files) == 0: - print('Nothing to do!', file=sys.stderr) + print('Nothing to do!', file=sys.stderr) sys.exit(1) # Absolutize paths, and check that they make sense @@ -576,7 +576,7 @@ def was_seen(name): } var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ? Module['locateFile'](REMOTE_PACKAGE_BASE) : - ((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE); + (Module['filePackagePrefixURL'] + REMOTE_PACKAGE_BASE); ''' % (escape_for_js_string(data_target), escape_for_js_string(remote_package_name)) metadata['remote_package_size'] = remote_package_size metadata['package_uuid'] = str(package_uuid) @@ -839,7 +839,7 @@ def was_seen(name): var REMOTE_METADATA_NAME = typeof Module['locateFile'] === 'function' ? Module['locateFile']('%(metadata_file)s') : - ((Module['filePackagePrefixURL'] || '') + '%(metadata_file)s'); + (Module['filePackagePrefixURL'] + '%(metadata_file)s'); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { From 82ef1e028b2c98f12a67f40cd9bd9e07d6c44514 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 2 Feb 2018 06:00:11 +0200 Subject: [PATCH 06/24] Changelog have changed, move new feature into trunk --- ChangeLog.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.markdown b/ChangeLog.markdown index e7017e379380..57699b533276 100644 --- a/ChangeLog.markdown +++ b/ChangeLog.markdown @@ -9,6 +9,7 @@ Not all changes are documented here. In particular, new features, user-oriented Current Trunk ------------- + - Added new option "Module.scriptDirectory" that allows customizing the URL where .wasm, .mem and some other files are located (defaults to the same location as .js file) v1.37.28: 01/08/2018 -------------------- @@ -36,7 +37,6 @@ v1.37.23: 12/4/2017 v1.37.17: 7/25/2017 ------------------ - Updated to libc++'s "v2" ABI, which provides better alignment for string data and other improvements. This is an ABI-incompatible change, so bitcode files from previous versions will not be compatible. - - Added new option "Module.scriptDirectory" that allows customizing the URL where .wasm, .mem and some other files are located (defaults to the same location as .js file) - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see - Emscripten: https://github.com/kripken/emscripten/compare/1.37.13...incoming - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.37.13...incoming From 25c65b95dca5d1a2e86e44c7712d1b43ea9c86b5 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 2 Feb 2018 06:08:58 +0200 Subject: [PATCH 07/24] Restored compatibility with IE, which doesn't have `String.startsWith` --- src/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell.js b/src/shell.js index 387389500b53..a26c4ef98758 100644 --- a/src/shell.js +++ b/src/shell.js @@ -91,7 +91,7 @@ if (typeof Module['locateFile'] !== 'function') { #if !SUPPORT_BASE64_EMBEDDING if (ENVIRONMENT_IS_NODE) { Module['scriptDirectory'] = __dirname + '/'; - } else if (ENVIRONMENT_IS_WEB && !document.currentScript.src.startsWith('blob:')) { + } else if (ENVIRONMENT_IS_WEB && document.currentScript.src.indexOf('blob:') !== 0) { Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; } else if (ENVIRONMENT_IS_WORKER) { Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; From 07ed0bcb9b936783fe8fc336547e5ec587cf5e06 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Fri, 2 Feb 2018 17:11:55 +0200 Subject: [PATCH 08/24] Make sure `Module.scriptDirectory` is available even if `Module.locateFile` is present --- src/shell.js | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/shell.js b/src/shell.js index a26c4ef98758..e43a2d335d78 100644 --- a/src/shell.js +++ b/src/shell.js @@ -85,35 +85,33 @@ if (!ENVIRONMENT_IS_PTHREAD) PthreadWorkerInit = {}; var currentScriptUrl = (typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined; #endif -if (typeof Module['locateFile'] !== 'function') { - // `/` should be present at the end if `Module['scriptDirectory']` is not empty - if (!Module['scriptDirectory']) { +// `/` should be present at the end if `Module['scriptDirectory']` is not empty +if (!Module['scriptDirectory']) { #if !SUPPORT_BASE64_EMBEDDING - if (ENVIRONMENT_IS_NODE) { - Module['scriptDirectory'] = __dirname + '/'; - } else if (ENVIRONMENT_IS_WEB && document.currentScript.src.indexOf('blob:') !== 0) { - Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; - } else if (ENVIRONMENT_IS_WORKER) { - Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; - } else { - Module['scriptDirectory'] = ''; - } -#else + if (ENVIRONMENT_IS_NODE) { + Module['scriptDirectory'] = __dirname + '/'; + } else if (ENVIRONMENT_IS_WEB && document.currentScript.src.indexOf('blob:') !== 0) { + Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; + } else if (ENVIRONMENT_IS_WORKER) { + Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; + } else { Module['scriptDirectory'] = ''; -#endif - } - if (!Module['memoryInitializerPrefixURL']) { - Module['memoryInitializerPrefixURL'] = Module['scriptDirectory']; - } - if (!Module['pthreadMainPrefixURL']) { - Module['pthreadMainPrefixURL'] = Module['scriptDirectory']; - } - if (!Module['cdInitializerPrefixURL']) { - Module['cdInitializerPrefixURL'] = Module['scriptDirectory']; - } - if (!Module['filePackagePrefixURL']) { - Module['filePackagePrefixURL'] = Module['scriptDirectory']; } +#else + Module['scriptDirectory'] = ''; +#endif +} +if (!Module['memoryInitializerPrefixURL']) { + Module['memoryInitializerPrefixURL'] = Module['scriptDirectory']; +} +if (!Module['pthreadMainPrefixURL']) { + Module['pthreadMainPrefixURL'] = Module['scriptDirectory']; +} +if (!Module['cdInitializerPrefixURL']) { + Module['cdInitializerPrefixURL'] = Module['scriptDirectory']; +} +if (!Module['filePackagePrefixURL']) { + Module['filePackagePrefixURL'] = Module['scriptDirectory']; } if (ENVIRONMENT_IS_NODE) { From 1bfa6b0162f6b99f89b147573502e13260bd33bc Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 24 Feb 2018 05:39:35 +0200 Subject: [PATCH 09/24] Minor tweak, check if `document.currentScript` is present, it might not be available if module is a part of Browserify build or in similar cases --- src/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell.js b/src/shell.js index 283d7ad37cb1..490009e83420 100644 --- a/src/shell.js +++ b/src/shell.js @@ -90,7 +90,7 @@ if (!Module['scriptDirectory']) { #if !SUPPORT_BASE64_EMBEDDING if (ENVIRONMENT_IS_NODE) { Module['scriptDirectory'] = __dirname + '/'; - } else if (ENVIRONMENT_IS_WEB && document.currentScript.src.indexOf('blob:') !== 0) { + } else if (ENVIRONMENT_IS_WEB && document.currentScript && document.currentScript.src.indexOf('blob:') !== 0) { Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; } else if (ENVIRONMENT_IS_WORKER) { Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; From 4ca757ca1ddfbc6e38b518b6eb38a88abd6a7c08 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 24 Feb 2018 05:43:37 +0200 Subject: [PATCH 10/24] Revert some `file_packager.py` changes to fix browser tests --- tools/file_packager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/file_packager.py b/tools/file_packager.py index 90c06ab911c1..fc1f6e5a6dee 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -584,7 +584,7 @@ def was_seen(name): } var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ? Module['locateFile'](REMOTE_PACKAGE_BASE) : - (Module['filePackagePrefixURL'] + REMOTE_PACKAGE_BASE); + ((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE); ''' % (escape_for_js_string(data_target), escape_for_js_string(remote_package_name)) metadata['remote_package_size'] = remote_package_size metadata['package_uuid'] = str(package_uuid) @@ -847,7 +847,7 @@ def was_seen(name): var REMOTE_METADATA_NAME = typeof Module['locateFile'] === 'function' ? Module['locateFile']('%(metadata_file)s') : - (Module['filePackagePrefixURL'] + '%(metadata_file)s'); + ((Module['filePackagePrefixURL'] || '') + '%(metadata_file)s'); var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { From 0e3d19ebcae47ab745d9e63e1d75379e00b8908b Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 24 Feb 2018 16:30:37 +0200 Subject: [PATCH 11/24] Fix for `-s MODULARIZE=1` where module is loaded at the time when `document.currentScript` is `null` --- emcc.py | 4 ++++ src/shell.js | 17 ++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/emcc.py b/emcc.py index 24640fa5bd5a..dab9fdd8a593 100755 --- a/emcc.py +++ b/emcc.py @@ -2451,6 +2451,10 @@ def modularize(): return %(EXPORT_NAME)s; }%(instantiate)s; +%(EXPORT_NAME)s.bind({ + _currentScript: typeof document !== 'undefined' ? document.currentScript : undefined, + _selfLocation: typeof self !== 'undefined' ? self.location : undefined +}); if (typeof exports === 'object' && typeof module === 'object') module.exports = %(EXPORT_NAME)s; else if (typeof define === 'function' && define['amd']) diff --git a/src/shell.js b/src/shell.js index 490009e83420..9e21bbfade1b 100644 --- a/src/shell.js +++ b/src/shell.js @@ -87,18 +87,21 @@ var currentScriptUrl = (typeof document !== 'undefined' && document.currentScrip // `/` should be present at the end if `Module['scriptDirectory']` is not empty if (!Module['scriptDirectory']) { + Module['scriptDirectory'] = ''; #if !SUPPORT_BASE64_EMBEDDING if (ENVIRONMENT_IS_NODE) { Module['scriptDirectory'] = __dirname + '/'; - } else if (ENVIRONMENT_IS_WEB && document.currentScript && document.currentScript.src.indexOf('blob:') !== 0) { - Module['scriptDirectory'] = document.currentScript.src.split('/').slice(0, -1).join('/') + '/'; + } else if (ENVIRONMENT_IS_WEB) { + // We do this for `-s MODULARIZE=1` where at the time when this code runs document.currentScript might already be unavailable + var currentScript = this['_currentScript'] || document.currentScript; + if (currentScript.src.indexOf('blob:') !== 0) { + Module['scriptDirectory'] = currentScript.src.split('/').slice(0, -1).join('/') + '/'; + } } else if (ENVIRONMENT_IS_WORKER) { - Module['scriptDirectory'] = self.location.href.split('/').slice(0, -1).join('/') + '/'; - } else { - Module['scriptDirectory'] = ''; + // We do this for `-s MODULARIZE=1` where at the time when this code runs self.location might already be unavailable + var selfLocation = this['_selfLocation'] || self.location; + Module['scriptDirectory'] = selfLocation.href.split('/').slice(0, -1).join('/') + '/'; } -#else - Module['scriptDirectory'] = ''; #endif } if (!Module['memoryInitializerPrefixURL']) { From d0deafd343abed871713582c2f507ccafe79a9b6 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 24 Feb 2018 17:19:32 +0200 Subject: [PATCH 12/24] Missing assignment in latest commit --- emcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc.py b/emcc.py index dab9fdd8a593..33fbfc47a26a 100755 --- a/emcc.py +++ b/emcc.py @@ -2451,7 +2451,7 @@ def modularize(): return %(EXPORT_NAME)s; }%(instantiate)s; -%(EXPORT_NAME)s.bind({ +%(EXPORT_NAME)s = %(EXPORT_NAME)s.bind({ _currentScript: typeof document !== 'undefined' ? document.currentScript : undefined, _selfLocation: typeof self !== 'undefined' ? self.location : undefined }); From d221d2ef0d6bae6965e7b3bd3468ec074bddd4e5 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sat, 24 Feb 2018 21:53:30 +0200 Subject: [PATCH 13/24] Fix for binding module function after instantiation --- emcc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index 33fbfc47a26a..bf6bbed95c20 100755 --- a/emcc.py +++ b/emcc.py @@ -2450,11 +2450,11 @@ def modularize(): %(src)s return %(EXPORT_NAME)s; -}%(instantiate)s; +}; %(EXPORT_NAME)s = %(EXPORT_NAME)s.bind({ _currentScript: typeof document !== 'undefined' ? document.currentScript : undefined, _selfLocation: typeof self !== 'undefined' ? self.location : undefined -}); +})%(instantiate)s; if (typeof exports === 'object' && typeof module === 'object') module.exports = %(EXPORT_NAME)s; else if (typeof define === 'function' && define['amd']) From 7d453dd35e907a8110a8786de6bf0c0b06983bc2 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sun, 15 Jul 2018 02:05:13 +0300 Subject: [PATCH 14/24] Fix browser test (it defaults to WASM now) --- tests/test_browser.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_browser.py b/tests/test_browser.py index c31785b3d99e..81c96ef4563b 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3750,7 +3750,7 @@ def test_fetch_to_memory(self): def test_fetch_cached_xhr(self): shutil.copyfile(path_from_root('tests', 'gears.png'), os.path.join(self.get_dir(), 'gears.png')) self.btest('fetch/cached_xhr.cpp', expected='1', args=['--std=c++11', '-s', 'FETCH_DEBUG=1', '-s', 'FETCH=1', '-s', 'WASM=0']) - + # Tests that response headers get set on emscripten_fetch_t values. def test_fetch_response_headers(self): shutil.copyfile(path_from_root('tests', 'gears.png'), os.path.join(self.get_dir(), 'gears.png')) @@ -3938,7 +3938,7 @@ def test_unicode_html_shell(self): self.run_browser('test.html', None, '/report_result?0') # Tests that Emscripten-compiled applications can be run from a relative path in browser that is different than the address of the current page - def test_node_js_run_from_different_directory(self): + def test_browser_run_from_different_directory(self): src = open(path_from_root('tests', 'browser_test_hello_world.c')).read() open('test.c', 'w').write(self.with_report_result(src)) Popen([PYTHON, EMCC, 'test.c', '-o', 'test.html', '-O3']).communicate() @@ -3946,9 +3946,9 @@ def test_node_js_run_from_different_directory(self): if not os.path.exists('subdir'): os.mkdir('subdir') shutil.move('test.js', os.path.join('subdir', 'test.js')) - shutil.move('test.html.mem', os.path.join('subdir', 'test.html.mem')) + shutil.move('test.wasm', os.path.join('subdir', 'test.wasm')) src = open('test.html').read() - # Force mem file to be loaded by JS and make sure JS is loaded from subdirectory - open('test-subdir.html', 'w').write(src.replace('var meminitXHR', '//var meminitXHR').replace('meminitXHR.', '//meminitXHR.').replace('test.js', 'subdir/test.js')) + # Make sure JS is loaded from subdirectory + open('test-subdir.html', 'w').write(src.replace('test.js', 'subdir/test.js')) self.run_browser('test-subdir.html', None, '/report_result?0') From 70a1abcd94dc8dfa5f0a3e801214c6cccf78013c Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sun, 15 Jul 2018 03:31:04 +0300 Subject: [PATCH 15/24] Remove `Module.scriptDirectory` and pass it as an argument to `Module.locateFile` instead. Remove all `Module.*PrefixURL` options. --- ChangeLog.markdown | 5 +- emcc.py | 6 +- site/source/docs/api_reference/module.rst | 11 +--- .../docs/porting/files/packaging_files.rst | 32 +++++------ site/source/docs/porting/pthreads.rst | 2 +- src/Fetch.js | 7 +-- src/library_debugger_toolkit.js | 6 +- src/library_pthread.js | 7 +-- src/postamble.js | 10 +--- src/preamble.js | 28 +++------- src/shell.js | 55 +++++++++---------- tests/test_browser.py | 12 ++-- tools/file_packager.py | 8 +-- 13 files changed, 76 insertions(+), 113 deletions(-) diff --git a/ChangeLog.markdown b/ChangeLog.markdown index 06798a3bfbe3..99f1a798e289 100644 --- a/ChangeLog.markdown +++ b/ChangeLog.markdown @@ -10,6 +10,10 @@ Not all changes are documented here. In particular, new features, user-oriented Current Trunk ------------- + - Fix `Module.locateFile` to resolve relative paths to *.wasm, *.mem and other files relatively to JavaScript file rather than current working directory + - Add second argument `prefix` to `Module.locateFile` function that contains path to JavaScript file where files are loaded from by default + - Remove `Module.*PrefixURL` APIs (use `Module.locateFile` instead) + v1.38.8: 07/06/2018 ------------------- - Fix a regression in 1.38.7 with binaryen no longer bundling binaryen.js (which emscripten doesn't need, that's just for handwritten JS users, but emscripten did check for its prescence). @@ -72,7 +76,6 @@ v1.37.35: 02/23/2018 -------------------- - MALLOC option, allowing picking between dlmalloc (previous allocator and still the default) and emmalloc, a new allocator which is smaller and simpler. - Binaryen update that should fix all known determinism bugs. - - Added new option "Module.scriptDirectory" that allows customizing the URL where .wasm, .mem and some other files are located (defaults to the same location as .js file) v1.37.34: 02/16/2018 -------------------- diff --git a/emcc.py b/emcc.py index 2333c90ec4c7..074461dd2aa4 100755 --- a/emcc.py +++ b/emcc.py @@ -2708,11 +2708,7 @@ def generate_html(target, options, js_target, target_basename, script.un_src() script.inline = (''' var memoryInitializer = '%s'; - if (typeof Module['locateFile'] === 'function') { - memoryInitializer = Module['locateFile'](memoryInitializer); - } else { - memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer; - } + memoryInitializer = Module._locateFile(memoryInitializer); Module['memoryInitializerRequestURL'] = memoryInitializer; var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest(); meminitXHR.open('GET', memoryInitializer, true); diff --git a/site/source/docs/api_reference/module.rst b/site/source/docs/api_reference/module.rst index c09078fb0de0..613706cc97d3 100644 --- a/site/source/docs/api_reference/module.rst +++ b/site/source/docs/api_reference/module.rst @@ -51,18 +51,9 @@ The following ``Module`` attributes affect code execution. Set them to customize The commandline arguments. The value of ``arguments`` contains the values returned if compiled code checks ``argc`` and ``argv``. - -.. js:attribute:: Module.filePackagePrefixURL - - This is the "prefix" URL for a preloaded data file that is hosted separately from its JavaScript and HTML files (it includes the full path up to, but not including, the data file). See :ref:`packaging-files-data-file-location` for more information. - .. js:attribute:: Module.locateFile - If set, this method will be called when the runtime needs to load a file, such as a ``.wasm`` WebAssembly file, ``.mem`` memory init file, or a file generated by the file packager. The function receives the URL, and should return the actual URL. This lets you host file packages or the ``.mem`` file etc. on a different location than the current directory (which is the default expectation), for example if you want to host them on a CDN. Note that ``locateFile`` is sort of a generalization of ``Module.*PrefixURL``. - -.. js:attribute:: Module.scriptDirectory - - Defaults to current directory of ``.js`` file and is used for ``Module.*PrefixURL`` if any of those are not specified explicitly, allows customizing the URL where .wasm, .mem and some other files are located, ``/`` should be present at the end if not empty. + If set, this method will be called when the runtime needs to load a file, such as a ``.wasm`` WebAssembly file, ``.mem`` memory init file, or a file generated by the file packager. The function receives the relative path to the file as configured in build process and a prefix (path to JavaScript file), and should return the actual URL. This lets you host file packages or the ``.mem`` file etc. on a different location than the directory of JavaScript file (which is the default expectation), for example if you want to host them on a CDN. .. js:attribute:: Module.logReadFiles diff --git a/site/source/docs/porting/files/packaging_files.rst b/site/source/docs/porting/files/packaging_files.rst index 62391aefb68c..3b419e839817 100644 --- a/site/source/docs/porting/files/packaging_files.rst +++ b/site/source/docs/porting/files/packaging_files.rst @@ -4,10 +4,10 @@ Packaging Files =============== -This topic shows how to package the files that will be used to populate :ref:`Emscripten's virtual file system ` when the page is loaded. +This topic shows how to package the files that will be used to populate :ref:`Emscripten's virtual file system ` when the page is loaded. There are two alternatives for how files are packaged: *preloading* and *embedding*. Embedding puts the specified files inside the generated JavaScript, while preloading packages the files separately. Embedding files is much less efficient than preloading and should only be used when packaging small numbers of small files. Preloading also enables the option to separately host the data. - + *Emcc* uses the *file packager* to package the files and generate the :ref:`File System API ` calls that create and load the file system at run time. While *Emcc* is the recommended tool for packaging, there are cases where it can make sense to run the *file packager* manually. With ``--use-preload-plugins``, files can be automatically decoded based on @@ -23,9 +23,9 @@ The command below shows how to package files for preloading: .. code-block:: bash ./emcc file.cpp -o file.html --preload-file asset_dir - + The command generates **file.html**, **file.js** and **file.data**. The **.data** file contains all the files in **asset_dir/**, and is loaded by **file.js**. - + .. note:: The :ref:`Tutorial ` demonstrates preloading using the **hello_world_file.cpp** test code. @@ -36,7 +36,7 @@ The command for embedding is shown below. In this case *emcc* generates **file.h ./emcc file.cpp -o file.html --embed-file asset_dir -By default, the files to be packaged should be nested in or below the compile-time command prompt directory. At runtime the same nested file structure is mapped to the virtual file system, with the root corresponding to the command prompt directory. +By default, the files to be packaged should be nested in or below the compile-time command prompt directory. At runtime the same nested file structure is mapped to the virtual file system, with the root corresponding to the command prompt directory. For example, consider a file structure **dir1/dir2/dir3/asset_dir/** where the project is compiled from **dir2**. When we package **asset_dir**, we specify its relative location **dir3/asset_dir/**: @@ -51,27 +51,27 @@ The ``@`` symbol can be used to map packaged files from any location in the loca .. _packaging-files-file-packager: -Packaging using the file packager tool +Packaging using the file packager tool ====================================== -You can also run the *file packager* manually using the instructions at the top of `file_packager.py `_. +You can also run the *file packager* manually using the instructions at the top of `file_packager.py `_. The file packager generates a **.data** file and **.js** file. The **.js** file contains the code to use the data file, and must be loaded *before* loading your main compiled code. .. note:: - - Using the *file packager* allows you to run file packaging separately from compiling the code. + - Using the *file packager* allows you to run file packaging separately from compiling the code. - You can load multiple datafiles by running the file packager on each and loading the **.js** outputs. See `BananaBread `_ for an example of this (`cube2/js/game-setup.js `_). - + .. _packaging-files-data-file-location: Changing the data file location =============================== -By default, the **.data** file containing all the preloaded files is loaded from the same URL as your **.js** file. In some cases it may be useful to have the data file in a different location from the other files — for example if your **.html** and **.js** change a lot you may want to keep the data file on a fast CDN somewhere else. +By default, the **.data** file containing all the preloaded files is loaded from the same URL as your **.js** file. In some cases it may be useful to have the data file in a different location from the other files — for example if your **.html** and **.js** change a lot you may want to keep the data file on a fast CDN somewhere else. -This model is supported by changing the :js:attr:`Module.filePackagePrefixURL` to be the URL where the data file is stored (this is a prefix, so should include the full path before the data's file name). The attribute must be specified in a `` + + ''') + + self.run_browser('test-subdir.html', None, '/report_result?0') From 7a3ec9cac871ea89f382b46338cdbcb51bbe77f0 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Sun, 22 Jul 2018 19:19:03 +0300 Subject: [PATCH 24/24] Refactor as suggested in review comments --- src/shell.js | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/shell.js b/src/shell.js index 3f8ea3af0d29..db5b645b0c4f 100644 --- a/src/shell.js +++ b/src/shell.js @@ -89,24 +89,9 @@ assert(typeof Module['pthreadMainPrefixURL'] === 'undefined', 'Module.pthreadMai assert(typeof Module['cdInitializerPrefixURL'] === 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['filePackagePrefixURL'] === 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); #endif + // `/` should be present at the end if `scriptDirectory` is not empty var scriptDirectory = ''; -#if ENVIRONMENT_MAY_BE_NODE -if (ENVIRONMENT_IS_NODE) { - scriptDirectory = __dirname + '/'; -} -#endif -#if ENVIRONMENT_MAY_BE_WEB_OR_WORKER -if (ENVIRONMENT_IS_WEB) { - // We do this for `-s MODULARIZE=1` where at the time when this code runs document.currentScript might already be unavailable - var currentScript = this['_currentScript'] || document.currentScript; - if (currentScript.src.indexOf('blob:') !== 0) { - scriptDirectory = currentScript.src.split('/').slice(0, -1).join('/') + '/'; - } -} else if (ENVIRONMENT_IS_WORKER) { - scriptDirectory = self.location.href.split('/').slice(0, -1).join('/') + '/'; -} -#endif function locateFile(path) { if (Module['locateFile']) { return Module['locateFile'](path, scriptDirectory); @@ -117,7 +102,7 @@ function locateFile(path) { #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE) { - + scriptDirectory = __dirname + '/'; #if ENVIRONMENT #if ASSERTIONS if (!(typeof process === 'object' && typeof require === 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); @@ -244,6 +229,15 @@ if (ENVIRONMENT_IS_SHELL) { #endif // ENVIRONMENT_MAY_BE_SHELL #if ENVIRONMENT_MAY_BE_WEB_OR_WORKER if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WEB) { + // We do this for `-s MODULARIZE=1` where at the time when this code runs document.currentScript might already be unavailable + var currentScript = this['_currentScript'] || document.currentScript; + if (currentScript.src.indexOf('blob:') !== 0) { + scriptDirectory = currentScript.src.split('/').slice(0, -1).join('/') + '/'; + } + } else if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = self.location.href.split('/').slice(0, -1).join('/') + '/'; + } #if ENVIRONMENT #if ASSERTIONS