aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-11-10 14:37:15 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-11-10 14:37:15 -0800
commitacbf809a3ce0e2f3a3915dc00065ff5e0b20b58f (patch)
tree34ea3cdec03476a29944dfc0a23c9829c4022442
parentf3d23fb5ee8362586c7e986e1d27039fb3a1756b (diff)
bootstrap relooperautomatically
-rwxr-xr-xemscripten.py2
-rwxr-xr-xtests/runner.py20
-rw-r--r--tools/shared.py58
3 files changed, 78 insertions, 2 deletions
diff --git a/emscripten.py b/emscripten.py
index 75167a29..e7321903 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -294,6 +294,8 @@ def main(args):
libraries = args.libraries[0].split(',') if len(args.libraries) > 0 else []
# Compile the assembly to Javascript.
+ if settings.get('RELOOP'): shared.Building.ensure_relooper()
+
emscript(args.infile, settings, args.outfile, libraries)
if __name__ == '__main__':
diff --git a/tests/runner.py b/tests/runner.py
index 413aa804..f965ffb1 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -10141,6 +10141,26 @@ fi
assert ERASING_MESSAGE in output
assert not os.path.exists(EMCC_CACHE)
+ def test_relooper(self):
+ restore()
+ for phase in range(2): # 0: we wipe the relooper dir. 1: we have it, so should just update
+ if phase == 0: Cache.erase()
+ try_delete(RELOOPER)
+
+ for i in range(4):
+ print phase, i
+ opt = min(i, 2)
+ try_delete('a.out.js')
+ output = Popen(['python', EMCC, path_from_root('tests', 'hello_world_loop.cpp'), '-O' + str(opt), '--closure', '0'],
+ stdout=PIPE, stderr=PIPE).communicate()
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ output = '\n'.join(output)
+ assert ('bootstrapping relooper succeeded' in output) == (i == 2), 'only bootstrap on first O2: ' + output
+ assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output
+ assert (' checking out' in output) == (i == 2 and phase == 0), 'check out the code on first O2, and if no dir already present: ' + output
+ assert (' updating' in output) == (i == 2 and phase == 1), 'when have relooper dir, just update: ' + output
+ assert ('L2 : do {' in open('a.out.js').read()) == (i >= 2), 'reloop code on O2: ' + output
+
else:
raise Exception('Test runner is confused: ' + str(sys.argv))
diff --git a/tools/shared.py b/tools/shared.py
index ae6c5eb5..530d2af5 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -207,6 +207,7 @@ AUTODEBUGGER = path_from_root('tools', 'autodebugger.py')
BINDINGS_GENERATOR = path_from_root('tools', 'bindings_generator.py')
EXEC_LLVM = path_from_root('tools', 'exec_llvm.py')
FILE_PACKAGER = path_from_root('tools', 'file_packager.py')
+RELOOPER = path_from_root('src', 'relooper.js')
# Temp dir. Create a random one, unless EMCC_DEBUG is set, in which case use TEMP_DIR/emscripten_temp
@@ -1011,6 +1012,54 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e
return False
+ # Make sure the relooper exists. If it does not, check out the relooper code and bootstrap it
+ @staticmethod
+ def ensure_relooper():
+ if os.path.exists(RELOOPER): return
+ try:
+ ok = False
+ print >> sys.stderr, '======================================='
+ print >> sys.stderr, 'bootstrapping relooper...'
+ Cache.ensure()
+ RELOOPER_DIR = os.path.join(Cache.dirname, 'relooper')
+ currdir = os.getcwd()
+ if not os.path.exists(RELOOPER_DIR):
+ # check out relooper
+ os.chdir(os.path.dirname(RELOOPER_DIR))
+ print >> sys.stderr, ' checking out', os.getcwd()
+ execute(['git', 'clone', 'git://github.com/kripken/Relooper.git', os.path.basename(RELOOPER_DIR)])
+ assert os.path.exists(RELOOPER_DIR)
+ else:
+ # update
+ print >> sys.stderr, ' updating'
+ os.chdir(RELOOPER_DIR)
+ execute(['git', 'pull', '-u'], stdout=None if DEBUG else PIPE, stderr=None if DEBUG else PIPE)
+
+ def make(opt_level):
+ raw = RELOOPER + '.raw.js'
+ Building.emcc(os.path.join(RELOOPER_DIR, 'Relooper.cpp'), ['-I' + os.path.join(RELOOPER_DIR), '--post-js', os.path.join(RELOOPER_DIR, 'emscripten', 'glue.js'), '-s', 'TOTAL_MEMORY=52428800', '-s', 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=["memcpy", "memset", "malloc", "free", "puts"]', '-O' + str(opt_level)], raw)
+ f = open(RELOOPER, 'w')
+ f.write("// Relooper, (C) 2012 Alon Zakai, MIT license, https://github.com/kripken/Relooper\n")
+ f.write("var Relooper = (function() {\n");
+ f.write(open(raw).read())
+ f.write('\n return Module.Relooper;\n')
+ f.write('})();\n')
+ 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'
+ 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'
+ make(2)
+ print >> sys.stderr, 'bootstrapping relooper succeeded'
+ print >> sys.stderr, '======================================='
+ ok = True
+ finally:
+ os.chdir(currdir)
+ if not ok:
+ print >> sys.stderr, 'bootstrapping relooper failed. You may need to manually create src/relooper.js, by checking out the Relooper project ( https://github.com/kripken/Relooper ) and building in the emscripten/ dir.'
+
# Permanent cache for dlmalloc and stdlibc++
class Cache:
dirname = os.environ.get('EM_CACHE')
@@ -1018,11 +1067,17 @@ class Cache:
dirname = os.path.expanduser(os.path.join('~', '.emscripten_cache'))
@staticmethod
+ def ensure():
+ if not os.path.exists(Cache.dirname):
+ os.makedirs(Cache.dirname)
+
+ @staticmethod
def erase():
try:
shutil.rmtree(Cache.dirname)
except:
pass
+ try_delete(RELOOPER)
# Request a cached file. If it isn't in the cache, it will be created with
# the given creator function
@@ -1032,8 +1087,7 @@ class Cache:
cachename = os.path.join(Cache.dirname, shortname)
if os.path.exists(cachename):
return cachename
- if not os.path.exists(Cache.dirname):
- os.makedirs(Cache.dirname)
+ Cache.ensure()
shutil.copyfile(creator(), cachename)
return cachename