diff options
Diffstat (limited to 'emcc')
-rwxr-xr-x | emcc | 899 |
1 files changed, 329 insertions, 570 deletions
@@ -48,19 +48,22 @@ emcc can be influenced by a few environment variables: ''' import os, sys, shutil, tempfile, subprocess, shlex, time, re, logging -from subprocess import PIPE, STDOUT -from tools import shared, jsrun +from subprocess import PIPE +from tools import shared, jsrun, system_libs from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS from tools.response_file import read_response_file # endings = dot + a suffix, safe to test by filename.endswith(endings) C_ENDINGS = ('.c', '.C') CXX_ENDINGS = ('.cpp', '.cxx', '.cc', '.CPP', '.CXX', '.CC') -SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + ('.m', '.mm') +OBJC_ENDINGS = ('.m',) +OBJCXX_ENDINGS = ('.mm',) +SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + OBJC_ENDINGS + OBJCXX_ENDINGS BITCODE_ENDINGS = ('.bc', '.o', '.obj') DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll') STATICLIB_ENDINGS = ('.a',) ASSEMBLY_ENDINGS = ('.ll',) +HEADER_ENDINGS = ('.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH') LIB_PREFIXES = ('', 'lib') @@ -146,7 +149,7 @@ Options that are modified or new in %s include: This is the recommended setting when you want a reasonably optimized build that is generated as - quickly as possible (it is much faster than -O2). + quickly as possible (it builds much faster than -O2). (Note: for details on the affects of different opt levels, see apply_opt_level() in @@ -158,20 +161,20 @@ Options that are modified or new in %s include: time in return for the smallest and fastest output. - -O3 As -O2, plus dangerous optimizations that may - break the generated code! This adds + -Os Like -O2 with extra optimizations for size. - -s FORCE_ALIGNED_MEMORY=1 - -s DOUBLE_MODE=0 - -s PRECISE_I64_MATH=0 - --closure 1 - --llvm-lto 3 + -Oz Like -Os but reduces code size further. - 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. + -O3 Like -O2 plus additional JS optimizations that can + take a significant amount of compilation time and/or + 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 -s OPTION=VALUE JavaScript code generation option passed into the emscripten compiler. For the @@ -267,8 +270,7 @@ Options that are modified or new in %s include: 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. + may require some changes to the code. In asm.js mode, closure will only be used on the 'shell' code around the compiled code (the @@ -282,21 +284,6 @@ Options that are modified or new in %s include: Note: Closure is only run if js opts are being done (-O2 or above, or --js-opts 1). - --js-transform <cmd> <cmd> will be called on the generated code - before it is optimized. This lets you modify - the JavaScript, for example adding some code - or removing some code, in a way that those - modifications will be optimized together with - the generated code properly. <cmd> will be - called with the filename of the generated - code as a parameter; to modify the code, you - can read the original data and then append to - it or overwrite it with the modified data. - <cmd> is interpreted as a space-separated - list of arguments, for example, <cmd> of - "python processor.py" will cause a python - script to be run. - --pre-js <file> A file whose contents are added before the generated code. This is done *before* optimization, so it will be minified @@ -319,6 +306,13 @@ Options that are modified or new in %s include: If a directory is passed here, its entire contents will be embedded. + Note: Embedding files is much less + efficient than preloading them. You + should only use it for small amounts + of small files. Instead, use + --preload-file which emits efficient + binary data. + --preload-file <name> A file to preload before running the compiled code asynchronously. Otherwise similar to --embed-file, except that this @@ -344,10 +338,20 @@ 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 + --shell-file <path> The path name to a skeleton HTML file used + when generating HTML output. The shell file + used needs to have this token inside it: + {{{ SCRIPT }}} + (see src/shell.html and + src/shell_minimal.html for examples) + Note that this argument is ignored if a + target other than HTML is specified using + the -o option. + --compression <codec> **THIS OPTION IS DEPRECATED** Compress both the compiled code and embedded/ @@ -371,6 +375,21 @@ Options that are modified or new in %s include: --minify 0 Identical to -g1 + --js-transform <cmd> <cmd> will be called on the generated code + before it is optimized. This lets you modify + the JavaScript, for example adding some code + or removing some code, in a way that those + modifications will be optimized together with + the generated code properly. <cmd> will be + called with the filename of the generated + code as a parameter; to modify the code, you + can read the original data and then append to + it or overwrite it with the modified data. + <cmd> is interpreted as a space-separated + list of arguments, for example, <cmd> of + "python processor.py" will cause a python + script to be run. + --split <size> Splits the resulting javascript file into pieces to ease debugging. This option only works if Javascript is generated (target -o <name>.js). @@ -392,6 +411,9 @@ Options that are modified or new in %s include: The main file resides in the base directory and has the suffix ".js". + Note: this option is deprecated (modern JS debuggers + should work ok even on large files) + --bind Compiles the source code using the "embind" bindings approach, which connects C/C++ and JS. @@ -404,74 +426,22 @@ Options that are modified or new in %s include: errors. However, you will need to manually link to the shared libraries later on yourself. - --shell-file <path> The path name to a skeleton HTML file used - when generating HTML output. The shell file - used needs to have this token inside it: - {{{ SCRIPT }}} - (see src/shell.html for an example) - Note that this argument is ignored if a - 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 - - --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++, @@ -494,10 +464,13 @@ Options that are modified or new in %s include: 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) + --memory-init-file <on> 0: Do not emit a separate memory initialization + file, keep the static initialization inside + the generated JavaScript as text (default) + 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. -Wno-warn-absolute-paths If not specified, the compiler will warn about any uses of absolute paths in -I and -L command line @@ -522,9 +495,9 @@ 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'. The target file, if specified (-o <target>), defines what will be generated: @@ -565,17 +538,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 @@ -636,7 +611,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)) @@ -705,15 +680,12 @@ if len(sys.argv) == 1 or sys.argv[1] in ['x', 't']: sys.exit(0) use_cxx = True -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','.m')): + if arg.endswith(C_ENDINGS + OBJC_ENDINGS): use_cxx = False - 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) @@ -747,15 +719,6 @@ if '.' in target: else: final_suffix = '' -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) - logging.debug('Just copy:' + sys.argv[-1] + target) - shutil.copy(sys.argv[-1], target) - else: - logging.debug('No-op.') - exit(0) - if TEMP_DIR: temp_dir = TEMP_DIR if os.path.exists(temp_dir): @@ -781,6 +744,14 @@ def filename_type_ending(filename): suffix = filename_type_suffix(filename) return '' if not suffix else ('.' + suffix) +# Log out times for emcc stages +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) + log_time_last = now + try: call = CXX if use_cxx else CC @@ -847,10 +818,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]) - 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') elif newargs[i].startswith('--js-opts'): check_bad_eq(newargs[i]) js_opts = eval(newargs[i+1]) @@ -963,6 +943,7 @@ try: shared.set_logging() logging.debug('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]) @@ -975,15 +956,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]) @@ -1001,7 +984,7 @@ try: 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 + 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 @@ -1017,7 +1000,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: @@ -1029,9 +1012,7 @@ try: if js_opts is None: js_opts = opt_level >= 2 if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] - if llvm_lto is None and opt_level >= 3: llvm_lto = 3 if opt_level == 0: debug_level = 4 - if closure is None and opt_level == 3: closure = True if llvm_lto is None and bind: logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue @@ -1045,7 +1026,7 @@ 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) + 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': @@ -1057,7 +1038,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") @@ -1066,6 +1047,7 @@ try: input_files = [] has_source_inputs = False + has_header_inputs = False lib_dirs = [shared.path_from_root('system', 'local', 'lib'), shared.path_from_root('system', 'lib')] libs = [] @@ -1077,20 +1059,23 @@ 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)): + 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) - if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs + if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs newargs[i] = '' if arg_ending.endswith(SOURCE_ENDINGS): input_files.append(arg) has_source_inputs = True + elif arg_ending.endswith(HEADER_ENDINGS): + input_files.append(arg) + has_header_inputs = True elif arg_ending.endswith(ASSEMBLY_ENDINGS) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid input_files.append(arg) elif arg_ending.endswith(STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS): @@ -1124,18 +1109,18 @@ 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 if has_dash_c: - assert has_source_inputs, 'Must have source code inputs to use -c' + 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' # 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: @@ -1143,27 +1128,27 @@ 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)) + 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)) exit(0) newargs = CC_ADDITIONAL_ARGS + newargs @@ -1190,32 +1175,45 @@ 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 - assert shared.Settings.ALLOW_MEMORY_GROWTH == 0, 'memory growth not supported in fastcomp yet' - assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' - assert shared.Settings.SAFE_HEAP == 0, 'safe heap not supported in fastcomp yet' - 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.RESERVED_FUNCTION_POINTERS == 0, 'reserved function pointers 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.LEGACY_GL_EMULATION == 0, 'legacy gl emulation 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 bind, 'embind not supported in fastcomp yet' + shared.Settings.ASM_JS = 1 if opt_level > 0 else 2 + 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 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_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'] - if not shared.Settings.DISABLE_EXCEPTION_CATCHING: + 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: + fastcomp_opts += ['-emscripten-cxx-exceptions-whitelist=' + ','.join(shared.Settings.EXCEPTION_CATCHING_WHITELIST)] if shared.Settings.ASM_JS: assert opt_level >= 1 or fastcomp, 'asm.js requires -O1 or above' @@ -1230,6 +1228,14 @@ try: shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' + if shared.Settings.SAFE_HEAP and not js_opts: + js_opts = True + logging.warning('enabling js opts to allow SAFE_HEAP to work properly') + + if shared.Settings.ALLOW_MEMORY_GROWTH: + logging.warning('Disabling asm.js validation for memory growth (memory can grow, but you lose some amount of speed)'); + shared.Settings.ASM_JS = 2 + if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -1240,10 +1246,12 @@ try: 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: @@ -1265,7 +1273,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: @@ -1289,12 +1297,27 @@ try: if js_opts: shared.Settings.RUNNING_JS_OPTS = 1 + shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION + shared.Settings.OPT_LEVEL = opt_level + shared.Settings.DEBUG_LEVEL = debug_level + ## Compile source code to bitcode logging.debug('compiling to bitcode') temp_files = [] + log_time('parse arguments and setup') + + # Precompiled headers support + if has_header_inputs: + for header in input_files: + assert header.endswith(HEADER_ENDINGS), 'if you have one header input, we assume you want to precompile headers, and cannot have source files or other inputs as well: ' + str(input_files) + ' : ' + header + args = newargs + shared.EMSDK_CXX_OPTS + input_files + logging.debug("running (for precompiled headers: " + call + ' ' + ' '.join(args)) + execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) + sys.exit(1) + # 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) @@ -1334,6 +1357,8 @@ try: logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!') sys.exit(1) + log_time('bitcodeize inputs') + if not LEAVE_INPUTS_RAW: assert len(temp_files) == len(input_files) @@ -1343,7 +1368,7 @@ 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) shared.Building.llvm_opt(temp_file, llvm_opts) # If we were just asked to generate bitcode, stop there @@ -1380,387 +1405,27 @@ try: shared.Building.link(temp_files, specified_target) exit(0) + log_time('bitcodeize inputs') + ## Continue on to create JavaScript logging.debug('will generate JavaScript') - extra_files_to_link = [] - if not LEAVE_INPUTS_RAW and \ - not shared.Settings.BUILD_AS_SHARED_LIB == 2 and \ + not shared.Settings.BUILD_AS_SHARED_LIB and \ not shared.Settings.SIDE_MODULE: # shared libraries/side modules link no C libraries, need them in parent + extra_files_to_link = system_libs.calculate(temp_files, in_temp, stdout, stderr) + else: + extra_files_to_link = [] - # Check if we need to include some libraries that we compile. (We implement libc ourselves in js, but - # compile a malloc implementation and stdlibc++.) - - def read_symbols(path, exclude=None): - symbols = map(lambda line: line.strip().split(' ')[1], open(path).readlines()) - if exclude: - symbols = filter(lambda symbol: symbol not in exclude, symbols) - return set(symbols) - - lib_opts = ['-O2'] - - # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not - # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. - libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols')) - sdl_symbols = read_symbols(shared.path_from_root('system', 'lib', 'sdl.symbols')) - libcextra_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcextra.symbols')) - libcxx_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxx', 'symbols'), exclude=libc_symbols) - libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols'), exclude=libc_symbols) - - # XXX we should disable EMCC_DEBUG when building libs, just like in the relooper - - def build_libc(lib_filename, files): - o_s = [] - prev_cxx = os.environ.get('EMMAKEN_CXX') - if prev_cxx: os.environ['EMMAKEN_CXX'] = '' - musl_internal_includes = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal') - for src in files: - o = in_temp(os.path.basename(src) + '.o') - execute([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o, '-I', musl_internal_includes] + lib_opts, stdout=stdout, stderr=stderr) - o_s.append(o) - if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx - shared.Building.link(o_s, in_temp(lib_filename)) - return in_temp(lib_filename) - - def build_libcxx(src_dirname, lib_filename, files): - o_s = [] - for src in files: - o = in_temp(src + '.o') - srcfile = shared.path_from_root(src_dirname, src) - execute([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + lib_opts, stdout=stdout, stderr=stderr) - o_s.append(o) - shared.Building.link(o_s, in_temp(lib_filename)) - return in_temp(lib_filename) - - # libc - def create_libc(): - logging.debug(' building libc for cache') - libc_files = [ - 'dlmalloc.c', - os.path.join('libcxx', 'new.cpp'), - ] - musl_files = [ - ['internal', [ - 'floatscan.c', - 'shgetc.c', - ]], - ['math', [ - 'scalbn.c', - 'scalbnl.c', - ]], - ['stdio', [ - '__overflow.c', - '__toread.c', - '__towrite.c', - '__uflow.c', - ]], - ['stdlib', [ - 'atof.c', - 'strtod.c', - ]] |