diff options
Diffstat (limited to 'emcc')
-rwxr-xr-x | emcc | 344 |
1 files changed, 153 insertions, 191 deletions
@@ -74,18 +74,10 @@ emcc can be influenced by a few environment variables: EMMAKEN_COMPILER - The compiler to be used, if you don't want the default clang. ''' -import os, sys, shutil, tempfile, subprocess +import os, sys, shutil, tempfile, subprocess, shlex from subprocess import PIPE, STDOUT from tools import shared - -def execute(cmd, *args, **kw): - try: - return subprocess.Popen(cmd, *args, **kw).communicate() # let compiler frontend print directly, so colors are saved (PIPE kills that) - except: - if not isinstance(cmd, str): - cmd = ' '.join(cmd) - print >> sys.stderr, 'Invoking Process failed: <<< ' + cmd + ' >>>' - raise +from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename # Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt # levels 2 and 3 (emcc 3 is unsafe opts, so unsuitable for the only level to get @@ -128,7 +120,7 @@ if len(sys.argv) == 1: if sys.argv[1] == '--version': print '''emcc (Emscripten GCC-like replacement) 2.0 -Copyright (C) 2011 the Emscripten authors. +Copyright (C) 2012 the Emscripten authors. This is free and open source software under the MIT license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ''' @@ -174,6 +166,12 @@ Options that are modified or new in %s include: 2: -O2 LLVM optimizations 3: -O3 LLVM optimizations (default in -O2+) + --llvm-lto <level> 0: No LLVM LTO (default in -O0) + 1: LLVM LTO (default in -O1+) + Note: If LLVM optimizations are not run + (see --llvm-opts), setting this to 1 has no + effect. + --closure <on> 0: No closure compiler (default in -O0, -O1) 1: Run closure compiler (default in -O2, -O3) @@ -193,10 +191,14 @@ Options that are modified or new in %s include: script to be run. --pre-js <file> A file whose contents are added before the - generated code + generated code. This is done *before* + optimization, so it will be minified + properly if closure compiler is run. --post-js <file> A file whose contents are added after the - generated code + generated code This is done *before* + optimization, so it will be minified + properly if closure compiler is run. --embed-file <file> A file to embed inside the generated JavaScript. The compiled code will be able @@ -210,9 +212,14 @@ Options that are modified or new in %s include: compiled code asynchronously. Otherwise similar to --embed-file, except that this option is only relevant when generating - HTML (it uses asynchronous binary XHRs). + HTML (it uses asynchronous binary XHRs), + or JS that will be used in a web page. If a directory is passed here, its entire contents will be preloaded. + Preloaded files are stored in filename.data, + where filename.html is the main file you + are compiling to. To run your code, you + will need both the .html and the .data. --compression <codec> Compress both the compiled code and embedded/ preloaded files. <codec> should be a triple, @@ -228,6 +235,10 @@ Options that are modified or new in %s include: receive an array/typed array and return an array/typed array. Compression only works when generating HTML. + When compression is on, all filed specified + to be preloaded are compressed in one big + archive, which is given the same name as the + output HTML but with suffix .data.compress --minify <on> 0: Do not minify the generated JavaScript's whitespace (default if closure compiler @@ -255,6 +266,18 @@ Options that are modified or new in %s include: target other than HTML is specified using the -o option. + --js-library <lib> A JavaScript library to use in addition to + those in Emscripten's src/library_* + + -v Turns on verbose output. This will pass + -v to Clang, and also enable EMCC_DEBUG + to details emcc's operations + + --remove-duplicates If set, will remove duplicate symbols when + linking. This can be useful because + llvm-link's behavior is not as permissive + as ld is. + The target file, if specified (-o <target>), defines what will be generated: @@ -276,6 +299,9 @@ the source of emcc (search for 'os.environ'). ''' % (this, this, this) exit(0) +elif len(sys.argv) == 2 and sys.argv[1] == '-v': # -v with no inputs + print 'emcc (Emscripten GCC-like replacement) 2.0' + exit(subprocess.call([shared.CLANG, '-v'])) # If this is a configure-type thing, do not compile to JavaScript, instead use clang # to compile to a native binary (using our headers, so things make sense later) @@ -287,7 +313,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: compiler = shared.to_cc(compiler) cmd = [compiler] + shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] + sys.argv[1:] if DEBUG: print >> sys.stderr, 'emcc, just configuring: ', ' '.join(cmd) - exit(os.execvp(compiler, cmd)) + exit(subprocess.call(cmd)) if os.environ.get('EMMAKEN_COMPILER'): CXX = os.environ['EMMAKEN_COMPILER'] @@ -303,27 +329,22 @@ if os.environ.get('EMMAKEN_CXX'): CC_ADDITIONAL_ARGS = shared.COMPILER_OPTS # + ['-g']? EMMAKEN_CFLAGS = os.environ.get('EMMAKEN_CFLAGS') -if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ') +if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += shlex.split(EMMAKEN_CFLAGS) # ---------------- Utilities --------------- SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc') -BITCODE_SUFFIXES = ('.bc', '.o') +BITCODE_SUFFIXES = ('.bc', '.o', '.obj') DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll') STATICLIB_SUFFIXES = ('.a',) ASSEMBLY_SUFFIXES = ('.ll',) LIB_PREFIXES = ('', 'lib') -IMAGE_SUFFIXES = ('.jpg', '.png', '.bmp') - -def suffix(name): - return name.split('.')[:-1] - -def unsuffixed(name): - return '.'.join(name.split('.')[:-1]) - -def unsuffixed_basename(name): - return os.path.basename(unsuffixed(name)) +seen_names = {} +def uniquename(name): + if name not in seen_names: + seen_names[name] = str(len(seen_names)) + return unsuffixed(name) + '_' + seen_names[name] + (('.' + suffix(name)) if suffix(name) else '') # ---------------- End configs ------------- @@ -343,6 +364,12 @@ for i in range(1, len(sys.argv)): if arg.endswith('.h') and sys.argv[i-1] != '-include': header = True +if '-M' in sys.argv or '-MM' in sys.argv: + # Just output dependencies, do not compile. Warning: clang and gcc behave differently with -MF! (clang seems to not recognize it) + cmd = [CC] + shared.COMPILER_OPTS + sys.argv[1:] + if DEBUG: print >> sys.stderr, 'emcc, just dependencies: ', ' '.join(cmd) + exit(subprocess.call(cmd)) + # Check if a target is specified target = None for i in range(len(sys.argv)-1): @@ -356,8 +383,9 @@ for i in range(len(sys.argv)-1): if header: # header or such if len(sys.argv) >= 3: # if there is a source and a target, then copy, otherwise do nothing - if DEBUG: print >> sys.stderr, 'Just copy.' - shutil.copy(sys.argv[-1], sys.argv[-2]) + sys.argv = filter(lambda arg: not arg.startswith('-I'), sys.argv) + if DEBUG: print >> sys.stderr, 'Just copy:', sys.argv[-1], target + shutil.copy(sys.argv[-1], target) else: if DEBUG: print >> sys.stderr, 'No-op.' exit(0) @@ -371,22 +399,7 @@ else: temp_dir = tempfile.mkdtemp() def in_temp(name): - return os.path.join(temp_dir, name) - -class Compression: - on = False - - @staticmethod - def compressed_name(filename): - return filename + '.compress' - - @staticmethod - def compress(filename): - execute(Compression.encoder, stdin=open(filename, 'rb'), stdout=open(Compression.compressed_name(filename), 'wb')) - - @staticmethod - def worth_it(original, compressed): - return compressed < original - 1500 # save at least one TCP packet or so + return os.path.join(temp_dir, os.path.basename(name)) try: call = CXX if use_cxx else CC @@ -397,15 +410,19 @@ try: opt_level = 0 llvm_opts = None + llvm_lto = None closure = None js_transform = None - pre_js = None - post_js = None + pre_js = '' + post_js = '' minify_whitespace = None - data_files = [] + preload_files = [] + embed_files = [] compression = None ignore_dynamic_linking = False shell_path = shared.path_from_root('src', 'shell.html') + js_libraries = [] + remove_duplicates = False def check_bad_eq(arg): assert '=' not in arg, 'Invalid parameter (do not use "=" with "--" options)' @@ -423,6 +440,11 @@ try: llvm_opts = eval(newargs[i+1]) newargs[i] = '' newargs[i+1] = '' + elif newargs[i].startswith('--llvm-lto'): + check_bad_eq(newargs[i]) + llvm_lto = eval(newargs[i+1]) + newargs[i] = '' + newargs[i+1] = '' elif newargs[i].startswith('--closure'): check_bad_eq(newargs[i]) closure = int(newargs[i+1]) @@ -435,12 +457,12 @@ try: newargs[i+1] = '' elif newargs[i].startswith('--pre-js'): check_bad_eq(newargs[i]) - pre_js = open(newargs[i+1]).read() + pre_js += open(newargs[i+1]).read() + '\n' newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--post-js'): check_bad_eq(newargs[i]) - post_js = open(newargs[i+1]).read() + post_js += open(newargs[i+1]).read() + '\n' newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--minify'): @@ -450,12 +472,12 @@ try: newargs[i+1] = '' elif newargs[i].startswith('--embed-file'): check_bad_eq(newargs[i]) - data_files.append({ 'name': newargs[i+1], 'mode': 'embed' }) + embed_files.append(newargs[i+1]) newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--preload-file'): check_bad_eq(newargs[i]) - data_files.append({ 'name': newargs[i+1], 'mode': 'preload' }) + preload_files.append(newargs[i+1]) newargs[i] = '' newargs[i+1] = '' elif newargs[i].startswith('--compression'): @@ -470,23 +492,30 @@ try: Compression.on = True 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') - f.close() - newargs[i] = '' - newargs[i+1] = '' elif newargs[i] == '--ignore-dynamic-linking': ignore_dynamic_linking = True newargs[i] = '' + elif newargs[i] == '-v': + shared.COMPILER_OPTS += ['-v'] + DEBUG = 1 + newargs[i] = '' elif newargs[i].startswith('--shell-file'): check_bad_eq(newargs[i]) shell_path = newargs[i+1] newargs[i] = '' newargs[i+1] = '' + elif newargs[i].startswith('--js-library'): + check_bad_eq(newargs[i]) + js_libraries.append(newargs[i+1]) + newargs[i] = '' + newargs[i+1] = '' + elif newargs[i] == '--remove-duplicates': + remove_duplicates = True + newargs[i] = '' newargs = [ arg for arg in newargs if arg is not '' ] if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] + if llvm_lto is None: llvm_lto = llvm_opts > 0 if closure is None: closure = 1 if opt_level >= 2 else 0 if minify_whitespace is None: minify_whitespace = closure # if closure is run, minify whitespace @@ -497,9 +526,11 @@ try: settings_changes = [] for i in range(len(newargs)): if newargs[i] == '-s': - assert '=' in newargs[i+1], 'Incorrect syntax for -s (use -s OPT=VAL): ' + newargs[i+1] - settings_changes.append(newargs[i+1]) - newargs[i] = newargs[i+1] = '' + if i+1 < len(newargs) and '=' in newargs[i+1]: # -s OPT=VALUE is for us, -s by itself is a linker option + settings_changes.append(newargs[i+1]) + newargs[i] = newargs[i+1] = '' + else: + print >> sys.stderr, 'emcc: warning: treating -s as linker option and not as -s OPT=VALUE for js compilation' elif newargs[i].startswith('--typed-arrays'): assert '=' not in newargs[i], 'Invalid typed arrays parameter (do not use "=")' settings_changes.append('USE_TYPED_ARRAYS=' + newargs[i+1]) @@ -511,7 +542,7 @@ try: input_files = [] has_source_inputs = False - lib_dirs = [] + lib_dirs = [shared.path_from_root('system', 'lib')] libs = [] for i in range(len(newargs)): # find input files XXX this a simple heuristic. we should really analyze based on a full understanding of gcc params, # right now we just assume that what is left contains no more |-x OPT| things @@ -519,7 +550,7 @@ try: if i > 0: prev = newargs[i-1] - if prev == '-MT': continue # ignore this gcc-style argument + if prev in ['-MT', '-install_name']: continue # ignore this gcc-style argument if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs newargs[i] = '' @@ -531,6 +562,16 @@ try: # this should be bitcode, make sure it is valid if arg.endswith(ASSEMBLY_SUFFIXES) or shared.Building.is_bitcode(arg): input_files.append(arg) + elif arg.endswith(STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES): + # if it's not, and it's a library, just add it to libs to find later + l = unsuffixed_basename(arg) + for prefix in LIB_PREFIXES: + if not prefix: continue + if l.startswith(prefix): + l = l[len(prefix):] + break; + libs.append(l) + newargs[i] = '' else: print >> sys.stderr, 'emcc: %s: warning: Not valid LLVM bitcode' % arg else: @@ -541,6 +582,9 @@ try: elif arg.startswith('-l'): libs.append(arg[2:]) newargs[i] = '' + + original_input_files = input_files[:] + newargs = [ arg for arg in newargs if arg is not '' ] # Find library files @@ -606,7 +650,7 @@ try: for input_file in input_files: if input_file.endswith(SOURCE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: compiling source file: ', input_file - output_file = in_temp(unsuffixed_basename(input_file) + '.o') + output_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] if DEBUG: print >> sys.stderr, "emcc running:", call, ' '.join(args) @@ -617,12 +661,12 @@ try: else: # bitcode if input_file.endswith(BITCODE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: copying bitcode file: ', input_file - temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) elif input_file.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file): if DEBUG: print >> sys.stderr, 'emcc: copying library file: ', input_file - temp_file = in_temp(os.path.basename(input_file)) + temp_file = in_temp(uniquename(input_file)) shutil.copyfile(input_file, temp_file) temp_files.append(temp_file) else: #.ll @@ -630,7 +674,7 @@ try: # Note that by assembling the .ll file, then disassembling it later, we will # remove annotations which is a good thing for compilation time if DEBUG: print >> sys.stderr, 'emcc: assembling assembly file: ', input_file - temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shared.Building.llvm_as(input_file, temp_file) temp_files.append(temp_file) @@ -642,18 +686,16 @@ try: print >> sys.stderr, 'emcc: warning: -Ox flags ignored, since not generating JavaScript' if not specified_target: for input_file in input_files: - shutil.move(in_temp(unsuffixed_basename(input_file) + '.o'), unsuffixed_basename(input_file) + '.' + final_suffix) + shutil.move(in_temp(unsuffixed(uniquename(input_file)) + '.o'), unsuffixed_basename(input_file) + '.' + final_suffix) else: if len(input_files) == 1: - shutil.move(in_temp(unsuffixed_basename(input_files[0]) + '.o'), specified_target) + shutil.move(in_temp(unsuffixed(uniquename(input_files[0])) + '.o'), specified_target) else: - assert not has_dash_c, 'fatal error: cannot specify -o with -c with multiple files' + str(sys.argv) + 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 <target>), which is not JavaScript or HTML, and - # we have multiple files: Link them TODO: llvm link-time opts? - ld_args = temp_files + ['-b', specified_target] - #[arg.split('-Wl,')[1] for arg in filter(lambda arg: arg.startswith('-Wl,'), sys.argv)] - if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(ld_args) - execute([shared.LLVM_LD, '-disable-opt'] + ld_args) + # we have multiple files: Link them + if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(temp_files) + shared.Building.link(temp_files, specified_target, remove_duplicates=remove_duplicates) exit(0) ## Continue on to create JavaScript @@ -671,9 +713,9 @@ try: # dlmalloc def create_dlmalloc(): if DEBUG: print >> sys.stderr, 'emcc: building dlmalloc for cache' - execute([shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=stdout, stderr=stderr) + execute(shared.ENV_PREFIX + ['python', shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-g', '-o', in_temp('dlmalloc.o')], stdout=stdout, stderr=stderr) # we include the libc++ new stuff here, so that the common case of using just new/delete is quick to link - execute([shared.EMXX, shared.path_from_root('system', 'lib', 'libcxx', 'new.cpp'), '-g', '-o', in_temp('new.o')], stdout=stdout, stderr=stderr) + execute(shared.ENV_PREFIX + ['python', shared.EMXX, shared.path_from_root('system', 'lib', 'libcxx', 'new.cpp'), '-g', '-o', in_temp('new.o')], stdout=stdout, stderr=stderr) shared.Building.link([in_temp('dlmalloc.o'), in_temp('new.o')], in_temp('dlmalloc_full.o')) return in_temp('dlmalloc_full.o') def fix_dlmalloc(): @@ -699,7 +741,7 @@ try: assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++ with QUANTUM_SIZE == 1' # libcxx might need corrections, so turn them all on. TODO: check which are actually needed shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 - print >> sys.stderr, 'emcc: warning: using libcxx turns on CORRECT_* options' + #print >> sys.stderr, 'emcc: info: using libcxx turns on CORRECT_* options' libcxx_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxx', 'symbols')).readlines()) libcxx_symbols = filter(lambda symbol: symbol not in dlmalloc_symbols, libcxx_symbols) libcxx_symbols = set(libcxx_symbols) @@ -711,7 +753,7 @@ try: return os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'libcxxabi', 'libcxxabi.bc') def fix_libcxxabi(): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++abi with QUANTUM_SIZE == 1' - print >> sys.stderr, 'emcc: warning: using libcxxabi, this may need CORRECT_* options' + #print >> sys.stderr, 'emcc: info: using libcxxabi, this may need CORRECT_* options' #shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 libcxxabi_symbols = map(lambda line: line.strip().split(' ')[1], open(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols')).readlines()) libcxxabi_symbols = filter(lambda symbol: symbol not in dlmalloc_symbols, libcxxabi_symbols) @@ -745,8 +787,7 @@ try: (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in DYNAMICLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link if DEBUG: print >> sys.stderr, 'emcc: linking: ', linker_inputs - shared.Building.link(linker_inputs, - in_temp(target_basename + '.bc')) + shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), remove_duplicates=remove_duplicates) final = in_temp(target_basename + '.bc') else: if not LEAVE_INPUTS_RAW: @@ -772,7 +813,7 @@ try: shared.Building.llvm_opt(in_temp(target_basename + '.bc'), llvm_opts) if DEBUG: save_intermediate('opt', 'bc') # Do LTO in a separate pass to work around LLVM bug XXX (see failure e.g. in cubescript) - if shared.Building.can_use_unsafe_opts() and shared.Building.can_build_standalone(): + if llvm_lto and shared.Building.can_use_unsafe_opts() and shared.Building.can_build_standalone(): lto_opts = [] if not shared.Building.can_inline(): lto_opts.append('-disable-inlining') lto_opts.append('-std-link-opts') @@ -795,117 +836,29 @@ try: if AUTODEBUG: if DEBUG: print >> sys.stderr, 'emcc: autodebug' - execute(['python', shared.AUTODEBUGGER, final, final + '.ad.ll']) + execute(shared.ENV_PREFIX + ['python', shared.AUTODEBUGGER, final, final + '.ad.ll']) final += '.ad.ll' if DEBUG: save_intermediate('autodebug', 'll') # Emscripten if DEBUG: print >> sys.stderr, 'emcc: LLVM => JS' - final = shared.Building.emscripten(final, append_ext=False) + extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))] + final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args) if DEBUG: save_intermediate('original') # Embed and preload files - if len(data_files) > 0: + if len(preload_files) + len(embed_files) > 0: if DEBUG: print >> sys.stderr, 'emcc: setting up files' - code = '' - - # Expand directories into individual files - def add(mode, dirname, names): - for name in names: - combined = os.path.join(dirname, name) - data_files.append({ 'name': os.path.join(dirname, name), 'mode': mode }) - - for file_ in data_files: - if os.path.isdir(file_['name']): - os.path.walk(file_['name'], add, file_['mode']) - data_files = filter(lambda file_: not os.path.isdir(file_['name']), data_files) - - for file_ in data_files: - file_['net_name'] = file_['name'] - file_['compressed'] = False - + file_args = [] + if len(preload_files) > 0: + file_args.append('--preload') + file_args += preload_files + if len(embed_files) > 0: + file_args.append('--embed') + file_args += embed_files if Compression.on: - # Compress each file, if it is worth it - for file_ in data_files: - Compression.compress(file_['name']) - if Compression.worth_it(os.stat(file_['name']).st_size, - os.stat(Compression.compressed_name(file_['name'])).st_size): - file_['net_name'] = Compression.compressed_name(file_['name']) - file_['compressed'] = True - else: - if DEBUG: print >> sys.stderr, 'emcc: not compressing %s since not worth it' % file_['name'] - os.remove(Compression.compressed_name(file_['name'])) - - # Set up folders - partial_dirs = [] - for file_ in data_files: - dirname = os.path.dirname(file_['name']) - parts = dirname.split(os.path.sep) - if dirname != '' and dirname != os.path.sep: - for i in range(len(parts)): - partial = os.path.sep.join(parts[:i]) - if partial not in partial_dirs: - code += '''FS.createFolder('/%s', '%s', true, false);\n''' % (os.path.sep.join(parts[:i-1]), parts[-1]) - partial_dirs.append(partial) - - counter = 0 - for file_ in data_files: - filename = file_['name'] - if file_['mode'] == 'embed': - # Embed - code += '''FS.createDataFile('/', '%s', %s, true, true);\n''' % (os.path.basename(filename), str(map(ord, open(filename, 'rb').read()))) - elif file_['mode'] == 'preload': - # Preload - varname = 'filePreload%d' % counter - counter += 1 - image = filename.endswith(IMAGE_SUFFIXES) - code += ''' - var %(varname)s = new XMLHttpRequest(); - %(varname)s.open('GET', '%(netname)s', true); - %(varname)s.responseType = 'arraybuffer'; - %(varname)s.onload = function() { - var arrayBuffer = %(varname)s.response; // Note: not X.responseText - assert(arrayBuffer, 'Loading file %(filename)s failed.'); - var byteArray = new Uint8Array(arrayBuffer); - %(decompress_start)s - FS.createDataFile('/%(dirname)s', '%(basename)s', byteArray, true, true); - %(finish)s - %(decompress_end)s - }; - addRunDependency(); - %(varname)s.send(null); -''' % { - 'varname': varname, - 'filename': filename, - 'netname': file_['net_name'], - 'dirname': os.path.dirname(filename), - 'basename': os.path.basename(filename), - 'decompress_start': '' if not file_['compressed'] else 'Module["decompress"](byteArray, function(decompressed) { byteArray = new Uint8Array(decompressed);', - 'decompress_end': '' if not file_['compressed'] else '});', - 'finish': 'removeRunDependency();' if not image else '''var bb = new MozBlobBuilder(); - bb.append(byteArray.buffer); - var b = bb.getBlob(); - var url = window.URL.createObjectURL(b); - var img = new Image(); - img.onload = function() { - assert(img.complete, 'Image %(filename)s could not be decoded'); - var canvas = document.createElement('canvas'); - canvas.width = img.width; - canvas.height = img.height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(img, 0, 0); - preloadedImages['%(filename)s'] = ctx.getImageData(0, 0, canvas.width, canvas.height); - window.URL.revokeObjectURL(url); - removeRunDependency(); - }; - img.onerror = function(event) { - console.log('Image %(filename)s could not be decoded: ' + JSON.stringify(event)); - }; - img.src = url; -''' % { 'filename': filename } - } - else: - assert 0 + file_args += ['--compress', Compression.encoder, Compression.decoder, Compression.js_name] + code = execute(shared.ENV_PREFIX + ['python', shared.FILE_PACKAGER, unsuffixed(target) + '.data'] + file_args, stdout=PIPE)[0] src = open(final).read().replace('// {{PRE_RUN_ADDITIONS}}', code) final += '.files.js' open(final, 'w').write(src) @@ -916,15 +869,16 @@ try: if DEBUG: print >> sys.stderr, 'emcc: applying pre/postjses' src = open(final).read() final += '.pp.js' - open(final, 'w').write((pre_js or '') + src + (post_js or '')) + open(final, 'w').write(pre_js + src + post_js) if DEBUG: save_intermediate('pre-post') # Apply a source code transformation, if requested if js_transform: shutil.copyfile(final, final + '.tr.js') final += '.tr.js' + posix = True if not shared.WINDOWS else False if DEBUG: print >> sys.stderr, 'emcc: applying transform: %s' % js_transform - execute(js_transform.split(' ') + [os.path.abspath(final)]) + execute(shlex.split(js_transform, posix=posix) + [os.path.abspath(final)]) if DEBUG: save_intermediate('transformed') # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing @@ -954,18 +908,16 @@ try: flush_js_optimizer_queue() - # eliminator if DEBUG: print >> sys.stderr, 'emcc: running variable eliminator' final = shared.Building.eliminator(final) if DEBUG: save_intermediate('eliminator') - # js optimizer pre-pass js_optimizer_queue += ['simplifyExpressionsPre'] if shared.Settings.RELOOP: js_optimizer_queue += ['optimizeShiftsAggressive'] # aggressive shifts optimization requires loops, it breaks on switches - flush_js_optimizer_queue() - final = shared.Building.eliminator(final) # aggressive shifts optimization introduces some new variables, remove ones that we can - if DEBUG: save_intermediate('eliminator') + flush_js_optimizer_queue() + final = shared.Building.eliminator(final) # aggressive shifts optimization introduces some new variables, remove ones that we can + if DEBUG: save_intermediate('eliminator') if closure: flush_js_optimizer_queue() @@ -975,7 +927,6 @@ try: if DEBUG: save_intermediate('closure') if opt_level >= 1: - # js optimizer post-pass if DEBUG: print >> sys.stderr, 'emcc: running post-closure post-opts' js_optimizer_queue += ['simplifyExpressionsPost'] @@ -1005,14 +956,25 @@ try: decoding = ''' var decompressWorker = new Worker('decompress.js'); var decompressCallbacks = []; + var decompressions = 0; Module["decompress"] = function(data, callback) { var id = decompressCallbacks.length; decompressCallbacks.push(callback); decompressWorker.postMessage({ data: data, id: id }); + if (Module['setStatus']) { + decompressions++; + Module['setStatus']('Decompressing...'); + } }; decompressWorker.onmessage = function(event) { decompressCallbacks[event.data.id](event.data.data); decompressCallbacks[event.data.id] = null; + if (Module['setStatus']) { + decompressions--; + if (decompressions == 0) { + Module['setStatus'](''); + } + } }; var compiledCodeXHR = new XMLHttpRequest(); compiledCodeXHR.open('GET', '%s', true); |