diff options
-rwxr-xr-x | emcc | 50 | ||||
-rw-r--r-- | src/library.js | 18 | ||||
-rw-r--r-- | src/postamble.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 13 | ||||
-rwxr-xr-x | tests/runner.py | 41 | ||||
-rw-r--r-- | tools/shared.py | 2 |
6 files changed, 76 insertions, 52 deletions
@@ -198,11 +198,16 @@ Options that are modified or new in %s include: will be run). Note that this by itself will not minify the code (closure does that) - --embed-file <filename> A file to embed inside the generated + --embed-file <file> A file to embed inside the generated JavaScript. The compiled code will be able to access the file in the current directory with the same basename as given here (that is, just the filename, without a path to it). + --preload-file <name> A file to preload before running the + compiled code asynchronously. Otherwise + similar to --embed-file, except that this + option is only relevant when generating + HTML (it uses asynchronous binary XHRs). --ignore-dynamic-linking Normally emcc will treat dynamic linking like static linking, by linking in the code from the dynamic library. This fails if the same @@ -347,6 +352,7 @@ try: post_js = None compress_whitespace = None embed_files = [] + preload_files = [] ignore_dynamic_linking = False shell_path = shared.path_from_root('src', 'shell.html') @@ -396,6 +402,11 @@ try: embed_files.append(newargs[i+1]) newargs[i] = '' newargs[i+1] = '' + elif newargs[i].startswith('--preload-file'): + check_bad_eq(newargs[i]) + preload_files.append(newargs[i+1]) + newargs[i] = '' + newargs[i+1] = '' elif newargs[i] == '-MF': # clang cannot handle this, so we fake it f = open(newargs[i+1], 'w') f.write('\n') @@ -728,16 +739,35 @@ try: final = shared.Building.emscripten(final, append_ext=False) if DEBUG: save_intermediate('original') - # Embed files - if len(embed_files) > 0: - if DEBUG: print >> sys.stderr, 'emcc: embedding files' - src = open(final).read().replace( - '// {{PRE_RUN_ADDITIONS}}', - '\n'.join(map(lambda embed_file: "FS.createDataFile('/', '%s', %s, true, false);" % (os.path.basename(embed_file), str(map(ord, open(embed_file, 'rb').read()))), embed_files)) - ) - final += '.ef.js' + # Embed and preload files + if len(embed_files) + len(preload_files) > 0: + if DEBUG: print >> sys.stderr, 'emcc: setting up files' + code = '' + for filename in embed_files: + code += '''FS.createDataFile('/', '%s', %s, true, true);\n''' % (os.path.basename(filename), str(map(ord, open(filename, 'rb').read()))) + counter = 0 + for filename in preload_files: + name = 'filePreload%d' % counter + counter += 1 + code += ''' + var %(name)s = new XMLHttpRequest(); + %(name)s.open("GET", "%(filename)s", true); + %(name)s.responseType = 'arraybuffer'; + addRunDependency(); + %(name)s.onload = function (oEvent) { + var arrayBuffer = %(name)s.response; // Note: not X.responseText + assert(arrayBuffer, 'Loading file %(filename)s failed.'); + var byteArray = new Uint8Array(arrayBuffer); + FS.createDataFile('/', '%(filename)s', byteArray, true, true); + removeRunDependency(); + }; + %(name)s.send(null); +''' % { 'name': name, 'filename': filename } + + src = open(final).read().replace('// {{PRE_RUN_ADDITIONS}}', code) + final += '.files.js' open(final, 'w').write(src) - if DEBUG: save_intermediate('embedded_files') + if DEBUG: save_intermediate('files') # Apply pre and postjs files if pre_js or post_js: diff --git a/src/library.js b/src/library.js index 7cda8bbb..8f4e5799 100644 --- a/src/library.js +++ b/src/library.js @@ -255,23 +255,7 @@ LibraryManager.library = { var success = true; if (typeof XMLHttpRequest !== 'undefined') { // Browser. - // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. - var xhr = new XMLHttpRequest(); - xhr.open('GET', obj.url, false); - - // Some hints to the browser that we want binary data. - if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer'; - if (xhr.overrideMimeType) { - xhr.overrideMimeType('text/plain; charset=x-user-defined'); - } - - xhr.send(null); - if (xhr.status != 200 && xhr.status != 0) success = false; - if (xhr.response !== undefined) { - obj.contents = new Uint8Array(xhr.response || []); - } else { - obj.contents = intArrayFromString(xhr.responseText || '', true); - } + assert('Cannot do synchronous binary XHRs in modern browsers. Use --embed-file or --preload-file in emcc'); } else if (typeof read !== 'undefined') { // Command-line. try { diff --git a/src/postamble.js b/src/postamble.js index 56f0aee1..7371ff05 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -53,10 +53,10 @@ if (Module['preRun']) { #if INVOKE_RUN #else -Module['noInitialRun'] = true; +addRunDependency(); #endif -if (!Module['noInitialRun']) { +if (runDependencies == 0) { var ret = run(); #if CATCH_EXIT_CODE print('Exit Status: ' + ret); diff --git a/src/preamble.js b/src/preamble.js index afae5ea7..ae7bd660 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -873,5 +873,18 @@ var STRING_TABLE = []; {{{ unSign }}} {{{ reSign }}} +// A counter of dependencies for calling run(). If we need to +// do asynchronous work before running, increment this and +// decrement it. Incrementing must happen in Module.preRun +// or PRE_RUN_ADDITIONS (used by emcc to add file preloading). +var runDependencies = 0; +function addRunDependency() { + runDependencies++; +} +function removeRunDependency() { + runDependencies--; + if (runDependencies == 0) run(); +} + // === Body === diff --git a/tests/runner.py b/tests/runner.py index 4c2fdddf..4f72e67d 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -6175,27 +6175,24 @@ f.close() def run_browser(self, html_file, message, expectedResult=None): if expectedResult is not None: try: - try: - def server_func(q): - class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): - def do_GET(s): - q.put(s.path) - httpd = BaseHTTPServer.HTTPServer(('localhost', 8888), TestServerHandler) - httpd.serve_forever() # test runner will kill us - queue = multiprocessing.Queue() - server = multiprocessing.Process(target=server_func, args=(queue,)) - server.start() - webbrowser.open_new(os.path.abspath(html_file)) - output = '[no http server activity]' - start = time.time() - while time.time() - start < 5: - if not queue.empty(): - output = queue.get() - break - time.sleep(0.1) - self.assertIdentical(expectedResult, output) - except Exception, e: - print e + def server_func(q): + class TestServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): + def do_GET(s): + q.put(s.path) + httpd = BaseHTTPServer.HTTPServer(('localhost', 8888), TestServerHandler) + httpd.serve_forever() # test runner will kill us + queue = multiprocessing.Queue() + server = multiprocessing.Process(target=server_func, args=(queue,)) + server.start() + webbrowser.open_new(os.path.abspath(html_file)) + output = '[no http server activity]' + start = time.time() + while time.time() - start < 5: + if not queue.empty(): + output = queue.get() + break + time.sleep(0.1) + self.assertIdentical(expectedResult, output) finally: server.terminate() else: @@ -6213,7 +6210,7 @@ f.close() assert os.path.exists('something.html'), output self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.') - def zzztest_emcc_preload_file(self): + def test_emcc_preload_file(self): open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''load me right before running the code please''') open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' #include <stdio.h> diff --git a/tools/shared.py b/tools/shared.py index 7570473c..6a63d4ec 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -226,7 +226,7 @@ def check_engine(engine): print 'Checking JS engine %s failed. Check %s. Details: %s' % (str(engine), EM_CONFIG, str(e)) return False -def timeout_run(proc, timeout, note): +def timeout_run(proc, timeout, note='unnamed process'): start = time.time() if timeout is not None: while time.time() - start < timeout and proc.poll() is None: |