aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemscripten.py10
-rw-r--r--tests/runner.py65
-rw-r--r--tests/settings.py13
-rw-r--r--third_party/demangler.py9
-rwxr-xr-xtools/emmaken.py146
-rw-r--r--tools/shared.py23
6 files changed, 216 insertions, 50 deletions
diff --git a/emscripten.py b/emscripten.py
index a0351ab7..7a92455c 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -2,12 +2,14 @@
import os, sys, subprocess
-COMPILER = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'src', 'compiler.js')
-CONFIG_FILE = os.path.expanduser('~/.emscripten')
JS_ENGINE = None
-if os.path.exists(CONFIG_FILE):
- exec(open(CONFIG_FILE, 'r').read())
+abspath = os.path.abspath(os.path.dirname(__file__))
+def path_from_root(*pathelems):
+ return os.path.join(os.path.sep, *(abspath.split(os.sep) + list(pathelems)))
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
+
+COMPILER = path_from_root('src', 'compiler.js')
def emscripten(filename, settings):
data = open(filename, 'r').read()
diff --git a/tests/runner.py b/tests/runner.py
index 27f93224..86647fbb 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -7,25 +7,25 @@ See settings.py file for options&params. Edit as needed.
from subprocess import Popen, PIPE, STDOUT
import os, unittest, tempfile, shutil, time, inspect, sys, math, glob
-# Params
+# Setup
abspath = os.path.abspath(os.path.dirname(__file__))
-def path_from_root(pathelems):
- return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + pathelems))
+def path_from_root(*pathelems):
+ return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems)))
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
-EMSCRIPTEN = path_from_root(['emscripten.py'])
+# Sanity check for config
-exec(open(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'settings.py'), 'r').read())
+try:
+ assert COMPILERS != None
+except:
+ raise Exception('Cannot find "COMPILERS" definition. Is ~/.emscripten set up properly? You may need to copy the template at ~/tests/settings.py into it.')
-def timeout_run(proc, timeout, note):
- start = time.time()
- if timeout is not None:
- while time.time() - start < timeout and proc.poll() is None:
- time.sleep(0.1)
- if proc.poll() is None:
- proc.kill() # XXX bug: killing emscripten.py does not kill it's child process!
- raise Exception("Timed out: " + note)
- return proc.communicate()[0]
+# Paths
+
+EMSCRIPTEN = path_from_root('emscripten.py')
+DEMANGLER = path_from_root('third_party', 'demangler.py')
+NAMESPACER = path_from_root('tools', 'namespacer.py')
class RunnerCore(unittest.TestCase):
def get_dir(self):
@@ -106,7 +106,7 @@ class RunnerCore(unittest.TestCase):
shutil.move(os.path.join(dirname, main_file), filename)
# Copy Emscripten C++ API
- shutil.copy(path_from_root(['src', 'include', 'emscripten.h']), dirname)
+ shutil.copy(path_from_root('src', 'include', 'emscripten.h'), dirname)
# C++ => LLVM binary
try:
@@ -1288,25 +1288,25 @@ if 'benchmark' not in sys.argv:
def test_fannkuch(self):
results = [ (1,0), (2,1), (3,2), (4,4), (5,7), (6,10), (7, 16), (8,22) ]
for i, j in results:
- src = open(path_from_root(['tests', 'fannkuch.cpp']), 'r').read()
+ src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read()
self.do_test(src, 'Pfannkuchen(%d) = %d.' % (i,j), [str(i)], no_build=i>1)
def test_raytrace(self):
- src = open(path_from_root(['tests', 'raytrace.cpp']), 'r').read()
- output = open(path_from_root(['tests', 'raytrace.ppm']), 'r').read()
+ src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read()
+ output = open(path_from_root('tests', 'raytrace.ppm'), 'r').read()
self.do_test(src, output, ['3', '16'])
def test_dlmalloc(self):
# XXX Warning: Running this in SpiderMonkey can lead to an extreme amount of memory being
# used, see Mozilla bug 593659.
- src = open(path_from_root(['tests', 'dlmalloc.c']), 'r').read()
+ src = open(path_from_root('tests', 'dlmalloc.c'), 'r').read()
self.do_test(src, '*1,0*')
def test_fasta(self):
results = [ (1,'''GG*ctt**tgagc*'''), (20,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tacgtgtagcctagtgtttgtgttgcgttatagtctatttgtggacacagtatggtcaaa**tgacgtcttttgatctgacggcgttaacaaagatactctg*'''),
(50,'''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA*TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT*cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg**tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa**NtactMcSMtYtcMgRtacttctWBacgaa**agatactctgggcaacacacatacttctctcatgttgtttcttcggacctttcataacct**ttcctggcacatggttagctgcacatcacaggattgtaagggtctagtggttcagtgagc**ggaatatcattcgtcggtggtgttaatctatctcggtgtagcttataaatgcatccgtaa**gaatattatgtttatttgtcggtacgttcatggtagtggtgtcgccgatttagacgtaaa**ggcatgtatg*''') ]
for i, j in results:
- src = open(path_from_root(['tests', 'fasta.cpp']), 'r').read()
+ src = open(path_from_root('tests', 'fasta.cpp'), 'r').read()
self.do_test(src, j, [str(i)], lambda x: x.replace('\n', '*'), no_build=i>1)
def zzztest_gl(self):
@@ -1323,7 +1323,7 @@ if 'benchmark' not in sys.argv:
};'''
)
open(filename, 'w').write(src)
- self.do_test(path_from_root(['tests', 'gl']), '*?*', main_file='sdl_ogl.c', post_build=post)
+ self.do_test(path_from_root('tests', 'gl'), '*?*', main_file='sdl_ogl.c', post_build=post)
def test_cubescript(self):
# XXX Warning: Running this in SpiderMonkey can lead to an extreme amount of memory being
@@ -1333,10 +1333,10 @@ if 'benchmark' not in sys.argv:
# Overflows happen in hash loop
global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- self.do_test(path_from_root(['tests', 'cubescript']), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
+ self.do_test(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
def test_gcc_unmangler(self):
- self.do_test(path_from_root(['third_party']), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
+ self.do_test(path_from_root('third_party'), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj'], main_file='gcc_demangler.c')
#### Code snippet that is helpful to search for nonportable optimizations ####
#global LLVM_OPT_OPTS
@@ -1350,13 +1350,13 @@ if 'benchmark' not in sys.argv:
def test_bullet(self):
global SAFE_HEAP; SAFE_HEAP = 0 # Too slow for that
- self.do_ll_test(path_from_root(['tests', 'bullet', 'bulletTest.ll']), open(path_from_root(['tests', 'bullet', 'output.txt']), 'r').read())
+ self.do_ll_test(path_from_root('tests', 'bullet', 'bulletTest.ll'), open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read())
def test_lua(self):
# Overflows in luaS_newlstr hash loop
global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
- self.do_ll_test(path_from_root(['tests', 'lua', 'lua.ll']),
+ self.do_ll_test(path_from_root('tests', 'lua', 'lua.ll'),
'hello lua world!\n17.00000000000\n1.00000000000\n2.00000000000\n3.00000000000\n4.00000000000\n7.00000000000',
args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
output_nicerizer=lambda string: string.replace('\n\n', '\n').replace('\n\n', '\n'))
@@ -1367,7 +1367,7 @@ if 'benchmark' not in sys.argv:
global RELOOP; RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
global SAFE_HEAP; SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness.
- self.do_ll_test(path_from_root(['tests', 'python', 'python.ll']),
+ self.do_ll_test(path_from_root('tests', 'python', 'python.ll'),
'hello python world!\n\n[0, 2, 4, 6]\n\n5\n\n22\n\n5.470',
args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''],
js_engines=[V8_ENGINE]) # script stack space exceeded in SpiderMonkey, TODO
@@ -1376,15 +1376,15 @@ if 'benchmark' not in sys.argv:
def test_cases(self):
if LLVM_OPTS: return # Our code is not exactly 'normal' llvm assembly
- for name in glob.glob(path_from_root(['tests', 'cases', '*.ll'])):
+ for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
shortname = name.replace('.ll', '')
print "Testing case '%s'..." % shortname
- output_file = path_from_root(['tests', 'cases', shortname + '.txt'])
+ output_file = path_from_root('tests', 'cases', shortname + '.txt')
if os.path.exists(output_file):
output = open(output_file, 'r').read()
else:
output = 'hello, world!'
- self.do_ll_test(path_from_root(['tests', 'cases', name]), output)
+ self.do_ll_test(path_from_root('tests', 'cases', name), output)
### Integration tests
@@ -1417,7 +1417,6 @@ if 'benchmark' not in sys.argv:
'Module["_"] = ' + open(filename + '.tmp2', 'r').read().rstrip() + ';\n\n' + script_src + '\n\n' +
'// {{MODULE_ADDITIONS}'
)
-
open(filename, 'w').write(src)
self.do_test(src, '*166*\n*ok*', post_build=post)
@@ -1598,12 +1597,12 @@ else:
self.do_benchmark(src, [], 'lastprime: 348949.')
def test_fannkuch(self):
- src = open(path_from_root(['tests', 'fannkuch.cpp']), 'r').read()
+ src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read()
self.do_benchmark(src, ['9'], 'Pfannkuchen(9) = 30.')
def test_raytrace(self):
- src = open(path_from_root(['tests', 'raytrace.cpp']), 'r').read()
- self.do_benchmark(src, ['5', '64'], open(path_from_root(['tests', 'raytrace_5_64.ppm']), 'r').read())
+ src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read()
+ self.do_benchmark(src, ['5', '64'], open(path_from_root('tests', 'raytrace_5_64.ppm'), 'r').read())
if __name__ == '__main__':
sys.argv = [sys.argv[0]] + ['-v'] + sys.argv[1:] # Verbose output by default
diff --git a/tests/settings.py b/tests/settings.py
index a52d6c6f..c2607a49 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -1,10 +1,3 @@
-# XXX: Aside from these settings, you should create ~/.emscripten, and fill it with
-# something like this:
-#
-# JS_ENGINE=[os.path.expanduser('~/Dev/tracemonkey/js/src/js'), '-m']
-# JS_ENGINE_PARAMS=[]
-#
-
TEMP_DIR='/dev/shm'
LLVM_ROOT=os.path.expanduser('~/Dev/llvm-2.8/cbuild/Release/bin') # Might not need 'Release'
@@ -43,6 +36,10 @@ V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')]
#COMPILER_ENGINE=SPIDERMONKEY_ENGINE
COMPILER_ENGINE=V8_ENGINE
+JS_ENGINE=V8_ENGINE
+JS_ENGINE_PARAMS = ['--'] # For V8
+JS_ENGINE_PARAMS = [] # For SpiderMonkey
+
OUTPUT_TO_SCREEN = 0 # useful for debugging specific tests, or for subjectively seeing what parts are slow
TIMEOUT = None
@@ -50,6 +47,4 @@ TIMEOUT = None
# Tools
CLOSURE_COMPILER = os.path.expanduser('~/Dev/closure-compiler/compiler.jar')
-DEMANGLER = path_from_root(['third_party', 'demangler.py'])
-NAMESPACER = path_from_root(['tools', 'namespacer.py'])
diff --git a/third_party/demangler.py b/third_party/demangler.py
index b9b4b1ef..f3407825 100644
--- a/third_party/demangler.py
+++ b/third_party/demangler.py
@@ -21,8 +21,10 @@ JS_ENGINE_PARAMS=[]
import os, sys, subprocess
-CONFIG_FILE = os.path.expanduser('~/.emscripten')
-exec(open(CONFIG_FILE, 'r').read())
+abspath = os.path.abspath(os.path.dirname(__file__))
+def path_from_root(*pathelems):
+ return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems)))
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
data = open(sys.argv[1], 'r').readlines()
splitter = sys.argv[2]
@@ -35,8 +37,7 @@ for line in data:
func = line.lstrip().split(splitter)[0]
if func in SEEN: continue
SEEN[func] = True
- args = JS_ENGINE + [os.path.join(os.path.dirname(__file__), 'gcc_demangler.js')] + JS_ENGINE_PARAMS + [func[1:]]
- cleaned = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()[0]
+ cleaned = run_js(JS_ENGINE, path_from_root('third_party', 'gcc_demangler.js'), [func[1:]])
if cleaned is None: continue
if 'Fatal exception' in cleaned: continue
cleaned = cleaned[1:-2]
diff --git a/tools/emmaken.py b/tools/emmaken.py
new file mode 100755
index 00000000..1b29f7a9
--- /dev/null
+++ b/tools/emmaken.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+'''
+emmaken - the emscripten make proxy tool
+========================================
+
+Tell your build system to use this instead of the compiler, linker, ar and
+ranlib. All the normal build commands will be sent to this script, which
+will proxy them to the appropriate LLVM build commands, in order to
+generate proper code for Emscripten to later process.
+
+For example, compilation will be translated into calls to llvm-gcc
+with -emit-llvm, and linking will be translated into calls to llvm-link,
+and so forth.
+
+Example uses:
+
+ * With configure, do something like
+
+ RANLIB=PATH/emmaken.py AR=PATH/emmaken.py CXX=PATH/emmaken.py CC=PATH/emmaken.py ./configure [options]
+
+ where PATH is the path to this file.
+
+ * With CMake, do something like
+
+ SET(CMAKE_C_COMPILER "PATH/emmaken.py")
+ SET(CMAKE_CXX_COMPILER "PATH/emmaken.py")
+ SET(CMAKE_LINKER "PATH/emmaken.py")
+ SET(CMAKE_CXX_LINKER "PATH/emmaken.py")
+ SET(CMAKE_C_LINK_EXECUTABLE "PATH/emmaken.py")
+ SET(CMAKE_CXX_LINK_EXECUTABLE "PATH/emmaken.py")
+ SET(CMAKE_AR "PATH/emmaken.py")
+ SET(CMAKE_RANLIB "PATH/emmaken.py")
+
+After setting that up, run your build system normally. It should generate
+LLVM instead of the normal output, and end up with .ll files that you can
+give to Emscripten. Note that this tool doesn't run Emscripten itself. Note
+also that you may need to do some manual fiddling later, for example to
+link files that weren't linked, and them llvm-dis them.
+'''
+
+import sys
+import os
+import subprocess
+
+abspath = os.path.abspath(os.path.dirname(__file__))
+def path_from_root(*pathelems):
+ return os.path.join(os.path.sep, *(abspath.split(os.sep)[:-1] + list(pathelems)))
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
+
+CONFIG_FILE = os.path.expanduser('~/.emscripten')
+assert os.path.exists(CONFIG_FILE)
+exec(open(CONFIG_FILE, 'r').read())
+
+try:
+ print >> sys.stderr, 'emmaken.py: ', ' '.join(sys.argv)
+
+ CC='/home/alon/Dev/llvm-gcc-4.2-2.8.source/cbuild/install/bin/llvm-g++'
+ CC_ARG_SKIP = ['-g', '-O1', '-O2', '-O3']
+ CC_ADDITIONAL_ARGS = ['-m32', '-U__i386__', '-U__x86_64__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87']
+
+ #CC='llvm-gcc'
+ #CC_ARG_SKIP = ['-g', '-O1', '-O2', '-O3']
+ #CC_ADDITIONAL_ARGS = ['-U__i386__', '-U__x86_64__']
+
+ LLVM_LINK = '/home/alon/Dev/llvm-2.8/cbuild/Release/bin/llvm-link'
+ LLVM_DIS = '/home/alon/Dev/llvm-2.8/cbuild/Release/bin/llvm-dis'
+ ALLOWED_LINK_ARGS = ['-f', '-help', '-o', '-print-after', '-print-after-all', '-print-before',
+ '-print-before-all', '-time-passes', '-v', '-verify-dom-info', '-version' ]
+ #LINK_ARG_SKIP = ['-pthread', '-DNDEBUG', '-g', '-O3', '-Wall', '-Wstrict-prototypes',
+ # '-lpthread', '-ldl', '-lutil', '-Xlinker', '-export-dynamic', '-lm', '-shared']
+
+ # ---------------- End configs -------------
+
+ if len(sys.argv) == 2 and 'conftest' not in ' '.join(sys.argv): # Avoid messing with configure, see below too
+ # ranlib
+ os.execvp(LLVM_DIS, ['-show-annotations', sys.argv[1]])
+ sys.exit(0)
+ if sys.argv[1] in ['x', 't']:
+ # noop ar
+ sys.exit(0)
+
+ use_linker = True
+ #use_linker = False
+
+ opts = []
+ files = []
+ for arg in sys.argv[1:]:
+ if arg.startswith('-'):
+ opts.append(arg)
+ else:
+ files.append(arg)
+ if arg.endswith(('.c', '.cc', '.cpp')):
+ use_linker = False
+
+ if '--version' in opts:
+ use_linker = False
+
+ if sys.argv[1] == 'cru': # ar
+ sys.argv = sys.argv[:1] + sys.argv[3:] + ['-o='+sys.argv[2]]
+ assert use_linker, 'Linker should be used in this case'
+
+ if use_linker:
+ call = LLVM_LINK
+ newargs = []
+ found_o = False
+ for arg in sys.argv[1:]:
+ if os.path.basename(sys.argv[0])=='arproxy.py':
+ if arg.endswith('.a'):
+ newargs.append('-o=%s' % arg)
+ elif arg.endswith('.o'):
+ newargs.append(arg)
+ else:
+ pass
+ continue
+ if found_o:
+ newargs.append('-o=%s' % arg)
+ found_o = False
+ continue
+ if arg.startswith('-'):
+ if arg == '-o':
+ found_o = True
+ continue
+ prefix = arg.split('=')[0]
+ if prefix in ALLOWED_LINK_ARGS:
+ newargs.append(arg)
+ elif arg.endswith('.so'):
+ continue # .so's do not exist yet, in many cases
+ else:
+ # not option, so just append
+ newargs.append(arg)
+ else:
+ call = CC
+ newargs = [ arg for arg in sys.argv[1:] if arg not in CC_ARG_SKIP ] + CC_ADDITIONAL_ARGS
+ if 'conftest.c' not in files:
+ newargs.append('-emit-llvm')
+ if CC=='llvm-gcc':
+ newargs.append('-c')
+
+ print >> sys.stderr, "Running:", call, ' '.join(newargs)
+
+ os.execvp(call, [call] + newargs)
+except:
+ print 'Error in emmaken.py. Is the config file ~/.emscripten set up properly?'
+ raise
+
diff --git a/tools/shared.py b/tools/shared.py
new file mode 100644
index 00000000..f6594af2
--- /dev/null
+++ b/tools/shared.py
@@ -0,0 +1,23 @@
+
+import shutil, time
+from subprocess import Popen, PIPE, STDOUT
+
+CONFIG_FILE = os.path.expanduser('~/.emscripten')
+if not os.path.exists(CONFIG_FILE):
+ shutil.copy(path_from_root('tests', 'settings.py'), CONFIG_FILE)
+exec(open(CONFIG_FILE, 'r').read())
+
+def timeout_run(proc, timeout, note):
+ start = time.time()
+ if timeout is not None:
+ while time.time() - start < timeout and proc.poll() is None:
+ time.sleep(0.1)
+ if proc.poll() is None:
+ proc.kill() # XXX bug: killing emscripten.py does not kill it's child process!
+ raise Exception("Timed out: " + note)
+ return proc.communicate()[0]
+
+def run_js(engine, filename, args, check_timeout=False):
+ return timeout_run(Popen(engine + [filename] + (['--'] if 'v8' in engine[0] else []) + args,
+ stdout=PIPE, stderr=STDOUT), 120 if check_timeout else None, 'Execution')
+