diff options
Diffstat (limited to 'emcc')
-rwxr-xr-x | emcc | 335 |
1 files changed, 197 insertions, 138 deletions
@@ -47,10 +47,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, shlex, time, re, logging, json -from subprocess import PIPE, STDOUT +import os, sys, shutil, tempfile, subprocess, shlex, time, re, logging +from subprocess import PIPE from tools import shared, jsrun, system_libs -from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS +from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS, safe_move from tools.response_file import read_response_file # endings = dot + a suffix, safe to test by filename.endswith(endings) @@ -95,7 +95,7 @@ AUTODEBUG = os.environ.get('EMCC_AUTODEBUG') # If set to 1, we will run the auto # 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 -logging.debug('invocation: ' + ' '.join(sys.argv) + (' + ' + EMCC_CFLAGS if EMCC_CFLAGS else '')) +if DEBUG: logging.warning('invocation: ' + ' '.join(sys.argv) + (' + ' + EMCC_CFLAGS if EMCC_CFLAGS else '') + ' (in ' + os.getcwd() + ')') if EMCC_CFLAGS: sys.argv.append(EMCC_CFLAGS) if DEBUG and LEAVE_INPUTS_RAW: logging.warning('leaving inputs raw') @@ -161,9 +161,17 @@ Options that are modified or new in %s include: time in return for the smallest and fastest output. - -O3 As -O2, plus additional optimizations that can + -Os Like -O2 with extra optimizations for size. + + -Oz Like -Os but reduces code size further. + + -O3 Like -O2 plus additional JS optimizations that can take a significant amount of compilation time and/or - are relatively new. + are relatively new. Note that differs from -O2 only + during the bitcode to JS (final link + JS generation) + stage, as it is JS-specific, so you can run -Os + on your source files for example, and -O3 during + JS generation if you want. For tips on optimizing your code, see https://github.com/kripken/emscripten/wiki/Optimizing-Code @@ -227,6 +235,21 @@ Options that are modified or new in %s include: slower because JS optimization will be limited to 1 core. (default in -O0) + -profiling Use reasonable defaults when emitting JS to + make the build useful for profiling. This + sets -g2 (preserve function names) and may + also enable optimizations that affect + performance and otherwise might not be + performed in -g2. + + --emit-symbol-map Save a map file between the minified + global names and the original function names. + This allows you to reconstruct meaningful + stack traces, for example. (This is only + relevant when minifying global names, which + happens in -O2 and above, and when no -g + option to prevent minification was specified.) + --typed-arrays <mode> 0: No typed arrays 1: Parallel typed arrays 2: Shared (C-like) typed arrays (default) @@ -330,7 +353,7 @@ Options that are modified or new in %s include: For more docs on the options --preload-file accepts, see https://github.com/kripken/emscripten/wiki/Filesystem-Guide - --exclude-file <name> Files and directories to be excluded from + --exclude-file <name> Files and directories to be excluded from --embed-file and --preload-file wildcard is supported @@ -423,60 +446,17 @@ Options that are modified or new in %s include: -v Turns on verbose output. This will pass -v to Clang, and also enable EMCC_DEBUG - to details emcc's operations - - --jcache Use a JavaScript cache. This is disabled by - default. When enabled, emcc will store the - results of compilation in a cache and check - the cache when compiling later, something - like what ccache does. This allows incremental - builds - where you are compiling a large - program but only modified a small part of it - - to be much faster (at the cost of more disk - IO for cache accesses). Note that you need - to enable --jcache for both loading and saving - of data, so you must enable it on a full build - 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). + to details emcc's operations. + + It will also run emscripten's internal sanity + checks, checking that things like the LLVM directory + path looks correct, etc. This works with or + without other arguments, so it can be useful to run + + emcc -v + + if you see odd errors, as it can help diagnose + things. --clear-cache Manually clears the cache of compiled emscripten system libraries (libc++, @@ -505,7 +485,16 @@ Options that are modified or new in %s include: 1: Emit a separate memory initialization file in binary format. This is more efficient than storing it as text inside JavaScript, but does - mean you have another file to publish. + mean you have another file to publish. The + binary file will also be loaded asynchronously, + which means main() will not be called until + the file is downloaded and applied; you cannot + call any C functions until it arrives. (Call + yourself from main() to know when all async + stuff has happened and it is safe to call + library functions, as main() will only be + called at that time. You can also call + addOnPreMain from a preRun.) -Wno-warn-absolute-paths If not specified, the compiler will warn about any uses of absolute paths in -I and -L command line @@ -530,9 +519,11 @@ Options that are modified or new in %s include: --default-obj-ext .ext Specifies the file suffix to generate if the location of a directory name is passed to -o directive, e.g. emcc -c a.c -o dir/ - will by default generate an output name 'dir/a.o', + will by default generate an output name 'dir/a.o', but this cmdline param can be passed to generate a - file with a custom suffix 'dir/a.ext'. + file with a custom suffix 'dir/a.ext'. + --valid_abspath path Whitelist an absolute path to prevent warnings about + absolute include paths. The target file, if specified (-o <target>), defines what will be generated: @@ -573,17 +564,19 @@ elif sys.argv[1] == '--version': finally: os.chdir(here) print '''emcc (Emscripten GCC-like replacement) %s (%s) -Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt) +Copyright (C) 2014 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) + 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 ) %s' % shared.EMSCRIPTEN_VERSION - exit(subprocess.call([shared.CLANG, '-v'])) + code = subprocess.call([shared.CLANG, '-v']) + shared.check_sanity(force=True) + exit(code) -def is_minus_s_for_emcc(newargs,i): +def is_minus_s_for_emcc(newargs, i): assert newargs[i] == '-s' 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 @@ -644,7 +637,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: idx += 1 cmd = [compiler] + list(filter_emscripten_options(sys.argv[1:])) - if not use_js: cmd += shared.EMSDK_OPTS + ['-DEMSCRIPTEN'] + if not use_js: cmd += shared.EMSDK_OPTS + ['-D__EMSCRIPTEN__', '-DEMSCRIPTEN'] if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists logging.debug('just configuring: ' + ' '.join(cmd)) @@ -766,6 +759,15 @@ else: def in_temp(name): return os.path.join(temp_dir, os.path.basename(name)) +def in_directory(root, child): + # make both path absolute + root = os.path.realpath(root) + child = os.path.realpath(child) + + # return true, if the common prefix of both is equal to directory + # e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b + return os.path.commonprefix([root, child]) == root + # Parses the essential suffix of a filename, discarding Unix-style version numbers in the name. For example for 'libz.so.1.2.8' returns '.so' def filename_type_suffix(filename): for i in reversed(filename.split('.')[1:]): @@ -782,7 +784,7 @@ log_time_last = time.time() def log_time(name): global log_time_last now = time.time() - logging.debug('emcc step "%s" took %.2f seconds' % (name, now - log_time_last)) + logging.debug('emcc step "%s" took %.2f seconds', name, now - log_time_last) log_time_last = now try: @@ -794,6 +796,8 @@ try: opt_level = 0 debug_level = 0 + profiling = False + emit_symbol_map = False js_opts = None llvm_opts = None llvm_lto = None @@ -818,6 +822,14 @@ try: no_heap_copy = False proxy_to_worker = False default_object_extension = '.o' + valid_abspaths = [] + + def is_valid_abspath(path_name): + for valid_abspath in valid_abspaths: + if in_directory(valid_abspath, path_name): + return True + return 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. @@ -851,14 +863,19 @@ try: # Let -O default to -O2, which is what gcc does. requested_level = newargs[i][2:] or '2' if requested_level == 's': + llvm_opts = ['-Os'] requested_level = 2 settings_changes.append('INLINING_LIMIT=50') + elif requested_level == 'z': + llvm_opts = ['-Oz'] + requested_level = 2 + settings_changes.append('INLINING_LIMIT=25') opt_level = validate_arg_level(requested_level, 3, 'Invalid optimization level: ' + newargs[i]) # We leave the -O option in place so that the clang front-end runs in that # optimization mode, but we disable the actual optimization passes, as we'll # run them seperately. newargs.append('-mllvm') - newargs.append('-disable-llvm-optzns'); + newargs.append('-disable-llvm-optzns') elif newargs[i].startswith('--js-opts'): check_bad_eq(newargs[i]) js_opts = eval(newargs[i+1]) @@ -909,6 +926,13 @@ try: requested_level = newargs[i][2:] or '3' debug_level = validate_arg_level(requested_level, 4, 'Invalid debug level: ' + newargs[i]) newargs[i] = '-g' # we'll need this to get LLVM debug info + elif newargs[i] == '-profiling': + debug_level = 2 + profiling = True + newargs[i] = '' + elif newargs[i] == '--emit-symbol-map': + emit_symbol_map = True + newargs[i] = '' elif newargs[i] == '--bind': bind = True newargs[i] = '' @@ -969,8 +993,9 @@ try: # swap in debug logging DEBUG = 1 shared.set_logging() - logging.debug('invocation: ' + ' '.join(sys.argv)) + logging.debug('-v invocation: ' + ' '.join(sys.argv)) shared.apply_configuration() # reset config to pick up change + shared.check_sanity(force=True) newargs[i] = '' elif newargs[i].startswith('--shell-file'): check_bad_eq(newargs[i]) @@ -983,15 +1008,17 @@ try: newargs[i] = '' newargs[i+1] = '' elif newargs[i] == '--remove-duplicates': - logging.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': + logging.warning('jcache is deprecated') jcache = True newargs[i] = '' elif newargs[i] == '--clear-cache': newargs[i] = '' logging.warning('clearing cache') shared.Cache.erase() + shared.check_sanity(force=True) # this is a good time for a sanity check sys.exit(0) elif newargs[i] == '--save-bc': check_bad_eq(newargs[i]) @@ -1006,10 +1033,14 @@ try: elif newargs[i] == '--proxy-to-worker': proxy_to_worker = True newargs[i] = '' + elif newargs[i] == '--valid-abspath': + valid_abspaths.append(newargs[i+1]) + newargs[i] = '' + newargs[i+1] = '' elif newargs[i].startswith(('-I', '-L')): path_name = newargs[i][2:] - if not absolute_warning_shown and os.path.isabs(path_name): - logging.warning ('-I or -L of an absolute path "' + newargs[i] + '" 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). Pass \'-Wno-warn-absolute-paths\' to emcc to hide this warning.') # 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 + if not absolute_warning_shown and os.path.isabs(path_name) and not is_valid_abspath(path_name): + logging.warning('-I or -L of an absolute path "' + newargs[i] + '" 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). Pass \'-Wno-warn-absolute-paths\' to emcc to hide this warning.') # 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 elif newargs[i] == '--emrun': emrun = True @@ -1025,7 +1056,7 @@ try: default_object_extension = '.' + default_object_extension newargs[i+1] = '' - newargs = [ arg for arg in newargs if arg is not '' ] + 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: @@ -1050,9 +1081,6 @@ try: if DEBUG: start_time = time.time() # done after parsing arguments, which might affect debug state - if closure: - assert os.path.exists(shared.CLOSURE_COMPILER), logging.error('fatal: Closure compiler (%s) does not exist' % shared.CLOSURE_COMPILER) - for i in range(len(newargs)): if newargs[i] == '-s': if is_minus_s_for_emcc(newargs, i): @@ -1063,7 +1091,7 @@ try: settings_changes.append('USE_TYPED_ARRAYS=' + newargs[i+1]) newargs[i] = '' newargs[i+1] = '' - newargs = [ arg for arg in newargs if arg is not '' ] + newargs = [arg for arg in newargs if arg is not ''] if split_js_file: settings_changes.append("PRINT_SPLIT_FILE_MARKER=1") @@ -1084,12 +1112,12 @@ try: prev = newargs[i-1] if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument - if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)): + if os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS): arg = os.path.realpath(arg) if not arg.startswith('-'): if not os.path.exists(arg): - logging.error('%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)' % (arg, arg)) + logging.error('%s: No such file or directory ("%s" was expected to be an input file, based on the commandline arguments provided)', arg, arg) exit(1) arg_ending = filename_type_ending(arg) @@ -1134,7 +1162,7 @@ try: original_input_files = input_files[:] - newargs = [ arg for arg in newargs if arg is not '' ] + newargs = [arg for arg in newargs if arg is not ''] # -c means do not link in gcc, and for us, the parallel is to not go all the way to JS, but stop at bitcode has_dash_c = '-c' in newargs @@ -1142,10 +1170,11 @@ try: assert has_source_inputs or has_header_inputs, 'Must have source code or header inputs to use -c' target = target_basename + '.o' final_suffix = 'o' + final_ending = ('.' + final_suffix) if len(final_suffix) > 0 else '' # Find library files for lib in libs: - logging.debug('looking for library "%s"' % lib) + logging.debug('looking for library "%s"', lib) found = False for prefix in LIB_PREFIXES: for suff in STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS: @@ -1153,24 +1182,24 @@ try: for lib_dir in lib_dirs: path = os.path.join(lib_dir, name) if os.path.exists(path): - logging.debug('found library "%s" at %s' % (lib, path)) + logging.debug('found library "%s" at %s', lib, path) input_files.append(path) found = True break if found: break if found: break - if not found: logging.warning('emcc: cannot find library "%s"' % lib) + if not found: logging.warning('emcc: cannot find library "%s"', lib) # If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so # ignore dynamic linking, since multiple dynamic linkings can interfere with each other if not filename_type_suffix(target) in JS_CONTAINING_SUFFIXES or ignore_dynamic_linking: def check(input_file): if filename_type_ending(input_file) in DYNAMICLIB_ENDINGS: - if not ignore_dynamic_linking: logging.warning('ignoring dynamic library %s because not compiling to JS or HTML, remember to link it when compiling to JS or HTML at the end' % os.path.basename(input_file)) + if not ignore_dynamic_linking: logging.warning('ignoring dynamic library %s because not compiling to JS or HTML, remember to link it when compiling to JS or HTML at the end', os.path.basename(input_file)) return False else: return True - input_files = filter(lambda input_file: check(input_file), input_files) + input_files = [input_file for input_file in input_files if check(input_file)] if len(input_files) == 0: 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_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)) @@ -1200,29 +1229,41 @@ try: logging.warning('disabling asm.js since embind is not ready for it yet') shared.Settings.ASM_JS = 0 - fastcomp = os.environ.get('EMCC_FAST_COMPILER') == '1' + fastcomp = os.environ.get('EMCC_FAST_COMPILER') != '0' if fastcomp: shared.Settings.ASM_JS = 1 if opt_level > 0 else 2 - assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' - assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet' - assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' - assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp' - assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp' - assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp' - assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp' - assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' - assert shared.Settings.TARGET_LE32 == 1, 'fastcomp requires le32' - assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2' - assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' - assert not bind, 'embind not supported in fastcomp yet' - assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet' - assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' + try: + assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' + assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp - use SAFE_HEAP instead' + assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' + assert shared.Settings.ASM_HEAP_LOG == 0, 'asm heap log not supported in fastcomp' + assert shared.Settings.LABEL_DEBUG == 0, 'label debug not supported in fastcomp' + assert shared.Settings.EXECUTION_TIMEOUT == -1, 'execution timeout not supported in fastcomp' + assert shared.Settings.NAMED_GLOBALS == 0, 'named globals not supported in fastcomp' + assert shared.Settings.PGO == 0, 'pgo not supported in fastcomp' + assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten' + assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2' + assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' + assert not bind, 'embind not supported in fastcomp yet' + assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet' + assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' + assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp' + assert not shared.Settings.CORRUPTION_CHECK, 'CORRUPTION_CHECK is not supported in asm.js mode, which is what fastcomp can emit (you can use non-asm.js mode in non-fastcomp)' + except Exception, e: + logging.error('Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend') + raise e + if jcache: - logging.warning('jcache is not supported in fastcomp (you should not need it anyhow), disabling') + logging.warning('jcache is deprecated and not supported in fastcomp (you should not need it anyhow), disabling') jcache = False - fastcomp_opts = ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] + pre_fastcomp_opts = [] + fastcomp_opts = [] + if shared.Settings.NO_EXIT_RUNTIME: + pre_fastcomp_opts += ['-emscripten-no-exit-runtime'] + if not llvm_lto: fastcomp_opts += ['-globalopt', '-globaldce'] + fastcomp_opts += ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'] if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1: fastcomp_opts += ['-enable-emscripten-cxx-exceptions'] if len(shared.Settings.EXCEPTION_CATCHING_WHITELIST) > 0: @@ -1256,13 +1297,19 @@ try: logging.warning('disabling closure because debug info was requested') closure = False + if closure: + shared.Settings.CLOSURE_COMPILER = 1 + assert os.path.exists(shared.CLOSURE_COMPILER), logging.error('fatal: Closure compiler (%s) does not exist', shared.CLOSURE_COMPILER) + 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_ASMJS_UNKNOWN_EMSCRIPTEN = 0 + assert 'asmjs-unknown-emscripten' not in shared.COMPILER_OPTS + elif shared.LLVM_TARGET == 'asmjs-unknown-emscripten' or \ + shared.LLVM_TARGET == 'le32-unknown-nacl': + # For temporary compatibility, treat 'le32-unknown-nacl' as 'asmjs-unknown-emscripten'. + shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN = 1 shared.Settings.TARGET_X86 = 0 assert 'i386-pc-linux-gnu' not in shared.COMPILER_OPTS else: @@ -1284,7 +1331,7 @@ try: shared.Settings.LINKABLE = 1 # TODO: add FORCE_DCE option for the brave people that do want to dce here and in side modules debug_level = max(debug_level, 2) - if shared.Settings.ASSERTIONS and shared.Settings.ALIASING_FUNCTION_POINTERS: + if not fastcomp and 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.STB_IMAGE and final_suffix in JS_CONTAINING_SUFFIXES: @@ -1329,13 +1376,25 @@ try: execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) sys.exit(1) + def get_bitcode_file(input_file): + if final_suffix not in JS_CONTAINING_SUFFIXES: + # no need for a temp file, just emit to the right place + if len(input_files) == 1: + # can just emit directly to the target + if specified_target: + if specified_target.endswith('/') or specified_target.endswith('\\') or os.path.isdir(specified_target): + return os.path.join(specified_target, os.path.basename(unsuffixed(input_file))) + default_object_extension + return specified_target + return unsuffixed(input_file) + final_ending + return unsuffixed(input_file) + default_object_extension + return in_temp(unsuffixed(uniquename(input_file)) + default_object_extension) + # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: file_ending = filename_type_ending(input_file) if file_ending.endswith(SOURCE_ENDINGS): 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') + output_file = get_bitcode_file(input_file) temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] if file_ending.endswith(CXX_ENDINGS): @@ -1358,8 +1417,6 @@ try: temp_files.append(temp_file) elif file_ending.endswith(ASSEMBLY_ENDINGS): 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 logging.debug('assembling assembly file: ' + input_file) temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o') shared.Building.llvm_as(input_file, temp_file) @@ -1379,33 +1436,25 @@ try: file_ending = filename_type_ending(input_file) if file_ending.endswith(SOURCE_ENDINGS): temp_file = temp_files[i] - logging.debug('optimizing %s with -O%s' % (input_file, llvm_opts)) + logging.debug('optimizing %s', input_file) + #if DEBUG: shutil.copyfile(temp_file, os.path.join(TEMP_DIR, 'to_opt.bc') # useful when LLVM opt aborts shared.Building.llvm_opt(temp_file, llvm_opts) # If we were just asked to generate bitcode, stop there if final_suffix not in JS_CONTAINING_SUFFIXES: 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) + safe_move(get_bitcode_file(input_file), unsuffixed_basename(input_file) + final_ending) else: if len(input_files) == 1: - temp_output_base = in_temp(unsuffixed(uniquename(input_files[0]))) - if specified_target.endswith('/') or specified_target.endswith('\\') or os.path.isdir(specified_target): # User passed '-o <directory' as the location to output to. - obj_output_name = os.path.join(specified_target, os.path.splitext(os.path.basename(input_file))[0] + default_object_extension) - logging.debug('User specified -o <directoryname> as the location of the output. Generating output file ' + obj_output_name) - try: - shutil.move(temp_output_base + '.o', obj_output_name) - except IOError, e: - logging.error('Could not write to output file ' + obj_output_name + '. Perhaps the output directory does not exist?') - exit(1) - else: # User passed '-o <filename>' as the location to output to. - shutil.move(temp_output_base + '.o', specified_target) + safe_move(temp_files[0], specified_target if specified_target else unsuffixed_basename(input_file) + final_ending) + temp_output_base = unsuffixed(temp_files[0]) if os.path.exists(temp_output_base + '.d'): # There was a .d file generated, from -MD or -MMD and friends, save a copy of it to where the output resides, # adjusting the target name away from the temporary file name to the specified target. # It will be deleted with the rest of the temporary directory. deps = open(temp_output_base + '.d').read() - deps = deps.replace(temp_output_base + '.o', specified_target) + deps = deps.replace(temp_output_base + default_object_extension, specified_target) with open(os.path.join(os.path.dirname(specified_target), os.path.basename(unsuffixed(input_files[0]) + '.d')), "w") as out_dep: out_dep.write(deps) else: @@ -1414,9 +1463,10 @@ try: # we have multiple files: Link them logging.debug('link: ' + str(temp_files) + specified_target) shared.Building.link(temp_files, specified_target) + logging.debug('stopping at bitcode') exit(0) - log_time('bitcodeize inputs') + log_time('process inputs') ## Continue on to create JavaScript @@ -1436,7 +1486,7 @@ try: (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link logging.debug('linking: ' + str(linker_inputs)) - shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0) + shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents=len([temp for temp in temp_files if not temp.endswith(STATICLIB_ENDINGS)]) == 0) final = in_temp(target_basename + '.bc') else: if not LEAVE_INPUTS_RAW: @@ -1449,7 +1499,7 @@ try: log_time('link') if DEBUG: - logging.debug('saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR) + logging.debug('saving intermediate processing steps to %s', shared.EMSCRIPTEN_TEMP_DIR) intermediate_counter = 0 def save_intermediate(name=None, suffix='js'): @@ -1486,7 +1536,7 @@ try: else: if fastcomp and not save_bc: # Simplify LLVM bitcode for fastcomp - link_opts += fastcomp_opts + link_opts = pre_fastcomp_opts + link_opts + fastcomp_opts shared.Building.llvm_opt(final, link_opts) if DEBUG: save_intermediate('linktime', 'bc') if save_bc: @@ -1498,7 +1548,7 @@ try: # Prepare .ll for Emscripten if not LEAVE_INPUTS_RAW: - if save_bc: + if save_bc and not fastcomp: final = shared.Building.llvm_dis(final, final + '.ll') else: assert len(input_files) == 1 @@ -1573,7 +1623,7 @@ try: shutil.copyfile(final, final + '.tr.js') final += '.tr.js' posix = True if not shared.WINDOWS else False - logging.debug('applying transform: %s' % js_transform) + logging.debug('applying transform: %s', js_transform) subprocess.check_call(shlex.split(js_transform, posix=posix) + [os.path.abspath(final)]) if DEBUG: save_intermediate('transformed') @@ -1603,7 +1653,7 @@ try: if DEBUG: if os.path.exists(memfile): save_intermediate('meminit') - logging.debug('wrote memory initialization to %s' % memfile) + logging.debug('wrote memory initialization to %s', memfile) else: logging.debug('did not see memory initialization') elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE: @@ -1677,6 +1727,10 @@ try: js_optimizer_queue += ['simplifyExpressions'] + # simplify ifs if it is ok to make the code somewhat unreadable, and unless outlining (simplified ifs + # with commaified code breaks late aggressive variable elimination) + if shared.Settings.SIMPLIFY_IFS and (debug_level == 0 or profiling) and shared.Settings.OUTLINING_LIMIT == 0: js_optimizer_queue += ['simplifyIfs'] + if opt_level >= 3 and shared.Settings.PRECISE_F32: js_optimizer_queue += ['optimizeFrounds'] if closure and not shared.Settings.ASM_JS: @@ -1702,10 +1756,12 @@ try: js_optimizer_queue += ['registerize'] if opt_level >= 2: - if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames'] + if debug_level < 2 and shared.Settings.ASM_JS: + js_optimizer_queue += ['minifyNames'] + if emit_symbol_map: js_optimizer_queue += ['symbolMap='+target+'.symbols'] if debug_level == 0: js_optimizer_queue += ['minifyWhitespace'] - if closure and shared.Settings.ASM_JS: + if closure and shared.Settings.ASM_JS: js_optimizer_queue += ['closure'] if not shared.Settings.SIDE_MODULE: js_optimizer_queue += ['last'] # side modules are not finalized until after relocation @@ -1885,7 +1941,7 @@ try { log_time('final emitting') - if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time)) + if DEBUG: logging.debug('total time: %.2f seconds', (time.time() - start_time)) finally: if not TEMP_DIR: @@ -1896,3 +1952,6 @@ finally: else: logging.info('emcc saved files are in:' + temp_dir) +#//eliminate a = a in js opt. will kill STACKTOP = STACKTOP in funcs that do not use the C stack! add test for no STACKTOP or sp in such a func +#// minify if into ?: ? + |