46
47
# Call the process with fixed streams.
47
48
self.process = subprocess.Popen(args, bufsize, executable, self.stdin_, self.stdout_, self.stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
48
49
except Exception, e:
49
print >> sys.stderr, '\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e))
50
logging.error('\nsubprocess.Popen(args=%s) failed! Exception %s\n' % (' '.join(args), str(e)))
52
53
def communicate(self, input=None):
90
91
def path_from_root(*pathelems):
91
92
return os.path.join(__rootpath__, *pathelems)
94
def add_coloring_to_emit_windows(fn):
95
def _out_handle(self):
97
return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
98
out_handle = property(_out_handle)
100
def _set_color(self, code):
102
# Constants from the Windows API
103
self.STD_OUTPUT_HANDLE = -11
104
hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
105
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)
107
setattr(logging.StreamHandler, '_set_color', _set_color)
110
FOREGROUND_BLUE = 0x0001 # text color contains blue.
111
FOREGROUND_GREEN = 0x0002 # text color contains green.
112
FOREGROUND_RED = 0x0004 # text color contains red.
113
FOREGROUND_INTENSITY = 0x0008 # text color is intensified.
114
FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED
116
STD_INPUT_HANDLE = -10
117
STD_OUTPUT_HANDLE = -11
118
STD_ERROR_HANDLE = -12
121
FOREGROUND_BLACK = 0x0000
122
FOREGROUND_BLUE = 0x0001
123
FOREGROUND_GREEN = 0x0002
124
FOREGROUND_CYAN = 0x0003
125
FOREGROUND_RED = 0x0004
126
FOREGROUND_MAGENTA = 0x0005
127
FOREGROUND_YELLOW = 0x0006
128
FOREGROUND_GREY = 0x0007
129
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
131
BACKGROUND_BLACK = 0x0000
132
BACKGROUND_BLUE = 0x0010
133
BACKGROUND_GREEN = 0x0020
134
BACKGROUND_CYAN = 0x0030
135
BACKGROUND_RED = 0x0040
136
BACKGROUND_MAGENTA = 0x0050
137
BACKGROUND_YELLOW = 0x0060
138
BACKGROUND_GREY = 0x0070
139
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
140
levelno = args[1].levelno
142
color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY
144
color = FOREGROUND_RED | FOREGROUND_INTENSITY
146
color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
148
color = FOREGROUND_GREEN
150
color = FOREGROUND_MAGENTA
152
color = FOREGROUND_WHITE
153
args[0]._set_color(color)
155
args[0]._set_color( FOREGROUND_WHITE )
160
def add_coloring_to_emit_ansi(fn):
161
# add methods we need to the class
163
levelno = args[1].levelno
165
color = '\x1b[31m' # red
167
color = '\x1b[31m' # red
169
color = '\x1b[33m' # yellow
171
color = '\x1b[32m' # green
173
color = '\x1b[35m' # pink
175
color = '\x1b[0m' # normal
176
args[1].msg = color + args[1].msg + '\x1b[0m' # normal
181
WINDOWS = sys.platform.startswith('win')
184
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
186
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
93
188
# Emscripten configuration is done through the EM_CONFIG environment variable.
94
189
# If the string value contained in this environment variable contains newline
95
190
# separated definitions, then these definitions will be used to configure
124
219
config_file = config_file.replace('{{{ NODE }}}', node)
220
python = sys.executable or 'python'
127
222
python = Popen(['which', 'python2'], stdout=PIPE).communicate()[0].replace('\n', '') or \
128
223
Popen(['which', 'python'], stdout=PIPE).communicate()[0].replace('\n', '') or python
157
252
config_text = open(CONFIG_FILE, 'r').read() if CONFIG_FILE else EM_CONFIG
158
253
exec(config_text)
159
254
except Exception, e:
160
print >> sys.stderr, 'Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text)
255
logging.error('Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text))
169
264
actual = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0]
170
265
if expected in actual:
172
print >> sys.stderr, 'warning: LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected)
267
logging.warning('LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected))
175
270
def check_llvm_version():
177
272
check_clang_version();
178
273
except Exception, e:
179
print >> sys.stderr, 'warning: Could not verify LLVM version: %s' % str(e)
274
logging.warning('Could not verify LLVM version: %s' % str(e))
181
276
EXPECTED_NODE_VERSION = (0,6,8)
187
282
version = tuple(map(int, actual.replace('v', '').split('.')))
188
283
if version >= EXPECTED_NODE_VERSION:
190
print >> sys.stderr, 'warning: node version appears too old (seeing "%s", expected "%s")' % (actual, 'v' + ('.'.join(map(str, EXPECTED_NODE_VERSION))))
285
logging.warning('node version appears too old (seeing "%s", expected "%s")' % (actual, 'v' + ('.'.join(map(str, EXPECTED_NODE_VERSION)))))
192
287
except Exception, e:
193
print >> sys.stderr, 'warning: cannot check node version:', e
288
logging.warning('cannot check node version: %s', e)
196
291
# Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM)
235
330
check_node_version()
237
332
if os.environ.get('EM_IGNORE_SANITY'):
238
print >> sys.stderr, 'EM_IGNORE_SANITY set, ignoring sanity checks'
333
logging.info('EM_IGNORE_SANITY set, ignoring sanity checks')
241
print >> sys.stderr, '(Emscripten: Running sanity checks)'
336
logging.info('(Emscripten: Running sanity checks)')
243
338
if not check_engine(COMPILER_ENGINE):
244
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)
339
logging.critical('The JavaScript shell used for compiling (%s) does not seem to work, check the paths in %s' % (COMPILER_ENGINE, EM_CONFIG))
247
342
if NODE_JS != COMPILER_ENGINE:
248
343
if not check_engine(NODE_JS):
249
print >> sys.stderr, 'FATAL: Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG)
344
logging.critical('Node.js (%s) does not seem to work, check the paths in %s' % (NODE_JS, EM_CONFIG))
252
347
for cmd in [CLANG, LLVM_LINK, LLVM_AR, LLVM_OPT, LLVM_AS, LLVM_DIS, LLVM_NM]:
253
348
if not os.path.exists(cmd) and not os.path.exists(cmd + '.exe'): # .exe extension required for Windows
254
print >> sys.stderr, 'FATAL: Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG)
349
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
258
353
subprocess.call([JAVA, '-version'], stdout=PIPE, stderr=PIPE)
260
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'
355
logging.warning('java does not seem to exist, required for closure compiler. -O2 and above will fail. You need to define JAVA in ~/.emscripten')
262
357
if not os.path.exists(CLOSURE_COMPILER):
263
print >> sys.stderr, 'WARNING: Closure compiler (%s) does not exist, check the paths in %s. -O2 and above will fail' % (CLOSURE_COMPILER, EM_CONFIG)
358
logging.warning('Closure compiler (%s) does not exist, check the paths in %s. -O2 and above will fail' % (CLOSURE_COMPILER, EM_CONFIG))
265
360
# Sanity check passed!
346
441
if not os.path.exists(self.EMSCRIPTEN_TEMP_DIR):
347
442
os.makedirs(self.EMSCRIPTEN_TEMP_DIR)
348
443
except Exception, e:
349
print >> sys.stderr, e, 'Could not create canonical temp dir. Check definition of TEMP_DIR in ~/.emscripten'
444
logging.debug(e + 'Could not create canonical temp dir. Check definition of TEMP_DIR in ~/.emscripten')
351
446
def get_temp_files(self):
352
447
return tempfiles.TempFiles(
353
448
tmp=self.TEMP_DIR if not self.DEBUG else self.EMSCRIPTEN_TEMP_DIR,
354
449
save_debug_files=os.environ.get('EMCC_DEBUG_SAVE'))
356
def debug_log(self, msg):
358
print >> sys.stderr, msg
360
451
configuration = Configuration(environ=os.environ)
361
452
DEBUG = configuration.DEBUG
362
453
EMSCRIPTEN_TEMP_DIR = configuration.EMSCRIPTEN_TEMP_DIR
363
454
DEBUG_CACHE = configuration.DEBUG_CACHE
364
455
CANONICAL_TEMP_DIR = configuration.CANONICAL_TEMP_DIR
457
level = logging.DEBUG if os.environ.get('EMCC_DEBUG') else logging.INFO
458
logging.basicConfig(level=level, format='%(levelname)-8s %(name)s: %(message)s')
366
460
if not EMSCRIPTEN_TEMP_DIR:
367
461
EMSCRIPTEN_TEMP_DIR = tempfile.mkdtemp(prefix='emscripten_temp_', dir=configuration.TEMP_DIR)
368
462
def clean_temp():
391
if DEBUG: print >> sys.stderr, 'PYTHON not defined in ~/.emscripten, using "python"'
485
logging.debug('PYTHON not defined in ~/.emscripten, using "python"')
392
486
PYTHON = 'python'
397
if DEBUG: print >> sys.stderr, 'JAVA not defined in ~/.emscripten, using "java"'
491
logging.debug('JAVA not defined in ~/.emscripten, using "java"')
400
494
# Additional compiler options
402
496
# Target choice. Must be synced with src/settings.js (TARGET_*)
403
497
def get_llvm_target():
404
return os.environ.get('EMCC_LLVM_TARGET') or 'i386-pc-linux-gnu' # 'le32-unknown-nacl'
498
return os.environ.get('EMCC_LLVM_TARGET') or 'le32-unknown-nacl' # 'i386-pc-linux-gnu'
405
499
LLVM_TARGET = get_llvm_target()
412
506
COMPILER_OPTS = COMPILER_OPTS + ['-m32', '-U__i386__', '-U__i386', '-Ui386',
413
507
'-U__SSE__', '-U__SSE_MATH__', '-U__SSE2__', '-U__SSE2_MATH__', '-U__MMX__',
414
508
'-DEMSCRIPTEN', '-D__EMSCRIPTEN__', '-U__STRICT_ANSI__',
415
'-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno',
509
'-D__IEEE_LITTLE_ENDIAN', '-fno-math-errno', '-fno-threadsafe-statics',
416
510
'-target', LLVM_TARGET]
512
if LLVM_TARGET == 'le32-unknown-nacl':
513
COMPILER_OPTS += ['-U__native_client__', '-U__pnacl__', '-U__ELF__'] # The nacl target is originally used for Google Native Client. Emscripten is not NaCl, so remove the platform #define, when using their triple.
418
515
USE_EMSDK = not os.environ.get('EMMAKEN_NO_SDK')
581
681
Settings.EMIT_GENERATED_FUNCTIONS = 1
582
682
if opt_level >= 2:
583
683
Settings.RELOOP = 1
684
Settings.ALIASING_FUNCTION_POINTERS = 1
584
685
if opt_level >= 3:
585
686
# Aside from these, -O3 also runs closure compiler and llvm lto
687
Settings.FORCE_ALIGNED_MEMORY = 1
586
688
Settings.DOUBLE_MODE = 0
587
689
Settings.PRECISE_I64_MATH = 0
588
if noisy: print >> sys.stderr, 'Warning: Applying some potentially unsafe optimizations! (Use -O2 if this fails.)'
690
if noisy: logging.warning('Applying some potentially unsafe optimizations! (Use -O2 if this fails.)')
591
693
Settings = Settings2
671
774
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
672
775
process.communicate()
673
776
except Exception, e:
674
print >> sys.stderr, 'Error: Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args)
777
logging.error('Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args))
676
779
del env['EMMAKEN_JUST_CONFIGURE']
677
780
if process.returncode is not 0:
683
786
env = Building.get_building_env()
685
print >> sys.stderr, 'Error: Executable to run not specified.'
788
logging.error('Executable to run not specified.')
687
790
#args += ['VERBOSE=1']
689
792
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
690
793
process.communicate()
691
794
except Exception, e:
692
print >> sys.stderr, 'Error: Exception thrown when invoking Popen in make with args: "%s"!' % ' '.join(args)
795
logging.error('Exception thrown when invoking Popen in make with args: "%s"!' % ' '.join(args))
694
797
if process.returncode is not 0:
695
798
raise subprocess.CalledProcessError(cmd=args, returncode=process.returncode)
796
899
contents = filter(lambda x: len(x) > 0, Popen([LLVM_AR, 't', f], stdout=PIPE).communicate()[0].split('\n'))
797
900
#print >> sys.stderr, ' considering archive', f, ':', contents
798
901
if len(contents) == 0:
799
print >> sys.stderr, 'Warning: Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f
902
logging.debug('Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f)
801
904
for content in contents: # ar will silently fail if the directory for the file does not exist, so make all the necessary directories
802
905
dirname = os.path.dirname(content)
835
938
actual_files = unique_ordered(actual_files) # tolerate people trying to link a.so a.so etc.
836
if DEBUG: print >>sys.stderr, 'emcc: llvm-linking:', actual_files
939
logging.debug('emcc: llvm-linking: %s', actual_files)
838
941
# check for too-long command line
839
942
link_cmd = [LLVM_LINK] + actual_files + ['-o', target]
841
944
# for max command line size before we use a respose file
842
945
response_file = None
843
946
if WINDOWS and len(' '.join(link_cmd)) > 8192:
844
if DEBUG: print >>sys.stderr, 'using response file for llvm-link'
947
logging.debug('using response file for llvm-link')
845
948
[response_fd, response_file] = mkstemp(suffix='.response', dir=TEMP_DIR)
847
950
link_cmd = [LLVM_LINK, "@" + response_file]
887
990
if type(opts) is int:
888
991
opts = Building.pick_llvm_opts(opts)
889
992
#opts += ['-debug-pass=Arguments']
890
if DEBUG: print >> sys.stderr, 'emcc: LLVM opts:', opts
993
logging.debug('emcc: LLVM opts: ' + str(opts))
891
994
output = Popen([LLVM_OPT, filename] + opts + ['-o=' + filename + '.opt.bc'], stdout=PIPE).communicate()[0]
892
995
assert os.path.exists(filename + '.opt.bc'), 'Failed to run llvm optimizations: ' + output
893
996
shutil.move(filename + '.opt.bc', filename)
929
1032
def llvm_nm(filename, stdout=PIPE, stderr=None):
930
1033
if filename in Building.nm_cache:
931
#if DEBUG: print >> sys.stderr, 'loading nm results for %s from cache' % filename
1034
#logging.debug('loading nm results for %s from cache' % filename)
932
1035
return Building.nm_cache[filename]
934
1037
# LLVM binary ==> list of symbols
1002
1105
def get_safe_internalize():
1003
exports = ','.join(map(lambda exp: exp[1:], Settings.EXPORTED_FUNCTIONS))
1106
exports = ','.join(map(lambda exp: exp[1:], expand_response(Settings.EXPORTED_FUNCTIONS)))
1004
1107
# internalize carefully, llvm 3.2 will remove even main if not told not to
1005
1108
return ['-internalize', '-internalize-public-api-list=' + exports]
1111
1214
return js_optimizer.run(filename, passes, listify(NODE_JS), jcache)
1114
def closure_compiler(filename):
1217
def closure_compiler(filename, pretty=True):
1115
1218
if not os.path.exists(CLOSURE_COMPILER):
1116
1219
raise Exception('Closure compiler appears to be missing, looked at: ' + str(CLOSURE_COMPILER))
1121
1224
'-Xmx' + (os.environ.get('JAVA_HEAP_SIZE') or '1024m'), # if you need a larger Java heap, use this environment variable
1122
1225
'-jar', CLOSURE_COMPILER,
1123
1226
'--compilation_level', 'ADVANCED_OPTIMIZATIONS',
1124
'--formatting', 'PRETTY_PRINT',
1125
1227
'--language_in', 'ECMASCRIPT5',
1126
1228
#'--variable_map_output_file', filename + '.vars',
1127
1229
'--js', filename, '--js_output_file', filename + '.cc.js']
1230
if pretty: args += ['--formatting', 'PRETTY_PRINT']
1128
1231
if os.environ.get('EMCC_CLOSURE_ARGS'):
1129
1232
args += shlex.split(os.environ.get('EMCC_CLOSURE_ARGS'))
1130
1233
process = Popen(args, stdout=PIPE, stderr=STDOUT)
1175
1278
curr = os.getcwd()
1178
print >> sys.stderr, '======================================='
1179
print >> sys.stderr, 'bootstrapping relooper...'
1281
logging.info('=======================================')
1282
logging.info('bootstrapping relooper...')
1180
1283
os.chdir(path_from_root('src'))
1182
1285
emcc_debug = os.environ.get('EMCC_DEBUG')
1203
1306
# bootstrap phase 1: generate unrelooped relooper, for which we do not need a relooper (so we cannot recurse infinitely in this function)
1204
print >> sys.stderr, ' bootstrap phase 1'
1307
logging.info(' bootstrap phase 1')
1206
1309
# bootstrap phase 2: generate relooped relooper, using the unrelooped relooper (we see relooper.js exists so we cannot recurse infinitely in this function)
1207
print >> sys.stderr, ' bootstrap phase 2'
1310
logging.info(' bootstrap phase 2')
1209
print >> sys.stderr, 'bootstrapping relooper succeeded'
1210
print >> sys.stderr, '======================================='
1312
logging.info('bootstrapping relooper succeeded')
1313
logging.info('=======================================')
1214
1317
if emcc_debug: os.environ['EMCC_DEBUG'] = emcc_debug
1216
print >> sys.stderr, 'bootstrapping relooper failed. You may need to manually create relooper.js by compiling it, see src/relooper/emscripten'
1319
logging.error('bootstrapping relooper failed. You may need to manually create relooper.js by compiling it, see src/relooper/emscripten')