diff options
author | Éloi Rivard <azmeuk@gmail.com> | 2013-04-27 13:06:42 +0200 |
---|---|---|
committer | Éloi Rivard <azmeuk@gmail.com> | 2013-05-03 10:13:04 +0200 |
commit | ce122916a38c1fdc8b82e3eb4804c979fe06a242 (patch) | |
tree | d1b2d58997bc157dc75f2b2b4da62dc7bf12abe3 | |
parent | 34bce791b6b1c34e85c5deda7fb71869dcdd6435 (diff) |
* Added some colors to messages displayed from python files.
-rwxr-xr-x | emcc | 137 | ||||
-rw-r--r-- | tools/shared.py | 174 |
2 files changed, 202 insertions, 109 deletions
@@ -75,12 +75,14 @@ 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 +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 # llvm opt level 3, and speed-wise emcc level 2 is already the slowest/most optimizing @@ -107,10 +109,10 @@ 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 -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.error('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 @@ -120,7 +122,7 @@ shared.check_sanity(force=DEBUG) # Handle some global flags if len(sys.argv) == 1: - print 'emcc: no input files' + logging.error('no input files') exit(1) # read response files very early on @@ -506,7 +508,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 @@ -563,7 +565,7 @@ if CONFIGURE_CONFIG or CMAKE_CONFIG: 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 not use_js: @@ -634,7 +636,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 @@ -651,7 +653,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 @@ -677,10 +679,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: @@ -847,14 +849,14 @@ 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.info('clearing cache') shared.Cache.erase() sys.exit(0) elif newargs[i] == '--save-bc': @@ -869,7 +871,7 @@ try: 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 '' ] @@ -886,7 +888,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), '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) for i in range(len(newargs)): if newargs[i] == '-s': @@ -939,9 +941,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:]) @@ -963,12 +965,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: @@ -976,7 +978,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 @@ -987,8 +989,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 @@ -1015,15 +1016,15 @@ try: if bind: shared.Settings.ASM_JS = 0 - print >> sys.stderr, 'emcc: warning: disabling asm.js because it is not compatible with embind yet' + logging.warning('disabling asm.js because it is not compatible with embind yet') if closure: - print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation' + logging.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' + 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' + 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' @@ -1031,7 +1032,7 @@ try: keep_llvm_debug = True # must keep debug info to do line-by-line operations if (keep_llvm_debug or keep_js_debug) and closure: - print >> sys.stderr, 'emcc: warning: disabling closure because debug info was requested' + logging.warning('disabling closure because debug info was requested') closure = False if jcache and not keep_js_debug: print >> sys.stderr, 'emcc: warning: it is recommended to run jcache with -g when compiling bitcode to JS' @@ -1053,31 +1054,31 @@ try: ## 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) @@ -1085,7 +1086,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) @@ -1096,14 +1097,14 @@ try: if final_suffix not in JS_CONTAINING_SUFFIXES: if llvm_opts > 0: if not os.environ.get('EMCC_OPTIMIZE_NORMALLY'): - print >> sys.stderr, 'emcc: warning: -Ox flags ignored, since not generating JavaScript' + logging.warning('-Ox flags ignored, since not generating JavaScript') else: for input_file in input_files: if input_file.endswith(SOURCE_SUFFIXES): - if DEBUG: print >> sys.stderr, 'emcc: optimizing %s with -O%d since EMCC_OPTIMIZE_NORMALLY defined' % (input_file, llvm_opts) + 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: - if DEBUG: print >> sys.stderr, 'emcc: not optimizing %s despite EMCC_OPTIMIZE_NORMALLY since not source code' % (input_file) + 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) @@ -1114,13 +1115,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 generate JavaScript' + logging.debug('will generate JavaScript') extra_files_to_link = [] @@ -1169,7 +1170,7 @@ try: # libc def create_libc(): - if DEBUG: print >> sys.stderr, 'emcc: building libc for cache' + logging.debug(' building libc for cache') libc_files = [ 'dlmalloc.c', os.path.join('libcxx', 'new.cpp'), @@ -1199,7 +1200,7 @@ try: # libcextra def create_libcextra(): - if DEBUG: print >> sys.stderr, 'emcc: building libcextra for cache' + logging.debug('building libcextra for cache') musl_files = [ ['ctype', [ 'iswalnum.c', @@ -1278,7 +1279,7 @@ try: # libcxx def create_libcxx(): - if DEBUG: print >> sys.stderr, 'emcc: building libcxx for cache' + logging.debug('building libcxx for cache') libcxx_files = [ 'algorithm.cpp', 'condition_variable.cpp', @@ -1309,11 +1310,11 @@ try: assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++ with QUANTUM_SIZE == 1' # libcxx might need corrections, so turn them all on. TODO: check which are actually needed shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 - #print >> sys.stderr, 'emcc: info: using libcxx turns on CORRECT_* options' + #logging.info('using libcxx turns on CORRECT_* options') # libcxxabi - just for dynamic_cast for now def create_libcxxabi(): - if DEBUG: print >> sys.stderr, 'emcc: building libcxxabi for cache' + logging.debug('building libcxxabi for cache') libcxxabi_files = [ 'typeinfo.cpp', 'private_typeinfo.cpp' @@ -1322,7 +1323,7 @@ try: def fix_libcxxabi(need): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++abi with QUANTUM_SIZE == 1' - #print >> sys.stderr, 'emcc: info: using libcxxabi, this may need CORRECT_* options' + #logging.info('using libcxxabi, this may need CORRECT_* options') #shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 # If we have libcxx, we must force inclusion of libc, since libcxx uses new internally. Note: this is kind of hacky @@ -1346,10 +1347,10 @@ try: for haz in has: # remove symbols that are supplied by another of the inputs if haz in need: need.remove(haz) - if DEBUG: print >> sys.stderr, 'emcc: considering including %s: we need %s and have %s' % (name, str(need), str(has)) + logging.debug('considering including %s: we need %s and have %s' % (name, str(need), str(has))) if force or len(need) > 0: # We need to build and link the library in - if DEBUG: print >> sys.stderr, 'emcc: including %s' % name + logging.debug('including %s' % name) libfile = shared.Cache.get(name, create) extra_files_to_link.append(libfile) force = True @@ -1360,11 +1361,11 @@ try: if len(input_files) + len(extra_files_to_link) > 1 or \ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in DYNAMICLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link - if DEBUG: print >> sys.stderr, 'emcc: linking: ', linker_inputs + logging.debug('linking: ', linker_inputs) t0 = time.time() shared.Building.link(linker_inputs, in_temp(target_basename + '.bc')) t1 = time.time() - if DEBUG: print >> sys.stderr, 'emcc: linking took %.2f seconds' % (t1 - t0) + logging.debug(' linking took %.2f seconds' % (t1 - t0)) final = in_temp(target_basename + '.bc') else: if not LEAVE_INPUTS_RAW: @@ -1375,7 +1376,7 @@ try: shutil.copyfile(input_files[0], final) if DEBUG: - print >> sys.stderr, 'emcc: 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 intermediate_time = None @@ -1385,7 +1386,7 @@ try: intermediate_counter += 1 now = time.time() if intermediate_time: - print >> sys.stderr, 'emcc: step took %.2f seconds' % (now - intermediate_time) + logging.debug(' step took %.2f seconds' % (now - intermediate_time)) intermediate_time = now if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc') @@ -1399,7 +1400,7 @@ try: if DEBUG: save_intermediate('opt', 'bc') # Do LTO in a separate pass to work around LLVM bug XXX (see failure e.g. in cubescript) else: - if DEBUG: print >> sys.stderr, 'emcc: not running opt because EMCC_OPTIMIZE_NORMALLY was specified, opt should have been run before' + logging.debug('not running opt because EMCC_OPTIMIZE_NORMALLY was specified, opt should have been run before') if shared.Building.can_build_standalone(): # If we can LTO, do it before dce, since it opens up dce opportunities if llvm_lto and shared.Building.can_use_unsafe_opts(): @@ -1423,13 +1424,13 @@ try: if DEBUG: save_intermediate('ll', 'll') if AUTODEBUG: - if DEBUG: print >> sys.stderr, 'emcc: autodebug' + logging.debug('autodebug') execute([shared.PYTHON, shared.AUTODEBUGGER, final, final + '.ad.ll']) final += '.ad.ll' if DEBUG: save_intermediate('autodebug', 'll') # Emscripten - if DEBUG: print >> sys.stderr, 'emcc: LLVM => JS' + logging.debug('LLVM => JS') extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))] if jcache: extra_args.append('--jcache') final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args) @@ -1437,7 +1438,7 @@ try: # Embed and preload files if len(preload_files) + len(embed_files) > 0: - if DEBUG: print >> sys.stderr, 'emcc: setting up files' + logging.debug('setting up files') file_args = [] if len(preload_files) > 0: file_args.append('--preload') @@ -1457,7 +1458,7 @@ try: # Apply pre and postjs files if pre_js or post_js: - if DEBUG: print >> sys.stderr, 'emcc: applying pre/postjses' + logging.debug('applying pre/postjses') src = open(final).read() final += '.pp.js' open(final, 'w').write(pre_js + src + post_js) @@ -1465,7 +1466,7 @@ try: # Add bindings glue if used if bind: - if DEBUG: print >> sys.stderr, 'emcc: adding embind glue' + logging.debug('adding embind glue') src = open(final).read().replace('// {{PRE_RUN_ADDITIONS}}', '// {{PRE_RUN_ADDITIONS}}\n' + open(shared.path_from_root('src', 'embind', 'embind.js')).read() + open(shared.path_from_root('src', 'embind', 'emval.js')).read() @@ -1479,7 +1480,7 @@ try: shutil.copyfile(final, final + '.tr.js') final += '.tr.js' posix = True if not shared.WINDOWS else False - if DEBUG: print >> sys.stderr, 'emcc: applying transform: %s' % js_transform + logging.debug('applying transform: %s' % js_transform) execute(shlex.split(js_transform, posix=posix) + [os.path.abspath(final)]) if DEBUG: save_intermediate('transformed') @@ -1491,7 +1492,7 @@ try: if DEBUG != '2': if shared.Settings.ASM_JS: js_optimizer_queue = ['asm'] + js_optimizer_queue - if DEBUG: print >> sys.stderr, 'emcc: applying js optimization passes:', js_optimizer_queue + logging.debug('applying js optimization passes:', js_optimizer_queue) final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache) if DEBUG: save_intermediate('js_opts') else: @@ -1499,13 +1500,13 @@ try: passes = [name] if shared.Settings.ASM_JS: passes = ['asm'] + passes - print >> sys.stderr, 'emcc: applying js optimization pass:', passes + logging.info('applying js optimization pass:', passes) final = shared.Building.js_optimizer(final, passes, jcache) save_intermediate(name) js_optimizer_queue = [] if opt_level >= 1: - if DEBUG: print >> sys.stderr, 'emcc: running pre-closure post-opts' + logging.debug('running pre-closure post-opts') if DEBUG == '2': # Clean up the syntax a bit @@ -1526,12 +1527,12 @@ try: if closure: flush_js_optimizer_queue() - if DEBUG: print >> sys.stderr, 'emcc: running closure' + logging.debug('running closure') final = shared.Building.closure_compiler(final) if DEBUG: save_intermediate('closure') if opt_level >= 1: - if DEBUG: print >> sys.stderr, 'emcc: running post-closure post-opts' + logging.debug('running post-closure post-opts') js_optimizer_queue += ['simplifyExpressionsPost'] if not closure and shared.Settings.RELOOP and not keep_js_debug: @@ -1552,7 +1553,7 @@ try: if memory_init_file: if shared.Settings.USE_TYPED_ARRAYS != 2: - if type(memory_init_file) == int: print >> sys.stderr, 'emcc: warning: memory init file requires typed arrays mode 2' + if type(memory_init_file) == int: logging.warning('memory init file requires typed arrays mode 2') else: memfile = target + '.mem' shared.try_delete(memfile) @@ -1574,13 +1575,13 @@ try: if DEBUG: if os.path.exists(memfile): save_intermediate('meminit') - print >> sys.stderr, 'emcc: wrote memory initialization to %s' % memfile + logging.debug('wrote memory initialization to %s' % memfile) else: - print >> sys.stderr, 'emcc: did not see memory initialization' + logging.debug('did not see memory initialization') # If we were asked to also generate HTML, do that if final_suffix == 'html': - if DEBUG: print >> sys.stderr, 'emcc: generating HTML' + logging.debug('generating HTML') shell = open(shell_path).read() html = open(target, 'w') if not Compression.on: @@ -1657,7 +1658,7 @@ try: # copy final JS to output shutil.move(final, target) - if DEBUG: print >> sys.stderr, 'emcc: 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: @@ -1666,5 +1667,5 @@ finally: except: pass else: - print >> sys.stderr, 'emcc saved files are in:', temp_dir + logging.info('emcc saved files are in:' + temp_dir) diff --git a/tools/shared.py b/tools/shared.py index e9284bf7..97d30f0c 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -3,6 +3,7 @@ from subprocess import Popen, PIPE, STDOUT from tempfile import mkstemp import jsrun, cache, tempfiles from response_file import create_response_file +import logging, platform def listify(x): if type(x) is not list: return [x] @@ -90,6 +91,100 @@ __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def path_from_root(*pathelems): return os.path.join(__rootpath__, *pathelems) +def add_coloring_to_emit_windows(fn): + def _out_handle(self): + import ctypes + return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE) + out_handle = property(_out_handle) + + def _set_color(self, code): + import ctypes + # Constants from the Windows API + self.STD_OUTPUT_HANDLE = -11 + hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE) + ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code) + + setattr(logging.StreamHandler, '_set_color', _set_color) + + def new(*args): + FOREGROUND_BLUE = 0x0001 # text color contains blue. + FOREGROUND_GREEN = 0x0002 # text color contains green. + FOREGROUND_RED = 0x0004 # text color contains red. + FOREGROUND_INTENSITY = 0x0008 # text color is intensified. + FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED + # winbase.h + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + # wincon.h + FOREGROUND_BLACK = 0x0000 + FOREGROUND_BLUE = 0x0001 + FOREGROUND_GREEN = 0x0002 + FOREGROUND_CYAN = 0x0003 + FOREGROUND_RED = 0x0004 + FOREGROUND_MAGENTA = 0x0005 + FOREGROUND_YELLOW = 0x0006 + FOREGROUND_GREY = 0x0007 + FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified. + + BACKGROUND_BLACK = 0x0000 + BACKGROUND_BLUE = 0x0010 + BACKGROUND_GREEN = 0x0020 + BACKGROUND_CYAN = 0x0030 + BACKGROUND_RED = 0x0040 + BACKGROUND_MAGENTA = 0x0050 + BACKGROUND_YELLOW = 0x0060 + BACKGROUND_GREY = 0x0070 + BACKGROUND_INTENSITY = 0x0080 # background color is intensified. + levelno = args[1].levelno + if(levelno>=50): + color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY + elif(levelno>=40): + color = FOREGROUND_RED | FOREGROUND_INTENSITY + elif(levelno>=30): + color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY + elif(levelno>=20): + color = FOREGROUND_GREEN + elif(levelno>=10): + color = FOREGROUND_MAGENTA + else: + color = FOREGROUND_WHITE + args[0]._set_color(color) + ret = fn(*args) + args[0]._set_color( FOREGROUND_WHITE ) + #print "after" + return ret + return new + +def add_coloring_to_emit_ansi(fn): + # add methods we need to the class + def new(*args): + levelno = args[1].levelno + if(levelno>=50): + color = '\x1b[31m' # red + elif(levelno>=40): + color = '\x1b[31m' # red + elif(levelno>=30): + color = '\x1b[33m' # yellow + elif(levelno>=20): + color = '\x1b[32m' # green + elif(levelno>=10): + color = '\x1b[35m' # pink + else: + color = '\x1b[0m' # normal + args[1].msg = color + args[1].msg + '\x1b[0m' # normal + #print "after" + return fn(*args) + return new + +WINDOWS = sys.platform.startswith('win') + +if WINDOWS: + logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit) +else: + logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit) + # Emscripten configuration is done through the EM_CONFIG environment variable. # If the string value contained in this environment variable contains newline # separated definitions, then these definitions will be used to configure @@ -157,7 +252,7 @@ try: config_text = open(CONFIG_FILE, 'r').read() if CONFIG_FILE else EM_CONFIG exec(config_text) except Exception, e: - print >> sys.stderr, 'Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text) + logging.error('Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text)) sys.exit(1) # Expectations @@ -169,14 +264,14 @@ def check_clang_version(): actual = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0] if expected in actual: return True - print >> sys.stderr, 'warning: LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected) + logging.warning('LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected)) return False def check_llvm_version(): try: check_clang_version(); except Exception, e: - print >> sys.stderr, 'warning: Could not verify LLVM version: %s' % str(e) + logging.warning('Could not verify LLVM version: %s' % str(e)) EXPECTED_NODE_VERSION = (0,6,8) @@ -187,10 +282,10 @@ def check_node_version(): version = tuple(map(int, actual.replace('v', '').split('.'))) if version >= EXPECTED_NODE_VERSION: return True - print >> sys.stderr, 'warning: node version appears too old (seeing "%s", expected "%s")' % (actual, 'v' + ('.'.join(map(str, EXPECTED_NODE_VERSION)))) + logging.warning('node version appears too old (seeing "%s", expected "%s")' % (actual, 'v' + ('.'.join(map(str, EXPECTED_NODE_VERSION))))) return False except Exception, e: - print >> sys.stderr, 'warning: cannot check node version:', e + logging.warning('cannot check node version:' + e) return False # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) @@ -227,7 +322,7 @@ def check_sanity(force=False): except Exception, e: reason = 'unknown: ' + str(e) if reason: - print >> sys.stderr, '(Emscripten: %s, clearing cache)' % reason + logging.info('(Emscripten: %s, clearing cache)' % reason) Cache.erase() # some warning, not fatal checks - do them even if EM_IGNORE_SANITY is on @@ -235,32 +330,32 @@ def check_sanity(force=False): check_node_version() if os.environ.get('EM_IGNORE_SANITY'): - print >> sys.stderr, 'EM_IGNORE_SANITY set, ignoring sanity checks' + logging.info('EM_IGNORE_SANITY set, ignoring sanity checks') return - print >> sys.stderr, '(Emscripten: Running sanity checks)' + logging.info('(Emscripten: Running sanity checks)') if not check_engine(COMPILER_ENGINE): - print >> sys.stderr, 'FATAL: The JavaScript shell used for compiling (%s) does not seem to work, check the paths in %s' % (COMPILER_ENGINE, EM_CONFIG) + logging.critical('The JavaScript shell used for compiling (%s) does not seem to work, check the paths in %s' % (COMPILER_ENGINE, EM_CONFIG)) sys.exit(1) if NODE_JS != COMPILER_ENGINE: if not check_engine(NODE_JS): - print >> sys.stderr, 'FATAL: Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG) + logging.critical('Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG)) sys.exit(1) for cmd in [CLANG, LLVM_LINK, LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]: if not os.path.exists(cmd) and not os.path.exists(cmd + '.exe'): # .exe extension required for Windows - print >> sys.stderr, 'FATAL: Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG) + logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG)) sys.exit(1) try: subprocess.call([JAVA, '-version'], stdout=PIPE, stderr=PIPE) except: - print >> sys.stderr, 'WARNING: java does not seem to exist, required for closure compiler. -O2 and above will fail. You need to define JAVA in ~/.emscripten' + logging.warning('java does not seem to exist, required for closure compiler. -O2 and above will fail. You need to define JAVA in ~/.emscripten') if not os.path.exists(CLOSURE_COMPILER): - print >> sys.stderr, 'WARNING: Closure compiler (%s) does not exist, check the paths in %s. -O2 and above will fail' % (CLOSURE_COMPILER, EM_CONFIG) + logging.warning('Closure compiler (%s) does not exist, check the paths in %s. -O2 and above will fail' % (CLOSURE_COMPILER, EM_CONFIG)) # Sanity check passed! @@ -335,7 +430,7 @@ class Configuration: try: self.TEMP_DIR = TEMP_DIR except NameError: - print >> sys.stderr, 'TEMP_DIR not defined in ~/.emscripten, using /tmp' + logging.info('TEMP_DIR not defined in ~/.emscripten, using /tmp') self.TEMP_DIR = '/tmp' self.CANONICAL_TEMP_DIR = os.path.join(self.TEMP_DIR, 'emscripten_temp') @@ -346,23 +441,22 @@ class Configuration: if not os.path.exists(self.EMSCRIPTEN_TEMP_DIR): os.makedirs(self.EMSCRIPTEN_TEMP_DIR) except Exception, e: - print >> sys.stderr, e, 'Could not create canonical temp dir. Check definition of TEMP_DIR in ~/.emscripten' + logging.debug(e + 'Could not create canonical temp dir. Check definition of TEMP_DIR in ~/.emscripten') def get_temp_files(self): return tempfiles.TempFiles( tmp=self.TEMP_DIR if not self.DEBUG else self.EMSCRIPTEN_TEMP_DIR, save_debug_files=os.environ.get('EMCC_DEBUG_SAVE')) - def debug_log(self, msg): - if self.DEBUG: - print >> sys.stderr, msg - configuration = Configuration(environ=os.environ) DEBUG = configuration.DEBUG EMSCRIPTEN_TEMP_DIR = configuration.EMSCRIPTEN_TEMP_DIR DEBUG_CACHE = configuration.DEBUG_CACHE CANONICAL_TEMP_DIR = configuration.CANONICAL_TEMP_DIR +level = logging.DEBUG if os.environ.get('EMCC_DEBUG') else logging.INFO +logging.basicConfig(level=level, format='%(levelname)-8s %(name)s: %(message)s') + if not EMSCRIPTEN_TEMP_DIR: EMSCRIPTEN_TEMP_DIR = tempfile.mkdtemp(prefix='emscripten_temp_', dir=configuration.TEMP_DIR) def clean_temp(): @@ -388,13 +482,13 @@ except: try: PYTHON except: - if DEBUG: print >> sys.stderr, 'PYTHON not defined in ~/.emscripten, using "python"' + logging.debug('PYTHON not defined in ~/.emscripten, using "python"') PYTHON = 'python' try: JAVA except: - if DEBUG: print >> sys.stderr, 'JAVA not defined in ~/.emscripten, using "java"' + logging.debug('JAVA not defined in ~/.emscripten, using "java"') JAVA = 'java' # Additional compiler options @@ -450,8 +544,6 @@ try: except NameError: pass -WINDOWS = sys.platform.startswith('win') - # If we have 'env', we should use that to find python, because |python| may fail while |env python| may work # (For example, if system python is 3.x while we need 2.x, and env gives 2.x if told to do so.) ENV_PREFIX = [] @@ -585,7 +677,7 @@ class Settings: # Aside from these, -O3 also runs closure compiler and llvm lto Settings.DOUBLE_MODE = 0 Settings.PRECISE_I64_MATH = 0 - if noisy: print >> sys.stderr, 'Warning: Applying some potentially unsafe optimizations! (Use -O2 if this fails.)' + if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)') global Settings Settings = Settings2 @@ -671,7 +763,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e process = Popen(args, stdout=stdout, stderr=stderr, env=env) process.communicate() except Exception, e: - print >> sys.stderr, 'Error: Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args) + logging.error('Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args)) raise del env['EMMAKEN_JUST_CONFIGURE'] if process.returncode is not 0: @@ -682,14 +774,14 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e if env is None: env = Building.get_building_env() if not args: - print >> sys.stderr, 'Error: Executable to run not specified.' + logging.error('Executable to run not specified.') sys.exit(1) #args += ['VERBOSE=1'] try: process = Popen(args, stdout=stdout, stderr=stderr, env=env) process.communicate() except Exception, e: - print >> sys.stderr, 'Error: Exception thrown when invoking Popen in make with args: "%s"!' % ' '.join(args) + logging.error('Exception thrown when invoking Popen in make with args: "%s"!' % ' '.join(args)) raise if process.returncode is not 0: raise subprocess.CalledProcessError(cmd=args, returncode=process.returncode) @@ -796,7 +888,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e contents = filter(lambda x: len(x) > 0, Popen([LLVM_AR, 't', f], stdout=PIPE).communicate()[0].split('\n')) #print >> sys.stderr, ' considering archive', f, ':', contents if len(contents) == 0: - print >> sys.stderr, 'Warning: Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f + logging.debug('Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f) else: for content in contents: # ar will silently fail if the directory for the file does not exist, so make all the necessary directories dirname = os.path.dirname(content) @@ -833,7 +925,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e # Finish link actual_files = unique_ordered(actual_files) # tolerate people trying to link a.so a.so etc. - if DEBUG: print >>sys.stderr, 'emcc: llvm-linking:', actual_files + logging.debug('emcc: llvm-linking:', actual_files) # check for too-long command line link_cmd = [LLVM_LINK] + actual_files + ['-o', target] @@ -841,7 +933,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e # for max command line size before we use a respose file response_file = None if WINDOWS and len(' '.join(link_cmd)) > 8192: - if DEBUG: print >>sys.stderr, 'using response file for llvm-link' + logging.debug('using response file for llvm-link') [response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR) link_cmd = [LLVM_LINK, "@" + response_file] @@ -858,7 +950,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e link_cmd.append(target) if len(' '.join(link_cmd)) > 8192: - print >>sys.stderr, 'emcc: warning: link command line is very long, even with response file -- use paths with no spaces' + logging.warning('emcc: link command line is very long, even with response file -- use paths with no spaces') output = Popen(link_cmd, stdout=PIPE).communicate()[0] @@ -887,7 +979,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e if type(opts) is int: opts = Building.pick_llvm_opts(opts) #opts += ['-debug-pass=Arguments'] - if DEBUG: print >> sys.stderr, 'emcc: LLVM opts:', opts + logging.debug('emcc: LLVM opts:', opts) output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0] assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output shutil.move(filename + '.opt.bc', filename) @@ -1148,7 +1240,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e Building._is_ar_cache[filename] = sigcheck return sigcheck except Exception, e: - if DEBUG: print >> sys.stderr, 'shared.Building.is_ar failed to test whether file \'%s\' is a llvm archive file! Failed on exception: %s' % (filename, e) + logging.debug('Building.is_ar failed to test whether file \'%s\' is a llvm archive file! Failed on exception: %s' % (filename, e)) return False @staticmethod @@ -1175,8 +1267,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e curr = os.getcwd() try: ok = False - print >> sys.stderr, '=======================================' - print >> sys.stderr, 'bootstrapping relooper...' + logging.info('=======================================') + logging.info('bootstrapping relooper...') os.chdir(path_from_root('src')) emcc_debug = os.environ.get('EMCC_DEBUG') @@ -1201,19 +1293,19 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e f.close() # bootstrap phase 1: generate unrelooped relooper, for which we do not need a relooper (so we cannot recurse infinitely in this function) - print >> sys.stderr, ' bootstrap phase 1' + logging.info(' bootstrap phase 1') make(1) # bootstrap phase 2: generate relooped relooper, using the unrelooped relooper (we see relooper.js exists so we cannot recurse infinitely in this function) - print >> sys.stderr, ' bootstrap phase 2' + logging.info(' bootstrap phase 2') make(2) - print >> sys.stderr, 'bootstrapping relooper succeeded' - print >> sys.stderr, '=======================================' + logging.info('bootstrapping relooper succeeded') + logging.info('=======================================') ok = True finally: os.chdir(curr) if emcc_debug: os.environ['EMCC_DEBUG'] = emcc_debug if not ok: - print >> sys.stderr, 'bootstrapping relooper failed. You may need to manually create relooper.js by compiling it, see src/relooper/emscripten' + logging.error('bootstrapping relooper failed. You may need to manually create relooper.js by compiling it, see src/relooper/emscripten') 1/0 @staticmethod @@ -1274,7 +1366,7 @@ def execute(cmd, *args, **kw): except: if not isinstance(cmd, str): cmd = ' '.join(cmd) - print >> sys.stderr, 'Invoking Process failed: <<< ' + cmd + ' >>>' + logging.error('Invoking Process failed: <<< ' + cmd + ' >>>') raise def suffix(name): |