aboutsummaryrefslogtreecommitdiff
path: root/tests/runner.py
diff options
context:
space:
mode:
authorEhsan Akhgari <ehsan.akhgari@gmail.com>2012-01-27 15:02:10 -0500
committerEhsan Akhgari <ehsan.akhgari@gmail.com>2012-01-27 15:02:10 -0500
commit65febb8bf9e70ebacc252f75374c5c291befa6de (patch)
tree12f601f70cef7844d3212b10b9505953e8d62120 /tests/runner.py
parent58d80ab53ea7c71b6e7dd0e56bee1335514a59f6 (diff)
parentfff86540c3c5147e745a038bffad034ea1058d22 (diff)
Merge branch 'handle_broken_lli' into glgears
Conflicts: src/preamble.js
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-xtests/runner.py306
1 files changed, 200 insertions, 106 deletions
diff --git a/tests/runner.py b/tests/runner.py
index b214c202..a824d089 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -14,7 +14,7 @@ will use 4 processes. To install nose do something like
'''
from subprocess import Popen, PIPE, STDOUT
-import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser
+import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib
# Setup
@@ -126,12 +126,18 @@ process(sys.argv[1])
# Build JavaScript code from source code
def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[], post_build=None):
+ Building.pick_llvm_opts(3, safe=Building.LLVM_OPTS != 2) # pick llvm opts here, so we include changes to Settings in the test case code
+
# Copy over necessary files for compiling the source
if main_file is None:
f = open(filename, 'w')
f.write(src)
f.close()
- assert len(additional_files) == 0
+ final_additional_files = []
+ for f in additional_files:
+ final_additional_files.append(os.path.join(dirname, os.path.basename(f)))
+ shutil.copyfile(f, final_additional_files[-1])
+ additional_files = final_additional_files
else:
# copy whole directory, and use a specific main .cpp file
shutil.rmtree(dirname)
@@ -139,10 +145,9 @@ process(sys.argv[1])
shutil.move(os.path.join(dirname, main_file), filename)
# the additional files were copied; alter additional_files to point to their full paths now
additional_files = map(lambda f: os.path.join(dirname, f), additional_files)
+ os.chdir(self.get_dir())
# C++ => LLVM binary
- os.chdir(dirname)
- cwd = os.getcwd()
for f in [filename] + additional_files:
try:
@@ -157,8 +162,6 @@ process(sys.argv[1])
output = Popen(args, stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
assert os.path.exists(f + '.o'), 'Source compilation error: ' + output
- os.chdir(cwd)
-
# Link all files
if len(additional_files) + len(libraries) > 0:
shutil.move(filename + '.o', filename + '.o.alone')
@@ -192,9 +195,6 @@ process(sys.argv[1])
assert 'strict warning:' not in ret, 'We should pass all strict mode checks: ' + ret
return ret
- def run_llvm_interpreter(self, args):
- return Popen([EXEC_LLVM] + args, stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
-
def build_native(self, filename):
Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE).communicate()[0]
@@ -254,6 +254,8 @@ process(sys.argv[1])
sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
+Cache.erase() # Wipe the cache, so that we always test populating it in the tests, benchmarks, etc.
+
if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
# Tests
@@ -261,7 +263,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
## Does a complete test - builds, runs, checks output, etc.
- def do_run(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
+ def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
if force_c or (main_file is not None and main_file[-2:]) == '.c':
basename = 'src.c'
Building.COMPILER = to_cc(Building.COMPILER)
@@ -272,11 +274,6 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
- # If not provided with expected output, then generate it right now, using lli
- if expected_output is None:
- expected_output = self.run_llvm_interpreter([filename + '.o'])
- print '[autogenerated expected output: %20s]' % (expected_output[0:30].replace('\n', '|')+'...')
-
# Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
if js_engines is None:
js_engines = JS_ENGINES
@@ -651,7 +648,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
return 0;
}
'''
- self.do_run(src)#, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*')
+ self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*')
# Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires
# corrections otherwise
@@ -865,7 +862,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
}
'''
- self.do_run(src)
+ self.do_run(src, '*1800*')
generated = open('src.cpp.o.js', 'r').read()
assert '__label__ ==' not in generated, 'We should hoist into the loop'
@@ -1174,8 +1171,13 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, 'Assertion failed: 1 == false')
def test_exceptions(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
+
self.banned_js_engines = [NODE_JS] # node issue 1669, exception causes stdout not to be flushed
Settings.DISABLE_EXCEPTION_CATCHING = 0
+ if self.emcc_args is None:
+ if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion')
+ self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc
src = '''
#include <stdio.h>
@@ -2354,7 +2356,10 @@ def process(filename):
return 0;
}
'''
- self.do_run(src)
+ def check(result):
+ return hashlib.sha1(result).hexdigest()
+ self.do_run(src, '6c9cdfe937383b79e52ca7a2cce83a21d9f5422c',
+ output_nicerizer = check)
def test_memmove(self):
src = '''
@@ -2367,7 +2372,7 @@ def process(filename):
return 0;
}
'''
- self.do_run(src)
+ self.do_run(src, 'memmove can be very very useful')
def test_bsearch(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1')
@@ -2502,6 +2507,9 @@ def process(filename):
def test_runtimelink(self):
if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts')
+
+ Settings.LINKABLE = 1
+
self.banned_js_engines = [NODE_JS] # node's global scope behaves differently than everything else, needs investigation FIXME
header = r'''
@@ -2562,6 +2570,8 @@ def process(filename):
self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.')
def test_dlfcn_basic(self):
+ Settings.LINKABLE = 1
+
lib_src = '''
#include <cstdio>
@@ -2611,6 +2621,8 @@ def process(filename):
post_build=add_pre_run_and_checks)
def test_dlfcn_qsort(self):
+ Settings.LINKABLE = 1
+
if Settings.USE_TYPED_ARRAYS == 2:
Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations
@@ -2703,6 +2715,8 @@ def process(filename):
def test_dlfcn_data_and_fptr(self):
if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func')
+ Settings.LINKABLE = 1
+
lib_src = '''
#include <stdio.h>
@@ -2801,6 +2815,8 @@ def process(filename):
post_build=add_pre_run_and_checks)
def test_dlfcn_alias(self):
+ Settings.LINKABLE = 1
+
if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize away stuff we expect from the shared library')
lib_src = r'''
@@ -2853,6 +2869,8 @@ def process(filename):
Settings.INCLUDE_FULL_LIBRARY = 0
def test_dlfcn_varargs(self):
+ Settings.LINKABLE = 1
+
if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize things that prevent shared objects from working')
if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this')
@@ -3130,21 +3148,21 @@ at function.:blag
#include <stdlib.h>
int main () {
- printf("%d\n", atoi(""));
- printf("%d\n", atoi("a"));
- printf("%d\n", atoi(" b"));
- printf("%d\n", atoi(" c "));
- printf("%d\n", atoi("6"));
- printf("%d\n", atoi(" 5"));
- printf("%d\n", atoi("4 "));
- printf("%d\n", atoi("3 6"));
- printf("%d\n", atoi(" 3 7"));
- printf("%d\n", atoi("9 d"));
+ printf("%d*", atoi(""));
+ printf("%d*", atoi("a"));
+ printf("%d*", atoi(" b"));
+ printf("%d*", atoi(" c "));
+ printf("%d*", atoi("6"));
+ printf("%d*", atoi(" 5"));
+ printf("%d*", atoi("4 "));
+ printf("%d*", atoi("3 6"));
+ printf("%d*", atoi(" 3 7"));
+ printf("%d*", atoi("9 d"));
printf("%d\n", atoi(" 8 e"));
return 0;
}
'''
- self.do_run(src)
+ self.do_run(src, '0*0*0*0*6*5*4*3*3*9*8')
def test_sscanf(self):
src = r'''
@@ -3170,7 +3188,8 @@ at function.:blag
return 0;
}
'''
- self.do_run(src)
+ self.do_run(src, 'en-us : 2*en-r : 99*en : 3*1.234567, 0.000000',
+ output_nicerizer = lambda x: x.replace('\n', '*'))
# Part 2: doubles (issue 148)
if Settings.USE_TYPED_ARRAYS == 2:
@@ -3221,7 +3240,11 @@ Pass: 123456.789063 123456.789063
Pass: 0.000012 0.000012
Pass: 0.000012 0.000012''')
else:
- self.do_run(src)
+ self.do_run(src, '''Pass: 1.234568 1.234568
+Pass: 123456.789000 123456.789000
+Pass: 123456.789000 123456.789000
+Pass: 0.000012 0.000012
+Pass: 0.000012 0.000012''')
def test_langinfo(self):
src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
@@ -3834,9 +3857,40 @@ def process(filename):
self.do_run(src, expected)
CORRECT_SIGNS = 0
+ def test_atomic(self):
+ src = '''
+ #include <stdio.h>
+ int main() {
+ int x = 10;
+ int y = __sync_add_and_fetch(&x, 5);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_fetch_and_add(&x, 5);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_lock_test_and_set(&x, 6);
+ printf("*%d,%d*\\n", x, y);
+ x = 10;
+ y = __sync_bool_compare_and_swap(&x, 9, 7);
+ printf("*%d,%d*\\n", x, y);
+ y = __sync_bool_compare_and_swap(&x, 10, 7);
+ printf("*%d,%d*\\n", x, y);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*15,15*\n*15,10*\n*6,10*\n*10,0*\n*7,1*')
+
# libc++ tests
def test_iostream(self):
+ if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
+
+ if self.emcc_args is None:
+ if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion')
+ self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc
+ Settings.SAFE_HEAP = 0 # Some spurious warnings from libc++ internals
+
src = '''
#include <iostream>
@@ -3847,7 +3901,8 @@ def process(filename):
}
'''
- self.do_run(src, 'hello world\n77.\n')
+ # FIXME: should not have so many newlines in output here
+ self.do_run(src, 'hello world\n\n77.\n')
def test_stdvec(self):
src = '''
@@ -3907,11 +3962,13 @@ def process(filename):
self.do_run(src, j, [str(i)], lambda x: x.replace('\n', '*'), no_build=i>1)
def test_dlmalloc(self):
+ if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc
+
Settings.CORRECT_SIGNS = 2
Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]
Settings.TOTAL_MEMORY = 100*1024*1024 # needed with typed arrays
- src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
+ src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
self.do_run(src, '*1,0*', ['200', '1'])
self.do_run(src, '*400,0*', ['400', '400'], no_build=True)
@@ -3942,13 +3999,9 @@ def process(filename):
self.do_run(src.replace('{{{ NEW }}}', new).replace('{{{ DELETE }}}', delete), '*1,0*')
def test_libcxx(self):
- self.do_run(path_from_root('tests', 'libcxx'),
- 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march',
- main_file='main.cpp', additional_files=['hash.cpp'])
+ self.do_run(open(path_from_root('tests', 'hashtest.cpp')).read(),
+ 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march')
- # This will fail without using libcxx, as libstdc++ (gnu c++ lib) will use but not link in
- # __ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_
- # So a way to avoid that problem is to include libcxx, as done here
self.do_run('''
#include <set>
#include <stdio.h>
@@ -3958,7 +4011,7 @@ def process(filename):
printf("hello world\\n");
return 1;
}
- ''', 'hello world', includes=[path_from_root('tests', 'libcxx', 'include')]);
+ ''', 'hello world');
def test_static_variable(self):
Settings.SAFE_HEAP = 0 # LLVM mixes i64 and i8 in the guard check
@@ -4079,7 +4132,7 @@ def process(filename):
def get_freetype(self):
Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary
- return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a.bc'))
+ return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a'))
def test_freetype(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix')
@@ -4109,6 +4162,7 @@ def process(filename):
def test_sqlite(self):
# gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
+ if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc')
if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
pgo_data = read_pgo_data(path_from_root('tests', 'sqlite', 'sqlite-autooptimize.fails.txt'))
@@ -4146,7 +4200,6 @@ def process(filename):
open(path_from_root('tests', 'sqlite', 'benchmark.txt'), 'r').read(),
includes=[path_from_root('tests', 'sqlite')],
force_c=True,
- extra_emscripten_args=['-m'],
js_engines=[SPIDERMONKEY_ENGINE], # V8 is slow
post_build=post)#,build_ll_hook=self.do_autodebug)
@@ -4158,7 +4211,7 @@ def process(filename):
self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
- libraries=[self.get_library('zlib', os.path.join('libz.a.bc'), make_args=['libz.a'])],
+ libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])],
includes=[path_from_root('tests', 'zlib')],
force_c=True)
@@ -4175,9 +4228,9 @@ def process(filename):
self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
[open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read()],
- libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a.bc'),
- os.path.join('src', '.libs', 'libBulletDynamics.a.bc'),
- os.path.join('src', '.libs', 'libLinearMath.a.bc')],
+ libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a'),
+ os.path.join('src', '.libs', 'libBulletDynamics.a'),
+ os.path.join('src', '.libs', 'libLinearMath.a')],
configure_args=['--disable-demos','--disable-dependency-tracking'])],
includes=[path_from_root('tests', 'bullet', 'src')],
js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407
@@ -4223,9 +4276,9 @@ def process(filename):
poppler = self.get_library('poppler',
[os.path.join('poppler', '.libs', 'libpoppler.so.13.0.0'),
- os.path.join('goo', '.libs', 'libgoo.a.bc'),
- os.path.join('fofi', '.libs', 'libfofi.a.bc'),
- os.path.join('splash', '.libs', 'libsplash.a.bc'),
+ os.path.join('goo', '.libs', 'libgoo.a'),
+ os.path.join('fofi', '.libs', 'libfofi.a'),
+ os.path.join('splash', '.libs', 'libsplash.a'),
os.path.join('utils', 'pdftoppm.o'),
os.path.join('utils', 'parseargs.o')],
configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms'])
@@ -4336,8 +4389,7 @@ def process(filename):
self.do_ll_run(path_from_root('tests', 'python', 'python.ll'),
'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
- 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'''],
- extra_emscripten_args=['-m'])
+ 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'''])
# Test cases in separate files. Note that these files may contain invalid .ll!
# They are only valid enough for us to read for test purposes, not for llvm-as
@@ -4405,7 +4457,28 @@ def process(filename):
self.do_autodebug(filename)
# Compare to each other, and to expected output
- self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll'))
+ self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll'), '''AD:-1,15
+AD:15,0
+AD:21,5
+AD:24,6
+AD:27,101
+AD:30,7009
+AD:37,5
+AD:40,10
+AD:45,7009
+AD:48,7008
+AD:54,7008
+AD:57,7018
+AD:60,10
+AD:63,6
+AD:66,101
+AD:69,7018
+AD:73,101
+AD:77,7018
+AD:81,101
+AD:85,7018
+*10,6,101,7018,101,7018,101,7018*''')
+ assert open('stdout').read().startswith('AD:-1'), 'We must note when we enter functions'
# Test using build_ll_hook
src = '''
@@ -4423,30 +4496,17 @@ def process(filename):
return 0;
}
'''
- self.do_run(src, build_ll_hook=self.do_autodebug)
- self.do_run(src, 'AD:', build_ll_hook=self.do_autodebug)
-
- def test_dfe(self):
- def hook(filename):
- ll = open(filename + '.o.ll').read()
- assert 'unneeded' not in ll, 'DFE should remove the unneeded function'
-
- src = '''
- #include <stdio.h>
-
- void unneeded()
- {
- printf("some totally useless stuff\\n");
- }
-
- int main()
- {
- printf("*hello slim world*\\n");
- return 0;
- }
- '''
- # Using build_ll_hook forces a recompile, which leads to DFE being done even without opts
- self.do_run(src, '*hello slim world*', build_ll_hook=hook)
+ self.do_run(src, '''AD:-1,13
+AD:13,0
+AD:16,25
+AD:20,51
+AD:23,25
+AD:26,25
+AD:29,11.520000
+AD:31,25
+AD:33,51
+AD:36,11.520000
+*25,51,11.52*''', build_ll_hook=self.do_autodebug)
def test_profiling(self):
src = '''
@@ -4981,26 +5041,6 @@ def process(filename):
# This test *should* fail
assert 'Assertion failed' in str(e), str(e)
- def test_autoassemble(self):
- src = r'''
- #include <stdio.h>
-
- int main() {
- puts("test\n");
- return 0;
- }
- '''
- dirname = self.get_dir()
- filename = os.path.join(dirname, 'src.cpp')
- self.build(src, dirname, filename)
-
- new_filename = os.path.join(dirname, 'new.bc')
- shutil.copy(filename + '.o', new_filename)
- Building.emscripten(new_filename, append_ext=False)
-
- shutil.copy(filename + '.o.js', os.path.join(self.get_dir(), 'new.cpp.o.js'))
- self.do_run(None, 'test\n', basename='new.cpp', no_build=True)
-
def test_linespecific(self):
Settings.CHECK_SIGNS = 0
Settings.CHECK_OVERFLOWS = 0
@@ -5361,10 +5401,16 @@ Options that are modified or new in %s include:
for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'js']]:
target = args[1] if len(args) == 2 else 'hello_world.o'
clear()
- output = Popen([compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ Popen([compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate()
+ syms = Building.llvm_nm(target)
+ assert len(syms.defs) == 1 and 'main' in syms.defs, 'Failed to generate valid bitcode'
+ if target == 'js': # make sure emcc can recognize the target as a bitcode file
+ shutil.move(target, target + '.bc')
+ target += '.bc'
+ output = Popen([compiler, target, '-o', target + '.js'], stdout = PIPE, stderr = PIPE).communicate()
assert len(output[0]) == 0, output[0]
- assert os.path.exists(target), 'Expected %s to exist since args are %s : %s' % (target, str(args), '\n'.join(output))
- self.assertContained('hello, world!', self.run_llvm_interpreter([target]))
+ assert os.path.exists(target + '.js'), 'Expected %s to exist since args are %s : %s' % (target + '.js', str(args), '\n'.join(output))
+ self.assertContained('hello, world!', run_js(target + '.js'))
# emcc src.ll ==> generates .js
clear()
@@ -5509,8 +5555,12 @@ Options that are modified or new in %s include:
try_delete(target)
assert not os.path.exists(target)
output = Popen([compiler, 'twopart_main.o', 'twopart_side.o', '-o', 'combined.bc'] + args, stdout=PIPE, stderr=PIPE).communicate()
- assert os.path.exists('combined.bc'), '\n'.join(output)
- self.assertContained('side got: hello from main, over', self.run_llvm_interpreter(['combined.bc']))
+ syms = Building.llvm_nm('combined.bc')
+ assert len(syms.defs) == 2 and 'main' in syms.defs, 'Failed to generate valid bitcode'
+ output = Popen([compiler, 'combined.bc', '-o', 'combined.bc.js'], stdout = PIPE, stderr = PIPE).communicate()
+ assert len(output[0]) == 0, output[0]
+ assert os.path.exists('combined.bc.js'), 'Expected %s to exist' % ('combined.bc.js')
+ self.assertContained('side got: hello from main, over', run_js('combined.bc.js'))
# --js-transform <transform>
clear()
@@ -5859,7 +5909,7 @@ elif 'benchmark' in str(sys.argv):
def test_dlmalloc(self):
# XXX This seems to have regressed slightly with emcc. Are -g and the signs lines passed properly?
- src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
+ src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read()
self.do_benchmark(src, ['400', '400'], '*400,0*', emcc_args=['-g', '-s', 'CORRECT_SIGNS=2', '-s', 'CORRECT_SIGNS_LINES=[4820, 4195, 4250, 4203, 4209, 4239, 4231]'])
elif 'sanity' in str(sys.argv):
@@ -5887,6 +5937,9 @@ elif 'sanity' in str(sys.argv):
commands = [[EMCC], ['python', path_from_root('tests', 'runner.py'), 'blahblah']]
+ def mtime(filename):
+ return os.stat(filename).st_mtime
+
class sanity(RunnerCore):
def setUp(self):
wipe()
@@ -5974,9 +6027,6 @@ elif 'sanity' in str(sys.argv):
assert os.path.exists('a.out.js')
def test_emcc(self):
- def mtime(filename):
- return os.stat(filename).st_mtime
-
SANITY_MESSAGE = 'Emscripten: Running sanity checks'
SANITY_FAIL_MESSAGE = 'sanity check failed to run'
@@ -6014,6 +6064,50 @@ elif 'sanity' in str(sys.argv):
assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
self.assertNotContained(SANITY_FAIL_MESSAGE, output)
+ def test_emcc_caching(self):
+ INCLUDING_MESSAGE = 'emcc: including X'
+ BUILDING_MESSAGE = 'emcc: building X for cache'
+
+ EMCC_CACHE = Cache.dirname
+
+ restore()
+
+ Cache.erase()
+ assert not os.path.exists(EMCC_CACHE)
+
+ try:
+ emcc_debug = os.environ.get('EMCC_DEBUG')
+ os.environ['EMCC_DEBUG'] ='1'
+
+ # Building a file that doesn't need cached stuff should not trigger cache generation
+ output = self.do([EMCC, path_from_root('tests', 'hello_world.cpp')])
+ assert INCLUDING_MESSAGE.replace('X', 'dlmalloc') not in output
+ assert BUILDING_MESSAGE.replace('X', 'dlmalloc') not in output
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ assert not os.path.exists(EMCC_CACHE)
+ try_delete('a.out.js')
+
+ # Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time
+ for filename, libname in [('hello_malloc.cpp', 'dlmalloc'), ('hello_libcxx.cpp', 'libcxx')]:
+ for i in range(3):
+ try_delete(os.path.join(EMSCRIPTEN_TEMP_DIR, 'emcc-0-bc.bc')) # we might need to check this file later
+ output = self.do([EMCC, path_from_root('tests', filename)])
+ assert INCLUDING_MESSAGE.replace('X', libname) in output
+ if libname == 'dlmalloc':
+ assert INCLUDING_MESSAGE.replace('X', 'libcxx') not in output # we don't need libcxx in this code
+ else:
+ assert INCLUDING_MESSAGE.replace('X', 'dlmalloc') in output # libcxx always forces inclusion of dlmalloc
+ assert (BUILDING_MESSAGE.replace('X', libname) in output) == (i == 0), 'Must only build the first time'
+ self.assertContained('hello, world!', run_js('a.out.js'))
+ assert os.path.exists(EMCC_CACHE)
+ assert os.path.exists(os.path.join(EMCC_CACHE, libname + '.bc'))
+ if libname == 'libcxx':
+ assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 4000000, 'libc++ is big'
+ assert os.stat(os.path.join(EMSCRIPTEN_TEMP_DIR, 'emcc-0-bc.bc')).st_size < 2000000, 'Dead code elimination must remove most of libc++'
+ finally:
+ if emcc_debug:
+ os.environ['EMCC_DEBUG'] = emcc_debug
+
else:
raise Exception('Test runner is confused: ' + str(sys.argv))