aboutsummaryrefslogtreecommitdiff
path: root/emcc
diff options
context:
space:
mode:
Diffstat (limited to 'emcc')
-rwxr-xr-xemcc858
1 files changed, 615 insertions, 243 deletions
diff --git a/emcc b/emcc
index 7c971b71..9feba1b1 100755
--- a/emcc
+++ b/emcc
@@ -1,4 +1,5 @@
#!/usr/bin/env python2
+# -*- Mode: python -*-
'''
emcc - compiler helper script
@@ -15,7 +16,7 @@ Example uses:
with that command as an argument, for example
emconfigure.py ./configure [options]
-
+
emconfigure.py is a tiny script that just sets some environment vars
as a convenience. The command just shown is equivalent to
@@ -27,34 +28,6 @@ Example uses:
so it should relay everything to gcc/g++. You should not define that when
running make, of course.
- * With CMake, the same command will work (with cmake instead of ./configure). You may also be
- able to do the following in your CMakeLists.txt:
-
- SET(CMAKE_C_COMPILER "PATH/emcc")
- SET(CMAKE_CXX_COMPILER "PATH/em++")
- SET(CMAKE_LINKER "PATH/emcc")
- SET(CMAKE_CXX_LINKER "PATH/emcc")
- SET(CMAKE_C_LINK_EXECUTABLE "PATH/emcc")
- SET(CMAKE_CXX_LINK_EXECUTABLE "PATH/emcc")
- SET(CMAKE_AR "PATH/emar")
- SET(CMAKE_RANLIB "PATH/emranlib")
-
- * For SCons the shared.py can be imported like so:
- __file__ = str(Dir('#/project_path_to_emscripten/dummy/dummy'))
- __rootpath__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- def path_from_root(*pathelems):
- return os.path.join(__rootpath__, *pathelems)
- sys.path += [path_from_root('')]
- from tools.shared import *
-
- For using the Emscripten compilers/linkers/etc. you can do:
- env = Environment()
- ...
- env.Append(CCFLAGS = COMPILER_OPTS)
- env.Replace(LINK = LLVM_LD)
- env.Replace(LD = LLVM_LD)
- TODO: Document all relevant setup changes
-
After setting that up, run your build system normally.
Note the appearance of em++ instead of emcc
@@ -74,10 +47,13 @@ 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, shlex, time
+import os, sys, shutil, tempfile, subprocess, shlex, time, re, logging
from subprocess import PIPE, STDOUT
from tools import shared
from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename
+from tools.response_file import read_response_file
+
+logging = logging.getLogger('emcc')
# 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
@@ -90,22 +66,25 @@ LLVM_OPT_LEVEL = {
3: 3,
}
-DEBUG = int(os.environ.get('EMCC_DEBUG') or 0)
+DEBUG = os.environ.get('EMCC_DEBUG')
+if DEBUG == "0":
+ DEBUG = None
+
TEMP_DIR = os.environ.get('EMCC_TEMP_DIR')
LEAVE_INPUTS_RAW = os.environ.get('EMCC_LEAVE_INPUTS_RAW') # Do not compile .ll files into .bc, just compile them with emscripten directly
# Not recommended, this is mainly for the test runner, or if you have some other
# specific need.
- # One major limitation with this mode is that dlmalloc and libc++ cannot be
+ # One major limitation with this mode is that libc and libc++ cannot be
# added in. Also, LLVM optimizations will not be done, nor dead code elimination
AUTODEBUG = os.environ.get('EMCC_AUTODEBUG') # If set to 1, we will run the autodebugger (the automatic debugging tool, see tools/autodebugger).
# Note that this will disable inclusion of libraries. This is useful because including
# dlmalloc makes it hard to compare native and js builds
EMCC_CFLAGS = os.environ.get('EMCC_CFLAGS') # Additional compiler flags that we treat as if they were passed to us on the commandline
-if DEBUG: print >> sys.stderr, '\nemcc invocation: ', ' '.join(sys.argv), (' + ' + EMCC_CFLAGS if EMCC_CFLAGS else '')
+logging.debug('invocation: ' + ' '.join(sys.argv) + (' + ' + EMCC_CFLAGS if EMCC_CFLAGS else ''))
if EMCC_CFLAGS: sys.argv.append(EMCC_CFLAGS)
-if DEBUG and LEAVE_INPUTS_RAW: print >> sys.stderr, 'emcc: leaving inputs raw'
+if DEBUG and LEAVE_INPUTS_RAW: logging.warning('leaving inputs raw')
stdout = PIPE if not DEBUG else None # suppress output of child processes
stderr = PIPE if not DEBUG else None # unless we are in DEBUG mode
@@ -115,17 +94,23 @@ shared.check_sanity(force=DEBUG)
# Handle some global flags
if len(sys.argv) == 1:
- print 'emcc: no input files'
+ logging.warning('no input files')
exit(1)
-if sys.argv[1] == '--version':
- print '''emcc (Emscripten GCC-like replacement) 2.0
-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.
- '''
- exit(0)
-elif sys.argv[1] == '--help':
+# read response files very early on
+response_file = True
+while response_file:
+ response_file = None
+ for index in range(1, len(sys.argv)):
+ if sys.argv[index][0] == '@':
+ # found one, loop again next time
+ response_file = True
+ extra_args = read_response_file(sys.argv[index])
+ # slice in extra_args in place of the response file arg
+ sys.argv[index:index+1] = extra_args
+ break
+
+if len(sys.argv) == 1 or '--help' in sys.argv:
this = os.path.basename('em++' if os.environ.get('EMMAKEN_CXX') else 'emcc')
print '''%s [options] file...
@@ -136,7 +121,7 @@ Most normal gcc/g++ options will work, for example:
Options that are modified or new in %s include:
-O0 No optimizations (default)
- -O1 Simple optimizations, including LLVM -O1
+ -O1 Simple optimizations, including asm.js, LLVM -O1
optimizations, and no runtime assertions
or C++ exception catching (to re-enable
C++ exception catching, use
@@ -146,16 +131,28 @@ Options that are modified or new in %s include:
tools/shared.py and also src/settings.js.)
Note: Optimizations are only done when
compiling to JavaScript, not to intermediate
- bitcode.
+ bitcode, *unless* you build with
+ EMCC_OPTIMIZE_NORMALLY=1 (not recommended
+ unless you know what you are doing!)
-O2 As -O1, plus the relooper (loop recreation),
- plus closure compiler advanced opts, plus
- LLVM -O2 optimizations
- Warning: Compiling with this takes a long time!
+ LLVM -O2 optimizations, and
+
+ -s ALIASING_FUNCTION_POINTERS=1
+
-O3 As -O2, plus dangerous optimizations that may
- break the generated code! This is not
- recommended at all, see the wiki for more
- details (you can try -O2 and then add
- dangerous optimizations one by one).
+ break the generated code! This adds
+
+ -s FORCE_ALIGNED_MEMORY=1
+ -s DOUBLE_MODE=0
+ -s PRECISE_I64_MATH=0
+ --closure 1
+ --llvm-lto 1
+
+ This is not recommended at all. A better idea
+ is to try each of these separately on top of
+ -O2 to see what works. See the wiki and
+ src/settings.js (for the -s options) for more
+ information.
-s OPTION=VALUE JavaScript code generation option passed
into the emscripten compiler. For the
@@ -173,10 +170,30 @@ Options that are modified or new in %s include:
(without the external "s in either of those,
you would get an error)
+ You can also specify a file from which the
+ value would be read, for example,
+
+ -s DEAD_FUNCTIONS=@/path/to/file
+
+ The contents of /path/to/file will be read,
+ JSON.parsed and set into DEAD_FUNCTIONS (so
+ the file could contain
+
+ ["_func1", "func2"]
+
+ ). Note that the path must be absolute, not
+ relative.
+
-g Use debug info. Note that you need this during
the last compilation phase from bitcode to
JavaScript, or else we will remove it by
default in -O1 and above.
+ In -O0, line numbers wil be shown in the
+ generated code. In -O1 and above, the optimizer
+ removes those comments. This flag does however
+ have the effect of disabling anything that
+ causes name mangling or minification (closure
+ or the registerize pass).
--typed-arrays <mode> 0: No typed arrays
1: Parallel typed arrays
@@ -187,14 +204,28 @@ 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+)
+ --llvm-lto <level> 0: No LLVM LTO (default in -O2 and below)
+ 1: LLVM LTO (default in -O3)
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)
+ --closure <on> 0: No closure compiler (default in -O2 and below)
+ 1: Run closure compiler. This greatly reduces
+ code size and may in some cases increase
+ runtime speed (although the opposite can also
+ occur). Note that it takes time to run, and
+ may require some changes to the code. This
+ is run by default in -O3.
+
+ In asm.js mode, closure will only be used on the
+ 'shell' code around the compiled code (the
+ compiled code will be processed by the custom
+ asm.js minifier).
+
+ Note: If closure compiler hits an out-of-memory,
+ try adjusting JAVA_HEAP_SIZE in the environment
+ (for example, to 4096m for 4GB).
--js-transform <cmd> <cmd> will be called on the generated code
before it is optimized. This lets you modify
@@ -246,6 +277,15 @@ Options that are modified or new in %s include:
are compiling to. To run your code, you
will need both the .html and the .data.
+ emcc runs tools/file_packager.py to do the
+ actual packaging of embedded and preloaded
+ files. You can run the file packager yourself
+ if you want, see docs inside that file. You
+ should then put the output of the file packager
+ in an emcc --pre-js, so that it executes before
+ your main compiled code (or run it before in
+ some other way).
+
--compression <codec> Compress both the compiled code and embedded/
preloaded files. <codec> should be a triple,
@@ -266,13 +306,11 @@ Options that are modified or new in %s include:
output HTML but with suffix .data.compress
--minify <on> 0: Do not minify the generated JavaScript's
- whitespace (default if closure compiler
- will not be run)
+ whitespace (default in -O0, -O1, or if
+ -g is used)
1: Minify the generated JavaScript's
- whitespace (default if closure compiler
- will be run). Note that this by itself
- will not minify the code (closure does
- that)
+ whitespace (default in -O2+, assuming
+ -g is not used)
--split <size> Splits the resulting javascript file into pieces
to ease debugging. This option only works if
@@ -336,9 +374,48 @@ Options that are modified or new in %s include:
for a later incremental build (where you also
enable it) to be sped up.
+ Caching works separately on 4 parts of compilation:
+ 'pre' which is types and global variables; that
+ information is then fed into 'funcs' which are
+ the functions (which we parallelize), and then
+ 'post' which adds final information based on
+ the functions (e.g., do we need long64 support
+ code). Finally, 'jsfuncs' are JavaScript-level
+ optimizations. Each of the 4 parts can be cached
+ separately, but note that they can affect each
+ other: If you recompile a single C++ file that
+ changes a global variable - e.g., adds, removes
+ or modifies a global variable, say by adding
+ a printf or by adding a compile-time timestamp,
+ then 'pre' cannot be loaded from the cache. And
+ since 'pre's output is sent to 'funcs' and 'post',
+ they will get invalidated as well, and only
+ 'jsfuncs' will be cached. So avoid modifying
+ globals to let caching work fully.
+
+ To work around the problem mentioned in the
+ previous paragraph, you can use
+
+ emscripten_jcache_printf
+
+ when adding debug printfs to your code. That
+ function is specially preprocessed so that it
+ does not create a constant string global for
+ its first argument. See emscripten.h for more
+ details. Note in particular that you need to
+ already have a call to that function in your
+ code *before* you add one and do an incremental
+ build, so that adding an external reference
+ (also a global property) does not invalidate
+ everything.
+
+ Note that you should use -g during the linking
+ stage (bitcode to JS), for jcache to work
+ (otherwise, JS minification can confuse it).
+
--clear-cache Manually clears the cache of compiled
emscripten system libraries (libc++,
- libc++abi, dlmalloc). This is normally
+ libc++abi, libc). This is normally
handled automatically, but if you update
llvm in-place (instead of having a different
directory for a new version), the caching
@@ -350,14 +427,29 @@ Options that are modified or new in %s include:
the bootstrapped relooper. After the cache
is cleared, this process will exit.
+ --save-bc PATH When compiling to JavaScript or HTML, this
+ option will save a copy of the bitcode to
+ the specified path. The bitcode will include
+ all files being linked, including standard
+ libraries, and after any link-time optimizations
+ (if any).
+
+ --memory-init-file <on> If on, we generate a separate memory initialization
+ file. This is more efficient than storing the
+ memory initialization data embedded inside
+ JavaScript as text. (default is off)
+
The target file, if specified (-o <target>), defines what will
be generated:
- <name>.js JavaScript (default)
+ <name>.js JavaScript
<name>.html HTML with embedded JavaScript
- <name>.bc LLVM bitcode
+ <name>.bc LLVM bitcode (default)
<name>.o LLVM bitcode (same as .bc)
+(Note that if --memory-init-file is used, then in addition to a
+.js or .html file that is generated, a .mem file will also appear.)
+
The -c option (which tells gcc not to run the linker) will
cause LLVM bitcode to be generated, as %s only generates
JavaScript in the final linking stage of building.
@@ -373,6 +465,24 @@ emcc: supported targets: llvm bitcode, javascript, NOT elf
(autoconf likes to see elf above to enable shared object support)
''' % (this, this, this)
exit(0)
+
+elif sys.argv[1] == '--version':
+ revision = '(unknown revision)'
+ here = os.getcwd()
+ os.chdir(shared.path_from_root())
+ try:
+ revision = execute(['git', 'show'], stdout=PIPE, stderr=PIPE)[0].split('\n')[0]
+ except:
+ pass
+ finally:
+ os.chdir(here)
+ print '''emcc (Emscripten GCC-like replacement) %s (%s)
+Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
+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.
+ ''' % (shared.EMSCRIPTEN_VERSION, revision)
+ exit(0)
+
elif len(sys.argv) == 2 and sys.argv[1] == '-v': # -v with no inputs
print 'emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 2.0'
exit(subprocess.call([shared.CLANG, '-v']))
@@ -382,7 +492,7 @@ def is_minus_s_for_emcc(newargs,i):
if i+1 < len(newargs) and '=' in newargs[i+1]: # -s OPT=VALUE is for us, -s by itself is a linker option
return True
else:
- print >> sys.stderr, 'emcc: warning: treating -s as linker option and not as -s OPT=VALUE for js compilation'
+ logging.warning('treating -s as linker option and not as -s OPT=VALUE for js compilation')
return False
# If this is a configure-type thing, do not compile to JavaScript, instead use clang
@@ -391,7 +501,7 @@ CONFIGURE_CONFIG = (os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in
CMAKE_CONFIG = 'CMakeFiles/cmTryCompileExec.dir' in ' '.join(sys.argv)# or 'CMakeCCompilerId' in ' '.join(sys.argv)
if CONFIGURE_CONFIG or CMAKE_CONFIG:
debug_configure = 0 # XXX use this to debug configure stuff. ./configure's generally hide our normal output including stderr so we write to a file
- use_clang = 1 # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang
+ use_js = os.environ.get('EMCONFIGURE_JS') # whether we fake configure tests using clang - the local, native compiler - or not. if not we generate JS and use node with a shebang
# neither approach is perfect, you can try both, but may need to edit configure scripts in some cases
# XXX False is not fully tested yet
@@ -408,13 +518,16 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG:
if debug_configure: open(tempout, 'a').write('============= ' + sys.argv[i] + '\n' + src + '\n=============\n\n')
except:
pass
+ if sys.argv[i].endswith('.s'):
+ if debug_configure: open(tempout, 'a').write('(compiling .s assembly, must use clang\n')
+ use_js = 0
if src:
if 'fopen' in src and '"w"' in src:
- use_clang = True # we cannot write to files from js!
+ use_js = 0 # we cannot write to files from js!
if debug_configure: open(tempout, 'a').write('Forcing clang since uses fopen to write\n')
- compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if use_clang else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that
+ compiler = os.environ.get('CONFIGURE_CC') or (shared.CLANG if not use_js else shared.EMCC) # if CONFIGURE_CC is defined, use that. let's you use local gcc etc. if you need that
if not ('CXXCompiler' in ' '.join(sys.argv) or os.environ.get('EMMAKEN_CXX')):
compiler = shared.to_cc(compiler)
@@ -433,12 +546,13 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG:
idx += 1
cmd = [compiler] + list(filter_emscripten_options(sys.argv[1:]))
- if use_clang: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN']
+ if not use_js: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN']
+ if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists
- if DEBUG: print >> sys.stderr, 'emcc, just configuring: ', ' '.join(cmd)
+ logging.debug('just configuring: ' + ' '.join(cmd))
if debug_configure: open(tempout, 'a').write('emcc, just configuring: ' + ' '.join(cmd) + '\n\n')
- if use_clang:
+ if not use_js:
exit(subprocess.call(cmd))
else:
only_object = '-c' in cmd
@@ -461,7 +575,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG:
shutil.copyfile(target, target[:-3])
target = target[:-3]
src = open(target).read()
- full_node = shared.NODE_JS
+ full_node = ' '.join(shared.listify(shared.NODE_JS))
if os.path.sep not in full_node:
full_node = '/usr/bin/' + full_node # TODO: use whereis etc. And how about non-*NIX?
open(target, 'w').write('#!' + full_node + '\n' + src) # add shebang
@@ -487,7 +601,7 @@ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += shlex.split(EMMAKEN_CFLAGS)
# ---------------- Utilities ---------------
-SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc')
+SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc', '.m', '.mm')
BITCODE_SUFFIXES = ('.bc', '.o', '.obj')
DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll')
STATICLIB_SUFFIXES = ('.a',)
@@ -506,7 +620,7 @@ def uniquename(name):
if len(sys.argv) == 1 or sys.argv[1] in ['x', 't']:
# noop ar
- if DEBUG: print >> sys.stderr, 'emcc, just ar'
+ logging.debug('just ar')
sys.exit(0)
use_cxx = True
@@ -515,7 +629,7 @@ header = False # pre-compiled headers. We fake that by just copying the file
for i in range(1, len(sys.argv)):
arg = sys.argv[i]
if not arg.startswith('-'):
- if arg.endswith('.c'):
+ if arg.endswith(('.c','.m')):
use_cxx = False
if arg.endswith('.h') and sys.argv[i-1] != '-include':
header = True
@@ -523,7 +637,7 @@ for i in range(1, len(sys.argv)):
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)
+ logging.debug('just dependencies: ' + ' '.join(cmd))
exit(subprocess.call(cmd))
# Check if a target is specified
@@ -549,10 +663,10 @@ else:
if header: # header or such
if len(sys.argv) >= 3: # if there is a source and a target, then copy, otherwise do nothing
sys.argv = filter(lambda arg: not arg.startswith('-I'), sys.argv)
- if DEBUG: print >> sys.stderr, 'Just copy:', sys.argv[-1], target
+ logging.debug('Just copy:' + sys.argv[-1] + target)
shutil.copy(sys.argv[-1], target)
else:
- if DEBUG: print >> sys.stderr, 'No-op.'
+ logging.debug('No-op.')
exit(0)
if TEMP_DIR:
@@ -591,27 +705,39 @@ try:
ignore_dynamic_linking = False
shell_path = shared.path_from_root('src', 'shell.html')
js_libraries = []
- keep_debug = False
+ keep_llvm_debug = False
+ keep_js_debug = False
bind = False
jcache = False
+ save_bc = False
+ memory_init_file = False
+ use_preload_cache = False
+
+ if use_cxx:
+ default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline.
+ else:
+ default_cxx_std = '' # Compiling C code with .c files, don't enforce a default C++ std.
def check_bad_eq(arg):
assert '=' not in arg, 'Invalid parameter (do not use "=" with "--" options)'
absolute_warning_shown = False
+ settings_changes = []
+
for i in range(len(newargs)):
newargs[i] = newargs[i].strip() # On Windows Vista (and possibly others), excessive spaces in the command line leak into the items in this array, so trim e.g. 'foo.cpp ' -> 'foo.cpp'
if newargs[i].startswith('-O'):
- requested_level = newargs[i][2]
+ # Let -O default to -O2, which is what gcc does.
+ requested_level = newargs[i][2:] or '2'
if requested_level == 's':
- print >> sys.stderr, 'emcc: warning: -Os is ignored (use -O0, -O1, -O2)'
- else:
- try:
- opt_level = int(requested_level)
- assert 0 <= opt_level <= 3
- except:
- raise Exception('Invalid optimization level: ' + newargs[i])
+ requested_level = 2
+ settings_changes.append('INLINING_LIMIT=50')
+ try:
+ opt_level = int(requested_level)
+ assert 0 <= opt_level <= 3
+ except:
+ raise Exception('Invalid optimization level: ' + newargs[i])
newargs[i] = ''
elif newargs[i].startswith('--llvm-opts'):
check_bad_eq(newargs[i])
@@ -654,10 +780,15 @@ try:
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i] == '-g':
- keep_debug = True
+ keep_llvm_debug = True
+ keep_js_debug = True
elif newargs[i] == '--bind':
bind = True
- newargs[i] = '-std=c++11' # Force C++11 for embind code
+ newargs[i] = ''
+ if default_cxx_std:
+ default_cxx_std = '-std=c++11' # Force C++11 for embind code, but only if user has not explicitly overridden a standard.
+ elif newargs[i].startswith('-std='):
+ default_cxx_std = '' # User specified a standard to use, clear Emscripten from specifying it.
elif newargs[i].startswith('--embed-file'):
check_bad_eq(newargs[i])
embed_files.append(newargs[i+1])
@@ -680,6 +811,9 @@ try:
Compression.on = True
newargs[i] = ''
newargs[i+1] = ''
+ elif newargs[i].startswith('--use-preload-cache'):
+ use_preload_cache = True;
+ newargs[i] = ''
elif newargs[i] == '--ignore-dynamic-linking':
ignore_dynamic_linking = True
newargs[i] = ''
@@ -699,33 +833,47 @@ try:
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i] == '--remove-duplicates':
- print >> sys.stderr, 'emcc: warning: --remove-duplicates is deprecated as it is no longer needed. If you cannot link without it, file a bug with a testcase'
+ logging.warning ('--remove-duplicates is deprecated as it is no longer needed. If you cannot link without it, file a bug with a testcase')
newargs[i] = ''
elif newargs[i] == '--jcache':
jcache = True
newargs[i] = ''
elif newargs[i] == '--clear-cache':
newargs[i] = ''
- print >> sys.stderr, 'emcc: clearing cache'
+ logging.warning('clearing cache')
shared.Cache.erase()
sys.exit(0)
+ elif newargs[i] == '--save-bc':
+ check_bad_eq(newargs[i])
+ save_bc = newargs[i+1]
+ newargs[i] = ''
+ newargs[i+1] = ''
+ elif newargs[i] == '--memory-init-file':
+ check_bad_eq(newargs[i])
+ memory_init_file = int(newargs[i+1])
+ newargs[i] = ''
+ newargs[i+1] = ''
elif newargs[i].startswith(('-I/', '-L/')):
if not absolute_warning_shown:
- print >> sys.stderr, 'emcc: warning: -I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
+ logging.warning ('-I or -L of an absolute path encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)') # Of course an absolute path to a non-system-specific library or header is fine, and you can ignore this warning. The danger are system headers that are e.g. x86 specific and nonportable. The emscripten bundled headers are modified to be portable, local system ones are generally not
absolute_warning_shown = True
newargs = [ arg for arg in newargs if arg is not '' ]
+ # If user did not specify a default -std for C++ code, specify the emscripten default.
+ if default_cxx_std:
+ newargs = newargs + [default_cxx_std]
+
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 opt_level <= 0: keep_debug = True # always keep debug in -O0
+ if llvm_lto is None: llvm_lto = opt_level >= 3
+ if opt_level <= 0: keep_llvm_debug = keep_js_debug = True # always keep debug in -O0
+ if opt_level > 0: keep_llvm_debug = False # JS optimizer wipes out llvm debug info from being visible
+ if closure is None and opt_level == 3: closure = True
if DEBUG: start_time = time.time() # done after parsing arguments, which might affect debug state
if closure:
- assert os.path.exists(shared.CLOSURE_COMPILER), 'emcc: fatal: Closure compiler (%s) does not exist' % shared.CLOSURE_COMPILER
+ assert os.path.exists(shared.CLOSURE_COMPILER), logging.error('fatal: Closure compiler (%s) does not exist' % shared.CLOSURE_COMPILER)
- settings_changes = []
for i in range(len(newargs)):
if newargs[i] == '-s':
if is_minus_s_for_emcc(newargs, i):
@@ -756,6 +904,9 @@ try:
prev = newargs[i-1]
if prev in ['-MT', '-install_name', '-I', '-L']: continue # ignore this gcc-style argument
+ if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)):
+ arg = os.path.realpath(arg)
+
if not arg.startswith('-') and (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] = ''
if os.path.exists(arg):
@@ -777,9 +928,9 @@ try:
libs.append(l)
newargs[i] = ''
else:
- print >> sys.stderr, 'emcc: %s: warning: Not valid LLVM bitcode' % arg
+ logging.warning(arg + ' is not valid LLVM bitcode')
else:
- print >> sys.stderr, 'emcc: %s: error: No such file or directory' % arg
+ logging.error(arg + ': No such file or directory')
exit(1)
elif arg.startswith('-L'):
lib_dirs.append(arg[2:])
@@ -801,12 +952,12 @@ try:
# do not link in libs when just generating object code (not an 'executable', i.e. JS, or a library)
if ('.' + final_suffix) in BITCODE_SUFFIXES and len(libs) > 0:
- print >> sys.stderr, 'emcc: warning: not linking against libraries since only compiling to bitcode'
+ logging.warning('not linking against libraries since only compiling to bitcode')
libs = []
# Find library files
for lib in libs:
- if DEBUG: print >> sys.stderr, 'emcc: looking for library "%s"' % lib
+ logging.debug('looking for library "%s"' % lib)
found = False
for prefix in LIB_PREFIXES:
for suff in STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES:
@@ -814,7 +965,7 @@ try:
for lib_dir in lib_dirs:
path = os.path.join(lib_dir, name)
if os.path.exists(path):
- if DEBUG: print >> sys.stderr, 'emcc: found library "%s" at %s' % (lib, path)
+ logging.debug('found library "%s" at %s' % (lib, path))
input_files.append(path)
found = True
break
@@ -825,8 +976,7 @@ try:
input_files = filter(lambda input_file: not input_file.endswith(DYNAMICLIB_SUFFIXES), input_files)
if len(input_files) == 0:
- print >> sys.stderr, 'emcc: no input files'
- print >> sys.stderr, 'note that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + STATICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)
+ logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + STATICLIB_SUFFIXES + ASSEMBLY_SUFFIXES))
exit(0)
newargs += CC_ADDITIONAL_ARGS
@@ -843,52 +993,77 @@ try:
# Apply -s settings in newargs here (after optimization levels, so they can override them)
for change in settings_changes:
key, value = change.split('=')
+ if value[0] == '@':
+ value = '"@' + os.path.abspath(value[1:]) + '"'
+ value = value.replace('\\\\', '/').replace('\\', '/') # Convert backslash paths to forward slashes on Windows as well, since the JS compiler otherwise needs the backslashes escaped (alternative is to escape all input paths passing to JS, which feels clumsier to read)
exec('shared.Settings.' + key + ' = ' + value)
# Apply effects from settings
if shared.Settings.ASM_JS:
- if closure:
- print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation'
- closure = False
- if shared.Settings.CORRECT_SIGNS != 1:
- print >> sys.stderr, 'emcc: warning: setting CORRECT_SIGNS to 1 for asm.js code generation'
+ assert opt_level >= 1, 'asm.js requires -O1 or above'
+
+ if bind:
+ shared.Settings.RESERVED_FUNCTION_POINTERS = max(shared.Settings.RESERVED_FUNCTION_POINTERS, 10)
+ if shared.Settings.CORRECT_SIGNS != 1:
+ logging.warning('setting CORRECT_SIGNS to 1 for asm.js code generation')
shared.Settings.CORRECT_SIGNS = 1
- if shared.Settings.CORRECT_OVERFLOWS != 1:
- print >> sys.stderr, 'emcc: warning: setting CORRECT_OVERFLOWS to 1 for asm.js code generation'
+ if shared.Settings.CORRECT_OVERFLOWS != 1:
+ logging.warning('setting CORRECT_OVERFLOWS to 1 for asm.js code generation')
shared.Settings.CORRECT_OVERFLOWS = 1
+ assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode'
+
+ if shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS:
+ logging.warning('ALIASING_FUNCTION_POINTERS is on, function pointer comparisons may be invalid across types')
if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2:
- keep_debug = True # must keep debug info to do line-by-line operations
+ keep_llvm_debug = True # must keep debug info to do line-by-line operations
+
+ if (keep_llvm_debug or keep_js_debug) and closure:
+ logging.warning('disabling closure because debug info was requested')
+ closure = False
if minify_whitespace is None:
- minify_whitespace = closure # if closure is run, minify whitespace
+ minify_whitespace = opt_level >= 2 and not keep_js_debug
+
+ assert shared.LLVM_TARGET in shared.COMPILER_OPTS
+ if shared.LLVM_TARGET == 'i386-pc-linux-gnu':
+ shared.Settings.TARGET_X86 = 1
+ shared.Settings.TARGET_LE32 = 0
+ assert 'le32-unknown-nacl' not in shared.COMPILER_OPTS
+ elif shared.LLVM_TARGET == 'le32-unknown-nacl':
+ shared.Settings.TARGET_LE32 = 1
+ shared.Settings.TARGET_X86 = 0
+ assert 'i386-pc-linux-gnu' not in shared.COMPILER_OPTS
+ else:
+ raise Exception('unknown llvm target: ' + str(shared.LLVM_TARGET))
## Compile source code to bitcode
- if DEBUG: print >> sys.stderr, 'emcc: compiling to bitcode'
+ logging.debug('compiling to bitcode')
temp_files = []
# First, generate LLVM bitcode. For each input file, we get base.o with bitcode
for input_file in input_files:
if input_file.endswith(SOURCE_SUFFIXES):
- if DEBUG: print >> sys.stderr, 'emcc: compiling source file: ', input_file
+ logging.debug('compiling source file: ' + input_file)
+ input_file = shared.Building.preprocess(input_file, in_temp(uniquename(input_file)))
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)
+ logging.debug("running:" + call + ' '.join(args))
execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that)
if not os.path.exists(output_file):
- print >> sys.stderr, 'emcc: compiler frontend failed to generate LLVM bitcode, halting'
+ logging.error('compiler frontend failed to generate LLVM bitcode, halting')
sys.exit(1)
else: # bitcode
if input_file.endswith(BITCODE_SUFFIXES):
- if DEBUG: print >> sys.stderr, 'emcc: copying bitcode file: ', input_file
+ logging.debug('copying bitcode file: ' + input_file)
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
+ logging.debug('copying library file: ' + input_file)
temp_file = in_temp(uniquename(input_file))
shutil.copyfile(input_file, temp_file)
temp_files.append(temp_file)
@@ -896,7 +1071,7 @@ try:
if not LEAVE_INPUTS_RAW:
# 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
+ logging.debug('assembling assembly file: ' + input_file)
temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o')
shared.Building.llvm_as(input_file, temp_file)
temp_files.append(temp_file)
@@ -906,7 +1081,15 @@ try:
# If we were just asked to generate bitcode, stop there
if final_suffix not in JS_CONTAINING_SUFFIXES:
if llvm_opts > 0:
- print >> sys.stderr, 'emcc: warning: -Ox flags ignored, since not generating JavaScript'
+ if not os.environ.get('EMCC_OPTIMIZE_NORMALLY'):
+ logging.warning('-Ox flags ignored, since not generating JavaScript')
+ else:
+ for input_file in input_files:
+ if input_file.endswith(SOURCE_SUFFIXES):
+ logging.debug('optimizing %s with -O%d since EMCC_OPTIMIZE_NORMALLY defined' % (input_file, llvm_opts))
+ shared.Building.llvm_opt(in_temp(unsuffixed(uniquename(input_file)) + '.o'), llvm_opts)
+ else:
+ logging.debug('not optimizing %s despite EMCC_OPTIMIZE_NORMALLY since not source code' % (input_file))
if not specified_target:
for input_file in input_files:
shutil.move(in_temp(unsuffixed(uniquename(input_file)) + '.o'), unsuffixed_basename(input_file) + '.' + final_suffix)
@@ -917,13 +1100,13 @@ try:
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
- if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(temp_files), specified_target
+ logging.debug('link: ' + str(temp_files) + specified_target)
shared.Building.link(temp_files, specified_target)
exit(0)
## Continue on to create JavaScript
- if DEBUG: print >> sys.stderr, 'emcc: will gener