diff options
Diffstat (limited to 'tools/shared.py')
-rw-r--r-- | tools/shared.py | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/tools/shared.py b/tools/shared.py index f71bec72..c09db358 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -114,6 +114,7 @@ LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis')) LLVM_NM=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-nm')) LLVM_INTERPRETER=os.path.expanduser(os.path.join(LLVM_ROOT, 'lli')) LLVM_COMPILER=os.path.expanduser(os.path.join(LLVM_ROOT, 'llc')) +LLVM_EXTRACT=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-extract')) COFFEESCRIPT = path_from_root('tools', 'eliminator', 'node_modules', 'coffee-script', 'bin', 'coffee') EMSCRIPTEN = path_from_root('emscripten.py') @@ -131,6 +132,7 @@ BINDINGS_GENERATOR = path_from_root('tools', 'bindings_generator.py') EXEC_LLVM = path_from_root('tools', 'exec_llvm.py') VARIABLE_ELIMINATOR = path_from_root('tools', 'eliminator', 'eliminator.coffee') JS_OPTIMIZER = path_from_root('tools', 'js-optimizer.js') +FILE_PACKAGER = path_from_root('tools', 'file_packager.py') # Temp dir. Create a random one, unless EMCC_DEBUG is set, in which case use TEMP_DIR/emscripten_temp @@ -196,8 +198,11 @@ USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK') if USE_EMSDK: # Disable system C and C++ include directories, and add our own (using -idirafter so they are last, like system dirs, which # allows projects to override them) - EMSDK_OPTS = ['-nostdinc', '-nostdinc++', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdinc++', '-Xclang', '-nostdsysteminc', + # Note that -nostdinc++ is not needed, since -nostdinc implies that! + EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', + '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'), '-Xclang', '-isystem' + path_from_root('system', 'include'), + '-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'bsd'), # posix stuff '-Xclang', '-isystem' + path_from_root('system', 'include', 'libc'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'), @@ -392,11 +397,12 @@ class Settings: if opt_level >= 2: Settings.RELOOP = 1 if opt_level >= 3: + Settings.INLINING_LIMIT = 0 + Settings.DOUBLE_MODE = 0 + Settings.PRECISE_I64_MATH = 0 Settings.CORRECT_SIGNS = 0 Settings.CORRECT_OVERFLOWS = 0 Settings.CORRECT_ROUNDINGS = 0 - Settings.DOUBLE_MODE = 0 - Settings.PRECISE_I64_MATH = 0 if noisy: print >> sys.stderr, 'Warning: Applying some potentially unsafe optimizations! (Use -O2 if this fails.)' global Settings @@ -419,7 +425,7 @@ class Building: env['CXX'] = EMXX if not WINDOWS else 'python %r' % EMXX env['AR'] = EMAR if not WINDOWS else 'python %r' % EMAR env['RANLIB'] = EMRANLIB if not WINDOWS else 'python %r' % EMRANLIB - env['LIBTOOL'] = EMLIBTOOL if not WINDOWS else 'python %r' % EMLIBTOOL + #env['LIBTOOL'] = EMLIBTOOL if not WINDOWS else 'python %r' % EMLIBTOOL env['EMMAKEN_COMPILER'] = Building.COMPILER env['EMSCRIPTEN_TOOLS'] = path_from_root('tools') env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(Building.COMPILER_TEST_OPTS) @@ -427,6 +433,8 @@ class Building: env['HOST_CXX'] = CLANG_CPP env['HOST_CFLAGS'] = "-W" #if set to nothing, CFLAGS is used, which we don't want env['HOST_CXXFLAGS'] = "-W" #if set to nothing, CXXFLAGS is used, which we don't want + env['PKG_CONFIG_LIBDIR'] = path_from_root('system', 'local', 'lib', 'pkgconfig') + os.path.pathsep + path_from_root('system', 'lib', 'pkgconfig') + env['PKG_CONFIG_PATH'] = os.environ.get ('EM_PKG_CONFIG_PATH') or '' return env @staticmethod @@ -528,7 +536,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e return generated_libs @staticmethod - def link(files, target): + def link(files, target, remove_duplicates=False): actual_files = [] unresolved_symbols = set() # necessary for .a linking, see below resolved_symbols = set() @@ -577,8 +585,27 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e finally: os.chdir(cwd) try_delete(target) + + if remove_duplicates: + # Remove duplicate symbols. This is a workaround for how we compile .a files, we try to + # emulate ld behavior which is permissive TODO: cache llvm-nm results + seen_symbols = set() + print >> sys.stderr, actual_files + for actual in actual_files: + symbols = Building.llvm_nm(actual) + dupes = seen_symbols.intersection(symbols.defs) + if len(dupes) > 0: + print >> sys.stderr, 'emcc: warning: removing duplicates in', actual + for dupe in dupes: + print >> sys.stderr, 'emcc: warning: removing duplicate', dupe + Popen([LLVM_EXTRACT, actual, '-delete', '-glob=' + dupe, '-o', actual], stderr=PIPE).communicate() + Popen([LLVM_EXTRACT, actual, '-delete', '-func=' + dupe, '-o', actual], stderr=PIPE).communicate() + Popen([LLVM_EXTRACT, actual, '-delete', '-glob=.str', '-o', actual], stderr=PIPE).communicate() # garbage that appears here + seen_symbols = seen_symbols.union(symbols.defs) + + # Finish link output = Popen([LLVM_LINK] + actual_files + ['-o', target], stdout=PIPE).communicate()[0] - assert os.path.exists(target) and (output is None or 'Could not open input file' not in output), 'Linking error: ' + output + assert os.path.exists(target) and (output is None or 'Could not open input file' not in output), 'Linking error: ' + output + '\nemcc: If you get duplicate symbol errors, try --remove-duplicates' if temp_dir: try_delete(temp_dir) @@ -811,8 +838,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e if type(passes) == str: passes = [passes] # XXX Disable crankshaft to work around v8 bug 1895 - output, err = Popen([NODE_JS, '--nocrankshaft', JS_OPTIMIZER, filename] + passes, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() - assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + err + '\n\n' + output + output = Popen([NODE_JS, '--nocrankshaft', JS_OPTIMIZER, filename] + passes, stdout=PIPE).communicate()[0] + assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output filename += '.jo.js' f = open(filename, 'w') f.write(output) @@ -827,8 +854,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e coffee = path_from_root('tools', 'eliminator', 'node_modules', 'coffee-script', 'bin', 'coffee') eliminator = path_from_root('tools', 'eliminator', 'eliminator.coffee') input = open(filename, 'r').read() - output, err = Popen([NODE_JS, coffee, eliminator], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(input) - assert len(output) > 0, 'Error in eliminator: ' + err + '\n\n' + output + output = Popen([NODE_JS, coffee, eliminator, filename], stdout=PIPE).communicate()[0] + assert len(output) > 0, 'Error in eliminator: ' + output filename += '.el.js' f = open(filename, 'w') f.write(output) @@ -932,3 +959,41 @@ class Cache: shutil.copyfile(creator(), cachename) return cachename +# Compression of code and data for smaller downloads +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 + +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 + +def suffix(name): + parts = name.split('.') + if len(parts) > 1: + return parts[-1] + else: + return None + +def unsuffixed(name): + return '.'.join(name.split('.')[:-1]) + +def unsuffixed_basename(name): + return os.path.basename(unsuffixed(name)) + |