aboutsummaryrefslogtreecommitdiff
path: root/tools/shared.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/shared.py')
-rw-r--r--tools/shared.py172
1 files changed, 109 insertions, 63 deletions
diff --git a/tools/shared.py b/tools/shared.py
index 6d757af4..5425d2c1 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -270,7 +270,7 @@ if EM_POPEN_WORKAROUND and os.name == 'nt':
# Expectations
-EXPECTED_LLVM_VERSION = (3,2)
+EXPECTED_LLVM_VERSION = (3,3)
actual_clang_version = None
@@ -303,10 +303,33 @@ def check_fastcomp():
print >> sys.stderr, '==========================================================================='
print >> sys.stderr, llc_version_info,
print >> sys.stderr, '==========================================================================='
+ logging.critical('you can fall back to the older (pre-fastcomp) compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend')
return False
+
+ # look for a source tree under the llvm binary directory. if there is one, look for emscripten-version.txt files
+ seen = False
+ d = os.path.dirname(LLVM_COMPILER)
+ while d != os.path.dirname(d):
+ # look for version file in llvm repo, making sure not to mistake the emscripten repo for it
+ if os.path.exists(os.path.join(d, 'emscripten-version.txt')) and not os.path.abspath(d) == os.path.abspath(path_from_root()):
+ seen = True
+ llvm_version = open(os.path.join(d, 'emscripten-version.txt')).read().strip()
+ if os.path.exists(os.path.join(d, 'tools', 'clang', 'emscripten-version.txt')):
+ clang_version = open(os.path.join(d, 'tools', 'clang', 'emscripten-version.txt')).read().strip()
+ elif os.path.exists(os.path.join(d, 'tools', 'clang')):
+ clang_version = '?' # Looks like the LLVM compiler tree has an old checkout from the time before it contained a version.txt: Should update!
+ else:
+ clang_version = llvm_version # This LLVM compiler tree does not have a tools/clang, so it's probably an out-of-source build directory. No need for separate versioning.
+ if EMSCRIPTEN_VERSION != llvm_version or EMSCRIPTEN_VERSION != clang_version:
+ logging.error('Emscripten, llvm and clang versions do not match, this is dangerous (%s, %s, %s)', EMSCRIPTEN_VERSION, llvm_version, clang_version)
+ logging.error('Make sure to use the same branch in each repo, and to be up-to-date on each. See https://github.com/kripken/emscripten/wiki/LLVM-Backend')
+ break
+ d = os.path.dirname(d)
+ if not seen:
+ logging.warning('did not see a source tree above LLVM_DIR, could not verify version numbers match')
return True
except Exception, e:
- logging.warning('cound not check fastcomp: %s' % str(e))
+ logging.warning('could not check fastcomp: %s' % str(e))
return True
EXPECTED_NODE_VERSION = (0,8,0)
@@ -345,7 +368,11 @@ def find_temp_directory():
# we re-check sanity when the settings are changed)
# We also re-check sanity and clear the cache when the version changes
-EMSCRIPTEN_VERSION = '1.11.0'
+try:
+ EMSCRIPTEN_VERSION = open(path_from_root('emscripten-version.txt')).read().strip()
+except Exception, e:
+ logging.error('cannot find emscripten version ' + str(e))
+ EMSCRIPTEN_VERSION = 'unknown'
def generate_sanity():
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()
@@ -379,7 +406,7 @@ def check_sanity(force=False):
# some warning, mostly not fatal checks - do them even if EM_IGNORE_SANITY is on
check_llvm_version()
check_node_version()
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
fastcomp_ok = check_fastcomp()
if os.environ.get('EM_IGNORE_SANITY'):
@@ -402,7 +429,7 @@ def check_sanity(force=False):
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
sys.exit(1)
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
if not fastcomp_ok:
logging.critical('failing sanity checks due to previous fastcomp failure')
sys.exit(1)
@@ -602,7 +629,11 @@ except:
# Target choice. Must be synced with src/settings.js (TARGET_*)
def get_llvm_target():
- return os.environ.get('EMCC_LLVM_TARGET') or 'le32-unknown-nacl' # 'i386-pc-linux-gnu'
+ if os.environ.get('EMCC_FAST_COMPILER') == '0':
+ if not os.environ.get('EMCC_LLVM_TARGET'):
+ os.environ['EMCC_LLVM_TARGET'] = 'le32-unknown-nacl'
+ return os.environ.get('EMCC_LLVM_TARGET')
+ return os.environ.get('EMCC_LLVM_TARGET') or 'asmjs-unknown-emscripten'
LLVM_TARGET = get_llvm_target()
# COMPILER_OPTS: options passed to clang when generating bitcode for us
@@ -610,40 +641,73 @@ try:
COMPILER_OPTS # Can be set in EM_CONFIG, optionally
except:
COMPILER_OPTS = []
-COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-DEMSCRIPTEN', '-D__EMSCRIPTEN__',
- '-fno-math-errno',
- #'-fno-threadsafe-statics', # disabled due to issue 1289
+COMPILER_OPTS = COMPILER_OPTS + [#'-fno-threadsafe-statics', # disabled due to issue 1289
'-target', LLVM_TARGET]
-if LLVM_TARGET == 'le32-unknown-nacl':
- COMPILER_OPTS = filter(lambda opt: opt != '-m32', COMPILER_OPTS) # le32 target is 32-bit anyhow, no need for -m32
- COMPILER_OPTS += ['-U__native_client__', '-U__pnacl__', '-U__ELF__'] # The nacl target is originally used for Google Native Client. Emscripten is not NaCl, so remove the platform #define, when using their triple.
-
-# Remove various platform specific defines, and set little endian
-COMPILER_STANDARDIZATION_OPTS = ['-U__i386__', '-U__i386', '-Ui386', '-U__STRICT_ANSI__', '-D__IEEE_LITTLE_ENDIAN',
- '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__',
- '-U__APPLE__', '-U__linux__']
+# COMPILER_STANDARDIZATION_OPTS: Options to correct various predefined macro options.
+COMPILER_STANDARDIZATION_OPTS = []
+
+# When we're not using an appropriate target triple, use -m32 to get i386, which we
+# can mostly make work.
+if LLVM_TARGET != 'asmjs-unknown-emscripten' and LLVM_TARGET != 'le32-unknown-nacl':
+ COMPILER_OPTS += ['-m32']
+ COMPILER_STANDARDIZATION_OPTS += ['-U__i386__', '-U__i386', '-Ui386',
+ '-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__',
+ '-U__APPLE__', '-U__linux__']
+
+# With the asmjs-unknown-emscripten target triple, clang sets up language modes
+# and predefined macros properly. When using the other targets, we have to set things
+# up manually.
+if LLVM_TARGET != 'asmjs-unknown-emscripten':
+ COMPILER_OPTS += ['-fno-math-errno']
+ COMPILER_STANDARDIZATION_OPTS += ['-D__IEEE_LITTLE_ENDIAN']
+ COMPILER_OPTS += ['-DEMSCRIPTEN', '-D__EMSCRIPTEN__', '-fno-math-errno',
+ '-U__native_client__', '-U__pnacl__', '-U__ELF__']
+
+# Changes to default clang behavior
+if LLVM_TARGET == 'asmjs-unknown-emscripten' or LLVM_TARGET == 'le32-unknown-nacl':
+ # Implicit functions can cause horribly confusing asm.js function pointer type errors, see #2175
+ # If your codebase really needs them - very unrecommended! - you can disable the error with
+ # -Wno-error=implicit-function-declaration
+ # or disable even a warning about it with
+ # -Wno-implicit-function-declaration
+ COMPILER_OPTS += ['-Werror=implicit-function-declaration']
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', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
- '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'compat'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'libcxx'),
- '-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', 'gfx'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'net'),
- '-Xclang', '-isystem' + path_from_root('system', 'include', 'SDL'),
+ C_INCLUDE_PATHS = [path_from_root('system', 'local', 'include'),
+ path_from_root('system', 'include', 'compat'),
+ path_from_root('system', 'include'),
+ path_from_root('system', 'include', 'emscripten'),
+ path_from_root('system', 'include', 'bsd'), # posix stuff
+ path_from_root('system', 'include', 'libc'),
+ path_from_root('system', 'include', 'gfx'),
+ path_from_root('system', 'include', 'net'),
+ path_from_root('system', 'include', 'SDL'),
+ ]
+
+ CXX_INCLUDE_PATHS = [path_from_root('system', 'include', 'libcxx')
+ ]
+
+ C_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc',
]
+
+ def include_directive(paths):
+ result = []
+ for path in paths:
+ result += ['-Xclang', '-isystem' + path]
+ return result
+
+ EMSDK_OPTS = C_OPTS + include_directive(C_INCLUDE_PATHS) + include_directive(CXX_INCLUDE_PATHS)
+
EMSDK_OPTS += COMPILER_STANDARDIZATION_OPTS
- if LLVM_TARGET != 'le32-unknown-nacl':
- EMSDK_CXX_OPTS = ['-nostdinc++'] # le32 target does not need -nostdinc++
+ # For temporary compatibility, treat 'le32-unknown-nacl' as 'asmjs-unknown-emscripten'.
+ if LLVM_TARGET != 'asmjs-unknown-emscripten' and \
+ LLVM_TARGET != 'le32-unknown-pnacl':
+ EMSDK_CXX_OPTS = ['-nostdinc++'] # asmjs-unknown-emscripten target does not need -nostdinc++
else:
EMSDK_CXX_OPTS = []
COMPILER_OPTS += EMSDK_OPTS
@@ -658,10 +722,13 @@ else:
# Engine tweaks
try:
- if 'gcparam' not in str(SPIDERMONKEY_ENGINE):
- if type(SPIDERMONKEY_ENGINE) is str:
- SPIDERMONKEY_ENGINE = [SPIDERMONKEY_ENGINE]
- SPIDERMONKEY_ENGINE += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap
+ new_spidermonkey = listify(SPIDERMONKEY_ENGINE)
+ if 'gcparam' not in str(new_spidermonkey):
+ new_spidermonkey += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap
+ if '-w' not in str(new_spidermonkey):
+ new_spidermonkey += ['-w']
+ JS_ENGINES = map(lambda x: new_spidermonkey if x == SPIDERMONKEY_ENGINE else x, JS_ENGINES)
+ SPIDERMONKEY_ENGINE = new_spidermonkey
except NameError:
pass
@@ -803,6 +870,8 @@ class Settings2(type):
@classmethod
def apply_opt_level(self, opt_level, noisy=False):
+ if opt_level == 0 and os.environ.get('EMCC_FAST_COMPILER') == '0':
+ self.attrs['ASM_JS'] = 0 # non-fastcomp has asm off in -O1
if opt_level >= 1:
self.attrs['ASM_JS'] = 1
self.attrs['ASSERTIONS'] = 0
@@ -1467,7 +1536,7 @@ class Building:
@staticmethod
def ensure_relooper(relooper):
if os.path.exists(relooper): return
- if os.environ.get('EMCC_FAST_COMPILER') == '1':
+ if os.environ.get('EMCC_FAST_COMPILER') != '0':
logging.debug('not building relooper to js, using it in c++ backend')
return
@@ -1528,34 +1597,6 @@ class Building:
import gen_struct_info
gen_struct_info.main(['-qo', info_path, path_from_root('src/struct_info.json')])
- @staticmethod
- def preprocess(infile, outfile):
- '''
- Preprocess source C/C++ in some special ways that emscripten needs. Returns
- a filename (potentially the same one if nothing was changed).
-
- Currently this only does emscripten_jcache_printf(..) rewriting.
- '''
- src = open(infile).read() # stack warning on jcacheprintf! in docs # add jcache printf test separatrely, for content of printf
- if 'emscripten_jcache_printf' not in src: return infile
- def fix(m):
- text = m.groups(0)[0]
- assert text.count('(') == 1 and text.count(')') == 1, 'must have simple expressions in emscripten_jcache_printf calls, no parens'
- assert text.count('"') == 2, 'must have simple expressions in emscripten_jcache_printf calls, no strings as varargs parameters'
- if os.environ.get('EMCC_FAST_COMPILER') == '1': # fake it in fastcomp
- return text.replace('emscripten_jcache_printf', 'printf')
- start = text.index('(')
- end = text.rindex(')')
- args = text[start+1:end].split(',')
- args = map(lambda x: x.strip(), args)
- if args[0][0] == '"':
- # flatten out
- args = map(lambda x: str(ord(x)), args[0][1:len(args[0])-1]) + ['0'] + args[1:]
- return 'emscripten_jcache_printf_(' + ','.join(args) + ')'
- src = re.sub(r'(emscripten_jcache_printf\([^)]+\))', lambda m: fix(m), src)
- open(outfile, 'w').write(src)
- return outfile
-
# compatibility with existing emcc, etc. scripts
Cache = cache.Cache(debug=DEBUG_CACHE)
JCache = cache.JCache(Cache)
@@ -1764,5 +1805,10 @@ def unsuffixed(name):
def unsuffixed_basename(name):
return os.path.basename(unsuffixed(name))
+def safe_move(src, dst):
+ if os.path.abspath(src) == os.path.abspath(dst):
+ return
+ shutil.move(src, dst)
+
import js_optimizer