@@ -277,6 +277,10 @@ def do_minify(self):
277
277
self .cleanup_shell = True
278
278
279
279
280
+ def embed_memfile (options ):
281
+ return shared .Settings .SINGLE_FILE or (shared .Settings .MEM_INIT_METHOD == 0 and (not shared .Settings .MAIN_MODULE and not shared .Settings .SIDE_MODULE and options .debug_level < 4 ))
282
+
283
+
280
284
#
281
285
# Main run() function
282
286
#
@@ -801,7 +805,7 @@ def detect_fixed_language_mode(args):
801
805
options .separate_asm = True
802
806
logging .warning ('forcing separate asm output (--separate-asm), because -s PRECISE_F32=2 or -s USE_PTHREADS=2 was passed.' )
803
807
if options .separate_asm :
804
- shared .Settings .SEPARATE_ASM = os . path . basename (asm_target )
808
+ shared .Settings .SEPARATE_ASM = shared . JS . get_subresource_location (asm_target )
805
809
806
810
if 'EMCC_STRICT' in os .environ :
807
811
shared .Settings .STRICT = os .environ .get ('EMCC_STRICT' ) != '0'
@@ -918,6 +922,8 @@ def check(input_file):
918
922
logging .warning ('disabling closure because debug info was requested' )
919
923
options .use_closure_compiler = False
920
924
925
+ assert not (shared .Settings .EMTERPRETIFY_FILE and shared .Settings .SINGLE_FILE ), 'cannot have both EMTERPRETIFY_FILE and SINGLE_FILE enabled at the same time'
926
+
921
927
assert not (shared .Settings .NO_DYNAMIC_EXECUTION and options .use_closure_compiler ), 'cannot have both NO_DYNAMIC_EXECUTION and closure compiler enabled at the same time'
922
928
923
929
if options .use_closure_compiler :
@@ -1110,10 +1116,16 @@ def check(input_file):
1110
1116
os .environ ['EMCC_WASM_BACKEND_BINARYEN' ] = '1'
1111
1117
1112
1118
if shared .Settings .BINARYEN :
1113
- # set file locations, so that JS glue can find what it needs
1114
- shared .Settings .WASM_TEXT_FILE = os .path .basename (wasm_text_target )
1115
- shared .Settings .WASM_BINARY_FILE = os .path .basename (wasm_binary_target )
1116
- shared .Settings .ASMJS_CODE_FILE = os .path .basename (asm_target )
1119
+ if shared .Settings .SINGLE_FILE :
1120
+ # placeholder strings for JS glue, to be replaced with subresource locations in do_binaryen
1121
+ shared .Settings .WASM_TEXT_FILE = shared .FilenameReplacementStrings .WASM_TEXT_FILE
1122
+ shared .Settings .WASM_BINARY_FILE = shared .FilenameReplacementStrings .WASM_BINARY_FILE
1123
+ shared .Settings .ASMJS_CODE_FILE = shared .FilenameReplacementStrings .ASMJS_CODE_FILE
1124
+ else :
1125
+ # set file locations, so that JS glue can find what it needs
1126
+ shared .Settings .WASM_TEXT_FILE = shared .JS .get_subresource_location (wasm_text_target )
1127
+ shared .Settings .WASM_BINARY_FILE = shared .JS .get_subresource_location (wasm_binary_target )
1128
+ shared .Settings .ASMJS_CODE_FILE = shared .JS .get_subresource_location (asm_target )
1117
1129
1118
1130
shared .Settings .ASM_JS = 2 # when targeting wasm, we use a wasm Memory, but that is not compatible with asm.js opts
1119
1131
shared .Settings .GLOBAL_BASE = 1024 # leave some room for mapping global vars
@@ -1538,6 +1550,10 @@ def get_final():
1538
1550
shared .Settings .MEM_INIT_METHOD = 1
1539
1551
else :
1540
1552
assert shared .Settings .MEM_INIT_METHOD != 1
1553
+
1554
+ if embed_memfile (options ):
1555
+ shared .Settings .SUPPORT_BASE64_EMBEDDING = 1
1556
+
1541
1557
final = shared .Building .emscripten (final , append_ext = False , extra_args = extra_args )
1542
1558
if DEBUG : save_intermediate ('original' )
1543
1559
@@ -1625,7 +1641,8 @@ def get_final():
1625
1641
1626
1642
with ToolchainProfiler .profile_block ('memory initializer' ):
1627
1643
memfile = None
1628
- if shared .Settings .MEM_INIT_METHOD > 0 :
1644
+
1645
+ if shared .Settings .MEM_INIT_METHOD > 0 or embed_memfile (options ):
1629
1646
memfile = target + '.mem'
1630
1647
shared .try_delete (memfile )
1631
1648
def repl (m ):
@@ -1636,20 +1653,17 @@ def repl(m):
1636
1653
while membytes and membytes [- 1 ] == 0 :
1637
1654
membytes .pop ()
1638
1655
if not membytes : return ''
1639
- if not options . memory_init_file :
1656
+ if shared . Settings . MEM_INIT_METHOD == 2 :
1640
1657
# memory initializer in a string literal
1641
1658
return "memoryInitializer = '%s';" % shared .JS .generate_string_initializer (list (membytes ))
1642
1659
open (memfile , 'wb' ).write ('' .join (map (chr , membytes )))
1643
1660
if DEBUG :
1644
1661
# Copy into temp dir as well, so can be run there too
1645
1662
shared .safe_copy (memfile , os .path .join (shared .get_emscripten_temp_dir (), os .path .basename (memfile )))
1646
- if not shared .Settings .BINARYEN :
1647
- return 'memoryInitializer = "%s";' % os . path . basename (memfile )
1663
+ if not shared .Settings .BINARYEN or 'asmjs' in shared . Settings . BINARYEN_METHOD or 'interpret-asm2wasm' in shared . Settings . BINARYEN_METHOD :
1664
+ return 'memoryInitializer = "%s";' % shared . JS . get_subresource_location (memfile , embed_memfile ( options ) )
1648
1665
else :
1649
- # with wasm, we may have the mem init file in the wasm binary already
1650
- return ('memoryInitializer = Module["wasmJSMethod"].indexOf("asmjs") >= 0 || '
1651
- 'Module["wasmJSMethod"].indexOf("interpret-asm2wasm") >= 0 ? "%s" : null;'
1652
- % os .path .basename (memfile ))
1666
+ return 'memoryInitializer = null;'
1653
1667
src = re .sub (shared .JS .memory_initializer_pattern , repl , open (final ).read (), count = 1 )
1654
1668
open (final + '.mem.js' , 'w' ).write (src )
1655
1669
final += '.mem.js'
@@ -1661,15 +1675,6 @@ def repl(m):
1661
1675
logging .debug ('wrote memory initialization to %s' , memfile )
1662
1676
else :
1663
1677
logging .debug ('did not see memory initialization' )
1664
- elif not shared .Settings .MAIN_MODULE and not shared .Settings .SIDE_MODULE and options .debug_level < 4 :
1665
- # not writing a binary init, but we can at least optimize them by splitting them up
1666
- src = open (final ).read ()
1667
- src = shared .JS .optimize_initializer (src )
1668
- if src is not None :
1669
- logging .debug ('optimizing memory initialization' )
1670
- open (final + '.mem.js' , 'w' ).write (src )
1671
- final += '.mem.js'
1672
- src = None
1673
1678
1674
1679
if shared .Settings .USE_PTHREADS :
1675
1680
target_dir = os .path .dirname (os .path .abspath (target ))
@@ -1829,6 +1834,9 @@ def get_eliminate():
1829
1834
if options .proxy_to_worker :
1830
1835
generate_worker_js (target , js_target , target_basename )
1831
1836
1837
+ if embed_memfile (options ):
1838
+ shared .try_delete (memfile )
1839
+
1832
1840
for f in generated_text_files_with_native_eols :
1833
1841
tools .line_endings .convert_line_endings_in_file (f , os .linesep , options .output_eol )
1834
1842
log_time ('final emitting' )
@@ -2352,6 +2360,24 @@ def do_binaryen(final, target, asm_target, options, memfile, wasm_binary_target,
2352
2360
passes .append ('minifyWhitespace' )
2353
2361
final = shared .Building .js_optimizer_no_asmjs (final , passes )
2354
2362
if DEBUG : save_intermediate ('postclean' , 'js' )
2363
+ # replace placeholder strings with correct subresource locations
2364
+ if shared .Settings .SINGLE_FILE :
2365
+ f = open (final , 'rb' )
2366
+ js = f .read ()
2367
+ f .close ()
2368
+ f = open (final , 'wb' )
2369
+ for target , replacement_string , should_embed in [
2370
+ (wasm_text_target , shared .FilenameReplacementStrings .WASM_TEXT_FILE , True ),
2371
+ (wasm_binary_target , shared .FilenameReplacementStrings .WASM_BINARY_FILE , True ),
2372
+ (asm_target , shared .FilenameReplacementStrings .ASMJS_CODE_FILE , not shared .Building .is_wasm_only ())
2373
+ ]:
2374
+ if should_embed and os .path .isfile (target ):
2375
+ js = js .replace (replacement_string , shared .JS .get_subresource_location (target ))
2376
+ else :
2377
+ js = js .replace (replacement_string , '' )
2378
+ shared .try_delete (target )
2379
+ f .write (js )
2380
+ f .close ()
2355
2381
return final
2356
2382
2357
2383
@@ -2399,11 +2425,17 @@ def generate_html(target, options, js_target, target_basename,
2399
2425
} else {
2400
2426
// note: no support for code mods (PRECISE_F32==2)
2401
2427
console.log('running code on the main thread');
2428
+ var filename = '%s';
2429
+ var fileBytes = tryParseAsDataURI(filename);
2402
2430
var script = document.createElement('script');
2403
- script.src = "%s.js";
2431
+ if (fileBytes) {
2432
+ script.innerHTML = intArrayToString(fileBytes);
2433
+ } else {
2434
+ script.src = filename;
2435
+ }
2404
2436
document.body.appendChild(script);
2405
2437
}
2406
- ''' % proxy_worker_filename
2438
+ ''' % shared . JS . get_subresource_location ( proxy_worker_filename + '.js' )
2407
2439
else :
2408
2440
# Normal code generation path
2409
2441
script .src = base_js_target
@@ -2417,33 +2449,40 @@ def generate_html(target, options, js_target, target_basename,
2417
2449
# We need to load the emterpreter file before anything else, it has to be synchronously ready
2418
2450
script .un_src ()
2419
2451
script .inline = '''
2452
+ var emterpretURL = '%s';
2420
2453
var emterpretXHR = new XMLHttpRequest();
2421
- emterpretXHR.open('GET', '%s' , true);
2454
+ emterpretXHR.open('GET', emterpretURL , true);
2422
2455
emterpretXHR.responseType = 'arraybuffer';
2423
2456
emterpretXHR.onload = function() {
2424
- Module.emterpreterFile = emterpretXHR.response;
2457
+ if (emterpretXHR.status === 200 || emterpretXHR.status === 0) {
2458
+ Module.emterpreterFile = emterpretXHR.response;
2459
+ } else {
2460
+ var emterpretURLBytes = tryParseAsDataURI(emterpretURL);
2461
+ if (emterpretURLBytes) {
2462
+ Module.emterpreterFile = emterpretURLBytes.buffer;
2463
+ }
2464
+ }
2425
2465
%s
2426
2466
};
2427
2467
emterpretXHR.send(null);
2428
- ''' % (shared .Settings .EMTERPRETIFY_FILE , script .inline )
2468
+ ''' % (shared .JS . get_subresource_location ( shared . Settings .EMTERPRETIFY_FILE ) , script .inline )
2429
2469
2430
2470
if options .memory_init_file :
2431
2471
# start to load the memory init file in the HTML, in parallel with the JS
2432
2472
script .un_src ()
2433
2473
script .inline = ('''
2434
- (function() {
2435
- var memoryInitializer = '%s';
2436
- if (typeof Module['locateFile'] === 'function') {
2437
- memoryInitializer = Module['locateFile'](memoryInitializer);
2438
- } else if (Module['memoryInitializerPrefixURL']) {
2439
- memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
2440
- }
2441
- var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest();
2442
- meminitXHR.open('GET', memoryInitializer, true);
2443
- meminitXHR.responseType = 'arraybuffer';
2444
- meminitXHR.send(null);
2445
- })();
2446
- ''' % os .path .basename (memfile )) + script .inline
2474
+ var memoryInitializer = '%s';
2475
+ if (typeof Module['locateFile'] === 'function') {
2476
+ memoryInitializer = Module['locateFile'](memoryInitializer);
2477
+ } else if (Module['memoryInitializerPrefixURL']) {
2478
+ memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
2479
+ }
2480
+ Module['memoryInitializerRequestURL'] = memoryInitializer;
2481
+ var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest();
2482
+ meminitXHR.open('GET', memoryInitializer, true);
2483
+ meminitXHR.responseType = 'arraybuffer';
2484
+ meminitXHR.send(null);
2485
+ ''' % shared .JS .get_subresource_location (memfile )) + script .inline
2447
2486
2448
2487
# Download .asm.js if --separate-asm was passed in an asm.js build, or if 'asmjs' is one
2449
2488
# of the wasm run methods.
@@ -2454,22 +2493,37 @@ def generate_html(target, options, js_target, target_basename,
2454
2493
if len (asm_mods ) == 0 :
2455
2494
# just load the asm, then load the rest
2456
2495
script .inline = '''
2496
+ var filename = '%s';
2497
+ var fileBytes = tryParseAsDataURI(filename);
2457
2498
var script = document.createElement('script');
2458
- script.src = "%s";
2499
+ if (fileBytes) {
2500
+ script.innerHTML = intArrayToString(fileBytes);
2501
+ } else {
2502
+ script.src = filename;
2503
+ }
2459
2504
script.onload = function() {
2460
2505
setTimeout(function() {
2461
2506
%s
2462
2507
}, 1); // delaying even 1ms is enough to allow compilation memory to be reclaimed
2463
2508
};
2464
2509
document.body.appendChild(script);
2465
- ''' % (os . path . basename (asm_target ), script .inline )
2510
+ ''' % (shared . JS . get_subresource_location (asm_target ), script .inline )
2466
2511
else :
2467
2512
# may need to modify the asm code, load it as text, modify, and load asynchronously
2468
2513
script .inline = '''
2514
+ var codeURL = '%s';
2469
2515
var codeXHR = new XMLHttpRequest();
2470
- codeXHR.open('GET', '%s' , true);
2516
+ codeXHR.open('GET', codeURL , true);
2471
2517
codeXHR.onload = function() {
2472
- var code = codeXHR.responseText;
2518
+ var code;
2519
+ if (codeXHR.status === 200 || codeXHR.status === 0) {
2520
+ code = codeXHR.responseText;
2521
+ } else {
2522
+ var codeURLBytes = tryParseAsDataURI(codeURL);
2523
+ if (codeURLBytes) {
2524
+ code = intArrayToString(codeURLBytes);
2525
+ }
2526
+ }
2473
2527
%s
2474
2528
var blob = new Blob([code], { type: 'text/javascript' });
2475
2529
codeXHR = null;
@@ -2485,21 +2539,36 @@ def generate_html(target, options, js_target, target_basename,
2485
2539
document.body.appendChild(script);
2486
2540
};
2487
2541
codeXHR.send(null);
2488
- ''' % (os . path . basename (asm_target ), '\n ' .join (asm_mods ), script .inline )
2542
+ ''' % (shared . JS . get_subresource_location (asm_target ), '\n ' .join (asm_mods ), script .inline )
2489
2543
2490
2544
if shared .Settings .BINARYEN and not shared .Settings .BINARYEN_ASYNC_COMPILATION :
2491
2545
# We need to load the wasm file before anything else, it has to be synchronously ready TODO: optimize
2492
2546
script .un_src ()
2493
2547
script .inline = '''
2548
+ var wasmURL = '%s';
2494
2549
var wasmXHR = new XMLHttpRequest();
2495
- wasmXHR.open('GET', '%s' , true);
2550
+ wasmXHR.open('GET', wasmURL , true);
2496
2551
wasmXHR.responseType = 'arraybuffer';
2497
2552
wasmXHR.onload = function() {
2498
- Module.wasmBinary = wasmXHR.response;
2553
+ if (wasmXHR.status === 200 || wasmXHR.status === 0) {
2554
+ Module.wasmBinary = wasmXHR.response;
2555
+ } else {
2556
+ var wasmURLBytes = tryParseAsDataURI(wasmURL);
2557
+ if (wasmURLBytes) {
2558
+ Module.wasmBinary = wasmURLBytes.buffer;
2559
+ }
2560
+ }
2499
2561
%s
2500
2562
};
2501
2563
wasmXHR.send(null);
2502
- ''' % (os .path .basename (wasm_binary_target ), script .inline )
2564
+ ''' % (shared .JS .get_subresource_location (wasm_binary_target ), script .inline )
2565
+
2566
+ # when script.inline isn't empty, add required helper functions such as tryParseAsDataURI
2567
+ if script .inline :
2568
+ for file in ['src/arrayUtils.js' , 'src/base64Utils.js' ]:
2569
+ f = open (shared .path_from_root (file ), 'r' )
2570
+ script .inline = f .read () + script .inline
2571
+ f .close ()
2503
2572
2504
2573
html = open (target , 'wb' )
2505
2574
html_contents = shell .replace ('{{{ SCRIPT }}}' , script .replacement ())
0 commit comments