aboutsummaryrefslogtreecommitdiff
path: root/emcc
diff options
context:
space:
mode:
Diffstat (limited to 'emcc')
-rwxr-xr-xemcc344
1 files changed, 153 insertions, 191 deletions
diff --git a/emcc b/emcc
index 69dd999e..7cc59c53 100755
--- a/emcc
+++ b/emcc
@@ -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);