import shutil, time, os, sys, json, tempfile, copy, shlex, atexit, subprocess
from subprocess import Popen, PIPE, STDOUT
from tempfile import mkstemp
# A helper class that is used on Windows to represent the subprocess object that is the return value of Popen.
class MockPopen:
def __init__(self, stdout, stderr, returncode):
self.returncode = returncode
self.output = (stdout, stderr)
def communicate(self):
return self.output
# On Windows python suffers from a particularly nasty bug if python is spawning new processes while python itself is spawned from some other non-console process.
# Use a custom replacement for Popen on Windows to avoid the "WindowsError: [Error 6] The handle is invalid" errors when emcc is driven through cmake or mingw32-make.
# See http://bugs.python.org/issue3905
def call_process(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False,
shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0):
# (stdin, stdout, stderr) store what the caller originally wanted to be done with the streams.
# (stdin_, stdout_, stderr_) will store the fixed set of streams that workaround the bug.
stdin_ = stdin
stdout_ = stdout
stderr_ = stderr
# If the caller wants one of these PIPEd, we must PIPE them all to avoid the 'handle is invalid' bug.
if stdin_ == PIPE or stdout_ == PIPE or stderr_ == PIPE:
if stdin_ == None:
stdin_ = PIPE
if stdout_ == None:
stdout_ = PIPE
if stderr_ == None:
stderr_ = PIPE
# Call the process with fixed streams.
process = subprocess.Popen(args, bufsize, executable, stdin_, stdout_, stderr_, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags)
output = process.communicate()
# If caller never wanted to PIPE stdout or stderr, route the output back to screen to avoid swallowing output.
if stdout == None and stdout_ == PIPE:
print >> sys.stdout, output[0]
if stderr == None and stderr_ == PIPE:
print >> sys.stderr, output[1]
# Return a mock object to the caller. This works as long as all emscripten code immediately .communicate()s the result, and doesn't
# leave the process object around for longer/more exotic uses.
if stdout == None and stderr == None:
return MockPopen(None, None, process.returncode)
if stdout == None:
return MockPopen(None, output[1], process.returncode)
if stderr == None:
return MockPopen(output[0], None, process.returncode)
return MockPopen(output[0], output[1], process.returncode)
# Install our replacement Popen handler if we are running on Windows to avoid python spawn process function.
if os.name == 'nt':
Popen = call_process
import js_optimizer
__rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def path_from_root(*pathelems):
return os.path.join(__rootpath__, *pathelems)
# 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
# Emscripten. Otherwise, the string is understood to be a path to a settings
# file that contains the required definitions.
EM_CONFIG = os.environ.get('EM_CONFIG')
if not EM_CONFIG:
EM_CONFIG = '~/.emscripten'
if '\n' in EM_CONFIG:
CONFIG_FILE = None
else:
CONFIG_FILE = os.path.expanduser(EM_CONFIG)
if not os.path.exists(CONFIG_FILE):
config_file = open(path_from_root('tools', 'settings_template_readonly.py')).read().split('\n')
config_file = config_file[1:] # remove "this file will be copied..."
config_file = '\n'.join(config_file)
# autodetect some default paths
config_file = config_file.replace('{{{ EMSCRIPTEN_ROOT }}}', __rootpath__)
llvm_root = '/usr/bin'
try:
llvm_root = os.path.dirname(Popen(['which', 'clang'], stdout=PIPE).communicate()[0].replace('\n', ''))
except:
pass
config_file