aboutsummaryrefslogtreecommitdiff
path: root/tests/runner.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-xtests/runner.py583
1 files changed, 507 insertions, 76 deletions
diff --git a/tests/runner.py b/tests/runner.py
index e2bb13d4..27100cbb 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -279,8 +279,6 @@ 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
@@ -430,49 +428,38 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
def test_i64(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
- for i64_mode in [0,1]:
- if i64_mode == 0 and Settings.USE_TYPED_ARRAYS != 0: continue # Typed arrays truncate i64
- if i64_mode == 1 and Settings.QUANTUM_SIZE == 1: continue # TODO: i64 mode 1 for q1
+ src = '''
+ #include <stdio.h>
+ int main()
+ {
+ long long a = 0x2b00505c10;
+ long long b = a >> 29;
+ long long c = a >> 32;
+ long long d = a >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d);
+ unsigned long long ua = 0x2b00505c10;
+ unsigned long long ub = ua >> 29;
+ unsigned long long uc = ua >> 32;
+ unsigned long long ud = ua >> 34;
+ printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud);
+
+ long long x = 0x0000def123450789ULL; // any bigger than this, and we
+ long long y = 0x00020ef123456089ULL; // start to run into the double precision limit!
+ printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2);
- Settings.I64_MODE = i64_mode
- src = '''
- #include <stdio.h>
- int main()
- {
- long long a = 0x2b00505c10;
- long long b = a >> 29;
- long long c = a >> 32;
- long long d = a >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\\n", a, b, c, d);
- unsigned long long ua = 0x2b00505c10;
- unsigned long long ub = ua >> 29;
- unsigned long long uc = ua >> 32;
- unsigned long long ud = ua >> 34;
- printf("*%Ld,%Ld,%Ld,%Ld*\\n", ua, ub, uc, ud);
-
- long long x = 0x0000def123450789ULL; // any bigger than this, and we
- long long y = 0x00020ef123456089ULL; // start to run into the double precision limit!
- printf("*%Ld,%Ld,%Ld,%Ld,%Ld*\\n", x, y, x | y, x & y, x ^ y, x >> 2, y << 2);
-
- printf("*");
- long long z = 13;
- int n = 0;
- while (z > 1) {
- printf("%.2f,", (float)z); // these must be integers!
- z = z >> 1;
- n++;
- }
- printf("*%d*\\n", n);
- return 0;
+ printf("*");
+ long long z = 13;
+ int n = 0;
+ while (z > 1) {
+ printf("%.2f,", (float)z); // these must be integers!
+ z = z >> 1;
+ n++;
}
- '''
- self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
-
- if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: i64 mode 1 for q1')
-
- # Stuff that only works in i64_mode = 1
-
- Settings.I64_MODE = 1
+ printf("*%d*\\n", n);
+ return 0;
+ }
+ '''
+ self.do_run(src, '*184688860176,344,43,10*\n*184688860176,344,43,10*\n*245127260211081,579378795077769,808077213656969,16428841631881,791648372025088*\n*13.00,6.00,3.00,*3*')
src = r'''
#include <time.h>
@@ -653,6 +640,166 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, '*1*\n*0*\n*0*\n')
+ def test_i64_b(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+ #include <sys/time.h>
+
+ typedef long long int64;
+
+ #define PRMJ_USEC_PER_SEC 1000000L
+
+ int main(int argc, char * argv[]) {
+ int64 sec = 1329409675 + argc;
+ int64 usec = 2329509675;
+ int64 mul = int64(sec) * PRMJ_USEC_PER_SEC;
+ int64 add = mul + int64(usec);
+ int add_low = add;
+ int add_high = add >> 32;
+ printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high);
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n')
+
+ def test_i64_cmp(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+
+ bool compare(int64 val) {
+ return val == -12;
+ }
+
+ bool compare2(int64 val) {
+ return val < -12;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d,%d,%d*\n", argc, compare(argc-1-12), compare(1000+argc), compare2(argc-1-10), compare2(argc-1-14), compare2(argc+1000));
+ return 0;
+ }
+ '''
+
+ self.do_run(src, '*1,1,0,0,1,0*\n')
+
+ def test_i64_cmp2(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef int32_t INT32;
+ typedef int64_t INT64;
+ typedef uint8_t UINT8;
+
+ void interface_clock_changed()
+ {
+ UINT8 m_divshift;
+ INT32 m_divisor;
+
+ //INT64 attos = m_attoseconds_per_cycle;
+ INT64 attos = 279365114840;
+ m_divshift = 0;
+ while (attos >= (1UL << 31))
+ {
+ m_divshift++;
+ printf("m_divshift is %i, on %Ld >?= %lu\n", m_divshift, attos, 1UL << 31);
+ attos >>= 1;
+ }
+ m_divisor = attos;
+
+ printf("m_divisor is %i\n",m_divisor);
+ }
+
+ int main() {
+ interface_clock_changed();
+ return 0;
+ }
+ '''
+ self.do_run(src, '''m_divshift is 1, on 279365114840 >?= 2147483648
+m_divshift is 2, on 139682557420 >?= 2147483648
+m_divshift is 3, on 69841278710 >?= 2147483648
+m_divshift is 4, on 34920639355 >?= 2147483648
+m_divshift is 5, on 17460319677 >?= 2147483648
+m_divshift is 6, on 8730159838 >?= 2147483648
+m_divshift is 7, on 4365079919 >?= 2147483648
+m_divshift is 8, on 2182539959 >?= 2147483648
+m_divisor is 1091269979
+''')
+
+ def test_i64_double(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+ src = r'''
+ #include <stdio.h>
+
+ typedef long long int64;
+ #define JSDOUBLE_HI32_SIGNBIT 0x80000000
+
+ bool JSDOUBLE_IS_NEGZERO(double d)
+ {
+ union {
+ struct {
+ unsigned int lo, hi;
+ } s;
+ double d;
+ } x;
+ if (d != 0)
+ return false;
+ x.d = d;
+ return (x.s.hi & JSDOUBLE_HI32_SIGNBIT) != 0;
+ }
+
+ bool JSINT64_IS_NEGZERO(int64 l)
+ {
+ union {
+ int64 i;
+ double d;
+ } x;
+ if (l != 0)
+ return false;
+ x.i = l;
+ return x.d == -0;
+ }
+
+ int main(int argc, char * argv[]) {
+ printf("*%d,%d,%d,%d*\n", JSDOUBLE_IS_NEGZERO(0), JSDOUBLE_IS_NEGZERO(-0), JSDOUBLE_IS_NEGZERO(-1), JSDOUBLE_IS_NEGZERO(+1));
+ printf("*%d,%d,%d,%d*\n", JSINT64_IS_NEGZERO(0), JSINT64_IS_NEGZERO(-0), JSINT64_IS_NEGZERO(-1), JSINT64_IS_NEGZERO(+1));
+ return 0;
+ }
+ '''
+ self.do_run(src, '*0,0,0,0*\n*1,1,0,0*\n') # same as gcc
+
+ def test_i64_umul(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+ src = r'''
+ #include <inttypes.h>
+ #include <stdio.h>
+
+ typedef uint32_t UINT32;
+ typedef uint64_t UINT64;
+
+ int main() {
+ volatile UINT32 testu32a = 2375724032U;
+ UINT32 bigu32 = 0xffffffffU;
+ volatile UINT64 testu64a = 14746250828952703000U;
+
+ while ((UINT64)testu32a * (UINT64)bigu32 < testu64a) {
+ printf("testu64a is %llu\n", testu64a);
+ testu64a /= 2;
+ }
+
+ return 0;
+ }
+ '''
+ self.do_run(src, 'testu64a is 14746250828952703000\n')
+
def test_unaligned(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1')
@@ -1319,6 +1466,41 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
'''
self.do_run(src, 'Assertion failed: 1 == false')
+ def test_longjmp(self):
+ src = r'''
+ #include <stdio.h>
+ #include <setjmp.h>
+
+ static jmp_buf buf;
+
+ void second(void) {
+ printf("second\n"); // prints
+ longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
+ }
+
+ void first(void) {
+ second();
+ printf("first\n"); // does not print
+ }
+
+ int main() {
+ int x = 0;
+ if ( ! setjmp(buf) ) {
+ x++;
+ first(); // when executed, setjmp returns 0
+ } else { // when longjmp jumps back, setjmp returns 1
+ printf("main: %d\n", x); // prints
+ }
+
+ return 0;
+ }
+ '''
+ # gcc -O0 and -O2 differ in what they do with the saved state of local vars - and we match that
+ if self.emcc_args is None or ('-O1' not in self.emcc_args and '-O2' not in self.emcc_args):
+ self.do_run(src, 'second\nmain: 1\n')
+ else:
+ self.do_run(src, 'second\nmain: 0\n')
+
def test_exceptions(self):
if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1")
@@ -1446,8 +1628,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, 'success')
def test_typed_exceptions(self):
- return self.skip('TODO: fix this for llvm 3.0')
-
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
Settings.SAFE_HEAP = 0 # Throwing null will cause an ignorable null pointer access.
Settings.EXCEPTION_DEBUG = 0 # Messes up expected output.
src = open(path_from_root('tests', 'exceptions', 'typed.cpp'), 'r').read()
@@ -1549,6 +1730,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, '*11,74,32,1012*\n*11*\n*22*')
def test_dynamic_cast(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
src = r'''
#include <stdio.h>
@@ -2104,6 +2287,8 @@ def process(filename):
self.do_run(src, '*nameA,nameB*')
def test_llvmswitch(self):
+ Settings.CORRECT_SIGNS = 1
+
src = '''
#include <stdio.h>
#include <string.h>
@@ -2115,23 +2300,22 @@ def process(filename):
case 'b':
case 'c':
return p-1;
- case 'd':
+ case 0xfffffff1:
return p+1;
}
return p;
}
int main( int argc, const char *argv[] ) {
- printf("*%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher('d'), switcher('e'));
+ unsigned int x = 0xfffffff1;
+ x >>= 0; // force it to be unsigned for purpose of checking our switch comparison in signed/unsigned
+ printf("*%d,%d,%d,%d,%d,%d*\\n", switcher('a'), switcher('b'), switcher('c'), switcher(x), switcher(-15), switcher('e'));
return 0;
}
'''
- self.do_run(src, '*96,97,98,101,101*')
+ self.do_run(src, '*96,97,98,-14,-14,101*')
def test_indirectbr(self):
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.I64_MODE = 1 # Unsafe optimizations use 64-bit load/store on two i32s
-
src = '''
#include <stdio.h>
int main(void) {
@@ -2439,6 +2623,27 @@ def process(filename):
self.do_run(src, '*1*', force_c=True)
+ def test_atexit(self):
+ # Confirms they are called in reverse order
+ src = r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ static void cleanA() {
+ printf("A");
+ }
+ static void cleanB() {
+ printf("B");
+ }
+
+ int main() {
+ atexit(cleanA);
+ atexit(cleanB);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'BA')
+
def test_time(self):
# XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again.
src = open(path_from_root('tests', 'time', 'src.c'), 'r').read()
@@ -3292,15 +3497,12 @@ at function.:blag
def test_parseInt(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
if Settings.QUANTUM_SIZE == 1: return self.skip('Q1 and I64_1 do not mix well yet')
- Settings.I64_MODE = 1 # Necessary to prevent i64s being truncated into i32s, but we do still get doubling
- # FIXME: The output here is wrong, due to double rounding of i64s!
src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
self.do_run(src, expected)
def test_printf(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
- Settings.I64_MODE = 1
self.banned_js_engines = [NODE_JS, V8_ENGINE] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
expected = [open(path_from_root('tests', 'printf', 'output.txt'), 'r').read(),
@@ -3493,6 +3695,37 @@ def process(filename):
self.do_run(src, 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\n',
post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ def test_files_m(self):
+ # Test for Module.stdin etc.
+
+ Settings.CORRECT_SIGNS = 1
+
+ post = '''
+def process(filename):
+ src = \'\'\'
+ var data = [10, 20, 40, 30];
+ var Module = {
+ stdin: function() { return data.pop() || null },
+ stdout: function(x) { print('got: ' + x) }
+ };
+ \'\'\' + open(filename, 'r').read()
+ open(filename, 'w').write(src)
+'''
+ src = r'''
+ #include <stdio.h>
+ #include <unistd.h>
+
+ int main () {
+ char c;
+ fprintf(stderr, "isatty? %d,%d,%d\n", isatty(fileno(stdin)), isatty(fileno(stdout)), isatty(fileno(stderr)));
+ while ((c = fgetc(stdin)) != EOF) {
+ putc(c+5, stdout);
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n', post_build=post)
+
def test_folders(self):
add_pre_run = '''
def process(filename):
@@ -3867,7 +4100,9 @@ def process(filename):
printf( "%i %i %i", one, two, three );
}
'''
- self.do_run(src, "1 2 3")
+ for linkable in [0, 1]:
+ Settings.LINKABLE = linkable # regression check for issue #273
+ self.do_run(src, "1 2 3")
def test_readdir(self):
add_pre_run = '''
@@ -4203,7 +4438,7 @@ def process(filename):
'''
# FIXME: should not have so many newlines in output here
- self.do_run(src, 'hello world\n\n77.\n')
+ self.do_run(src, 'hello world\n77.\n')
def test_stdvec(self):
src = '''
@@ -4813,6 +5048,74 @@ Block 0: ''', post_build=post1)
### Integration tests
+ def test_ccall(self):
+ if self.emcc_args is not None and '-O2' in self.emcc_args:
+ self.emcc_args += ['--closure', '1'] # Use closure here, to test we export things right
+
+ src = r'''
+ #include <stdio.h>
+
+ // Optimizations might wipe out our functions without this
+ #define KEEPALIVE __attribute__((used))
+
+ extern "C" {
+ int KEEPALIVE get_int() { return 5; }
+ float KEEPALIVE get_float() { return 3.14; }
+ char * KEEPALIVE get_string() { return "hello world"; }
+ void KEEPALIVE print_int(int x) { printf("%d\n", x); }
+ void KEEPALIVE print_float(float x) { printf("%.2f\n", x); }
+ void KEEPALIVE print_string(char *x) { printf("%s\n", x); }
+ int KEEPALIVE multi(int x, float y, int z, char *str) { puts(str); return (x+y)*z; }
+ int * KEEPALIVE pointer(int *in) { printf("%d\n", *in); static int ret = 21; return &ret; }
+ }
+
+ int main(int argc, char **argv) {
+ // keep them alive
+ if (argc == 10) return get_int();
+ if (argc == 11) return get_float();
+ if (argc == 12) return get_string()[0];
+ if (argc == 13) print_int(argv[0][0]);
+ if (argc == 14) print_float(argv[0][0]);
+ if (argc == 15) print_string(argv[0]);
+ if (argc == 16) pointer((int*)argv[0]);
+ if (argc % 17 == 12) return multi(argc, float(argc)/2, argc+1, argv[0]);
+ return 0;
+ }
+ '''
+
+ post = '''
+def process(filename):
+ src = \'\'\'
+ var Module = {
+ 'postRun': function() {
+ print('*');
+ var ret;
+ ret = ccall('get_int', 'number'); print([typeof ret, ret]);
+ ret = ccall('get_float', 'number'); print([typeof ret, ret.toFixed(2)]);
+ ret = ccall('get_string', 'string'); print([typeof ret, ret]);
+ ret = ccall('print_int', null, ['number'], [12]); print(typeof ret);
+ ret = ccall('print_float', null, ['number'], [14.56]); print(typeof ret);
+ ret = ccall('print_string', null, ['string'], ["cheez"]); print(typeof ret);
+ ret = ccall('multi', 'number', ['number', 'number', 'number', 'string'], [2, 1.4, 3, 'more']); print([typeof ret, ret]);
+ var p = ccall('malloc', 'pointer', ['number'], [4]);
+ setValue(p, 650, 'i32');
+ ret = ccall('pointer', 'pointer', ['pointer'], [p]); print([typeof ret, getValue(ret, 'i32')]);
+ print('*');
+ // part 2: cwrap
+ var multi = cwrap('multi', 'number', ['number', 'number', 'number', 'string']);
+ print(multi(2, 1.4, 3, 'atr'));
+ print(multi(8, 5.4, 4, 'bret'));
+ print('*');
+ }
+ };
+ \'\'\' + open(filename, 'r').read()
+ open(filename, 'w').write(src)
+'''
+
+ Settings.EXPORTED_FUNCTIONS = ['_get_int', '_get_float', '_get_string', '_print_int', '_print_float', '_print_string', '_multi', '_pointer', '_malloc']
+
+ self.do_run(src, '*\nnumber,5\nnumber,3.14\nstring,hello world\n12\nundefined\n14.56\nundefined\ncheez\nundefined\nmore\nnumber,10\n650\nnumber,21\n*\natr\n10\nbret\n53\n*\n', post_build=post)
+
def test_scriptaclass(self):
header_filename = os.path.join(self.get_dir(), 'header.h')
header = '''
@@ -5394,7 +5697,7 @@ def process(filename):
}
'''
- if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
Settings.CORRECT_ROUNDINGS = 0
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
@@ -5407,7 +5710,7 @@ def process(filename):
self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct
Settings.CORRECT_SIGNS = 0
- if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
Settings.CORRECT_ROUNDINGS = 2
Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
@@ -5415,7 +5718,7 @@ def process(filename):
self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-5**5*') # No such luck here
# And reverse the check with = 2
- if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1
+ if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
Settings.CORRECT_ROUNDINGS = 3
Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"]
self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*')
@@ -5478,16 +5781,21 @@ def process(filename):
def test_exit_status(self):
Settings.CATCH_EXIT_CODE = 1
- src = '''
+ src = r'''
#include <stdio.h>
#include <stdlib.h>
+ static void cleanup() {
+ printf("cleanup\n");
+ }
+
int main()
{
- printf("hello, world!\\n");
+ atexit(cleanup); // this atexit should still be called
+ printf("hello, world!\n");
exit(118); // Unusual exit status to make sure it's working!
}
'''
- self.do_run(src, 'hello, world!\nExit Status: 118')
+ self.do_run(src, 'hello, world!\ncleanup\nExit Status: 118')
# Generate tests for everything
@@ -5539,11 +5847,6 @@ class %s(T):
Settings.CATCH_EXIT_CODE = 0
Settings.EMULATE_UNALIGNED_ACCESSES = int(Settings.USE_TYPED_ARRAYS == 2 and Building.LLVM_OPTS == 2)
Settings.DOUBLE_MODE = 1 if Settings.USE_TYPED_ARRAYS and Building.LLVM_OPTS == 0 else 0
- if Settings.USE_TYPED_ARRAYS == 2:
- Settings.I64_MODE = 1
- Settings.SAFE_HEAP = 1 # only checks for alignment problems, which is very important with unsafe opts
- else:
- Settings.I64_MODE = 0
Building.pick_llvm_opts(3)
@@ -5577,9 +5880,6 @@ TT = %s
del T # T is just a shape for the specific subclasses, we don't test it itself
class other(RunnerCore):
- def test_reminder(self):
- assert 0, 'find appearances of i64 in src/, most are now unneeded'
-
def test_emcc(self):
emcc_debug = os.environ.get('EMCC_DEBUG')
@@ -5636,7 +5936,7 @@ Options that are modified or new in %s include:
# emcc src.cpp -c and emcc src.cpp -o src.[o|bc] ==> should give a .bc file
# regression check: -o js should create "js", with bitcode content
- for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'js']]:
+ for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'src.so'], ['-o', 'js']]:
target = args[1] if len(args) == 2 else 'hello_world.o'
clear()
Popen([compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate()
@@ -5650,6 +5950,15 @@ Options that are modified or new in %s include:
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'))
+ # handle singleton archives
+ clear()
+ Popen([compiler, path_from_root('tests', 'hello_world' + suffix), '-o', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
+ Popen([LLVM_AR, 'r', 'a.a', 'a.bc'], stdout=PIPE, stderr=PIPE).communicate()
+ assert os.path.exists('a.a')
+ output = Popen([compiler, 'a.a']).communicate()
+ assert os.path.exists('a.out.js'), output
+ self.assertContained('hello, world!', run_js('a.out.js'))
+
# emcc src.ll ==> generates .js
clear()
output = Popen([compiler, path_from_root('tests', 'hello_world.ll')], stdout=PIPE, stderr=PIPE).communicate()
@@ -5742,12 +6051,12 @@ Options that are modified or new in %s include:
for params, test, text in [
(['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'),
(['-O1', '-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' not in generated, 'inlining'),
- (['-s', 'USE_TYPED_ARRAYS=0', '-s', 'I64_MODE=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['-s', 'USE_TYPED_ARRAYS=1', '-s', 'I64_MODE=0'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'),
(['-s', 'EXPORTED_FUNCTIONS=["_main", "_dump"]'], lambda generated: 'Module["_dump"]' in generated, 'dump is now exported'),
- (['--typed-arrays', '0', '-s', 'I64_MODE=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['--typed-arrays', '1', '-s', 'I64_MODE=0'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ (['--typed-arrays', '0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
(['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
(['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
]:
@@ -5884,13 +6193,134 @@ f.close()
clear()
output = Popen([EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html',
'-DHAVE_BUILTIN_SINCOS',
- '-s', 'USE_TYPED_ARRAYS=0', '-s', 'I64_MODE=0',
+ '-s', 'USE_TYPED_ARRAYS=0',
'--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')],
stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
assert os.path.exists('something.html'), output
run_browser('something.html', 'You should not see animating gears.', '/report_gl_result?false')
+ def test_emcc_l_link(self):
+ # Linking with -lLIBNAME and -L/DIRNAME should work
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ extern void printey();
+ int main() {
+ printey();
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib\\n");
+ }
+ ''')
+
+ Popen([EMCC, os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-c'], stdout=PIPE, stderr=STDOUT).communicate()
+ shutil.move(os.path.join(self.get_dir(), 'libfile.o'), os.path.join(self.get_dir(), 'libdir', 'libfile.so'))
+ Popen([EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile'], stdout=PIPE, stderr=STDOUT).communicate()
+ self.assertContained('hello from lib', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_emcc_embed_file(self):
+ open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''hello from a file with lots of data and stuff in it thank you very much''')
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ int main() {
+ FILE *f = fopen("somefile.txt", "r");
+ char buf[100];
+ fread(buf, 1, 20, f);
+ buf[20] = 0;
+ fclose(f);
+ printf("|%s|\n", buf);
+ return 0;
+ }
+ ''')
+
+ Popen([EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--embed-file', 'somefile.txt']).communicate()
+ self.assertContained('|hello from a file wi|', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_emcc_multidynamic_link(self):
+ # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols
+ # A workaround is to use --ignore-dynamic-linking, see emcc --help for details
+
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ extern void printey();
+ extern void printother();
+ int main() {
+ printf("*");
+ printey();
+ printf("\n");
+ printother();
+ printf("\n");
+ printf("*");
+ return 0;
+ }
+ ''')
+
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib");
+ }
+ ''')
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern void printey();
+ void printother() {
+ printf("|");
+ printey();
+ printf("|");
+ }
+ ''')
+
+ # This lets us link the same dynamic lib twice. We will need to link it in manually at the end.
+ compiler = [EMCC, '--ignore-dynamic-linking']
+
+ # Build libfile normally into an .so
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate()
+ # Build libother and dynamically link it to libfile - but add --ignore-dynamic-linking
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
+ # Build the main file, linking in both the libs
+ Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate()
+
+ # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
+ Popen([EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate()
+
+ self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
+ def test_emcc_js_link(self):
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
+ #include <stdio.h>
+ int main() {
+ printf("hello from main\\n");
+ return 0;
+ }
+ ''')
+ open(os.path.join(self.get_dir(), 'before.js'), 'w').write('''
+ var MESSAGE = 'hello from js';
+ if (typeof Module != 'undefined') throw 'This code should run before anything else!';
+ ''')
+ open(os.path.join(self.get_dir(), 'after.js'), 'w').write('''
+ print(MESSAGE);
+ ''')
+
+ Popen([EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'before.js', '--post-js', 'after.js']).communicate()
+ self.assertContained('hello from main\nhello from js\n', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+
def test_eliminator(self):
input = open(path_from_root('tools', 'eliminator', 'eliminator-test.js')).read()
expected = open(path_from_root('tools', 'eliminator', 'eliminator-test-output.js')).read()
@@ -5936,6 +6366,7 @@ elif 'benchmark' in str(sys.argv):
pass
finally:
os.chdir(d)
+ fingerprint.append('llvm: ' + LLVM_ROOT)
print 'Running Emscripten benchmarks... [ %s ]' % ' | '.join(fingerprint)
sys.argv = filter(lambda x: x != 'benchmark', sys.argv)