diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-11-10 14:37:15 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-11-10 14:37:15 -0800 |
commit | acbf809a3ce0e2f3a3915dc00065ff5e0b20b58f (patch) | |
tree | 34ea3cdec03476a29944dfc0a23c9829c4022442 | |
parent | f3d23fb5ee8362586c7e986e1d27039fb3a1756b (diff) |
bootstrap relooperautomatically
-rwxr-xr-x | emscripten.py | 2 | ||||
-rwxr-xr-x | tests/runner.py | 20 | ||||
-rw-r--r-- | tools/shared.py | 58 |
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 |