def test_vanilla(self): restore_and_set_up() Cache.erase() def make_fake(report): with open(config_file, 'a') as f: f.write('LLVM_ROOT = "' + self.in_dir('fake', 'bin') + '"\n') # BINARYEN_ROOT needs to exist in the config, even though this test # doesn't actually use it. f.write('BINARYEN_ROOT= "%s"\n' % self.in_dir('fake', 'bin')) make_fake_clang(self.in_dir('fake', 'bin', 'clang'), EXPECTED_LLVM_VERSION) make_fake_llc(self.in_dir('fake', 'bin', 'llc'), report) make_fake_lld(self.in_dir('fake', 'bin', 'wasm-ld')) # fake llc output def test_with_fake(report, expected): make_fake(report) with env_modify({'EMCC_DEBUG': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], expected) test_with_fake( 'got js backend! JavaScript (asm.js, emscripten) backend', 'LLVM has not been built with the WebAssembly backend') try_delete(CANONICAL_TEMP_DIR)
def test_emcc_caching(self): INCLUDING_MESSAGE = 'including X' BUILDING_MESSAGE = 'building X for cache' ERASING_MESSAGE = 'clearing cache' EMCC_CACHE = Cache.dirname restore_and_set_up() Cache.erase() assert not os.path.exists(EMCC_CACHE) with env_modify({'EMCC_DEBUG': '1'}): # Building a file that *does* need something *should* trigger cache # generation, but only the first time for filename, libname in [('hello_libcxx.cpp', 'libcxx')]: for i in range(3): print(filename, libname, i) self.clear() output = self.do([EMCC, '-O' + str(i), '-s', '--llvm-lto', '0', path_from_root('tests', filename), '--save-bc', 'a.bc', '-s', 'DISABLE_EXCEPTION_CATCHING=0']) # print '\n\n\n', output assert INCLUDING_MESSAGE.replace('X', libname) in output if libname == 'libc': assert INCLUDING_MESSAGE.replace('X', 'libcxx') not in output # we don't need libcxx in this code else: assert INCLUDING_MESSAGE.replace('X', 'libc') in output # libcxx always forces inclusion of libc 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) full_libname = libname + '.bc' if libname != 'libcxx' else libname + '.a' assert os.path.exists(os.path.join(EMCC_CACHE, full_libname)) try_delete(CANONICAL_TEMP_DIR) restore_and_set_up() def ensure_cache(): self.do([PYTHON, EMCC, '-O2', path_from_root('tests', 'hello_world.c')]) # Manual cache clearing ensure_cache() self.assertTrue(os.path.exists(EMCC_CACHE)) output = self.do([PYTHON, EMCC, '--clear-cache']) self.assertIn(ERASING_MESSAGE, output) self.assertFalse(os.path.exists(EMCC_CACHE)) self.assertIn(SANITY_MESSAGE, output) # Changing LLVM_ROOT, even without altering .emscripten, clears the cache ensure_cache() with env_modify({'LLVM': 'waka'}): self.assertTrue(os.path.exists(EMCC_CACHE)) output = self.do([PYTHON, EMCC]) self.assertIn(ERASING_MESSAGE, output) self.assertFalse(os.path.exists(EMCC_CACHE))
def test_wacky_env(self): restore_and_set_up() def build(): return self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') def test(): self.assertContained('hello, world!', run_js('a.out.js')) print('normal build') with env_modify({'EMCC_FORCE_STDLIBS': None}): Cache.erase() build() test() print('wacky env vars, these should not mess our bootstrapping') with env_modify({'EMCC_FORCE_STDLIBS': '1'}): Cache.erase() build() test()
def test_nostdincxx(self): restore_and_set_up() Cache.erase() for compiler in [EMCC]: print(compiler) run_process([PYTHON, EMCC] + MINIMAL_HELLO_WORLD + ['-v']) # run once to ensure binaryen port is all ready proc = run_process([PYTHON, EMCC] + MINIMAL_HELLO_WORLD + ['-v'], stdout=PIPE, stderr=PIPE) out = proc.stdout err = proc.stderr proc2 = run_process([PYTHON, EMCC] + MINIMAL_HELLO_WORLD + ['-v', '-nostdinc++'], stdout=PIPE, stderr=PIPE) out2 = proc2.stdout err2 = proc2.stderr self.assertIdentical(out, out2) def focus(e): assert 'search starts here:' in e, e assert e.count('End of search list.') == 1, e return e[e.index('search starts here:'):e.index('End of search list.') + 20] err = focus(err) err2 = focus(err2) assert err == err2, err + '\n\n\n\n' + err2
def test_vanilla(self): restore_and_set_up() Cache.erase() with env_modify({'EMCC_DEBUG': '1'}): # see that we test vanilla status, and just once TESTING = 'testing for asm.js target' print(self.check_working(EMCC, TESTING)) for i in range(3): output = self.check_working(EMCC, 'check tells us to use') self.assertNotContained(TESTING, output) # if env var tells us, do what it says with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working( EMCC, 'EMCC_WASM_BACKEND tells us to use wasm backend') with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working( EMCC, 'EMCC_WASM_BACKEND tells us to use asm.js backend') def make_fake(report): with open(CONFIG_FILE, 'a') as f: f.write('LLVM_ROOT = "' + self.in_dir('fake', 'bin') + '"\n') # BINARYEN_ROOT needs to exist in the config, even though this test # doesn't actually use it. f.write('BINARYEN_ROOT= "%s"\n' % self.in_dir('fake', 'bin')) make_fake_clang(self.in_dir('fake', 'bin', 'clang'), expected_llvm_version()) make_fake_llc(self.in_dir('fake', 'bin', 'llc'), report) make_fake_lld(self.in_dir('fake', 'bin', 'wasm-ld')) with env_modify({'EMCC_DEBUG': '1'}): make_fake('wasm32-unknown-unknown-elf') # see that we request the right backend from llvm with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'wasm32-unknown-unknown-elf') make_fake('asmjs-unknown-emscripten') with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'asmjs-unknown-emscripten') # check the current installed one is ok restore_and_set_up() self.check_working(EMCC) output = self.check_working(EMCC, 'check tells us to use') if 'wasm backend' in output: self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'wasm32-unknown-unknown-elf') else: assert 'asm.js backend' in output self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'asmjs-unknown-emscripten') # fake llc output def test_with_fake(report, expected): make_fake(report) with env_modify({'EMCC_DEBUG': '1'}): output = self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], expected) self.assertContained( 'config file changed since we checked vanilla', output) test_with_fake( 'got js backend! JavaScript (asm.js, emscripten) backend', 'check tells us to use asm.js backend') test_with_fake('got wasm32 backend! WebAssembly 32-bit', 'check tells us to use wasm backend') # use LLVM env var to modify LLVM between vanilla checks assert not os.environ.get( 'EM_LLVM_ROOT'), 'we need to modify EM_LLVM_ROOT env var for this' f = open(CONFIG_FILE, 'a') f.write('LLVM_ROOT = "' + self.in_dir('fake1', 'bin') + '"\n') f.close() safe_ensure_dirs(self.in_dir('fake1', 'bin')) f = open(self.in_dir('fake1', 'bin', 'llc'), 'w') f.write('#!/bin/sh\n') f.write('echo "llc fake1 output\nRegistered Targets:\n%s"' % 'got js backend! JavaScript (asm.js, emscripten) backend') f.close() os.chmod(self.in_dir('fake1', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) safe_ensure_dirs(self.in_dir('fake2', 'bin')) f = open(self.in_dir('fake2', 'bin', 'llc'), 'w') f.write('#!/bin/sh\n') f.write('echo "llc fake2 output\nRegistered Targets:\n%s"' % 'got wasm32 backend! WebAssembly 32-bit') f.close() os.chmod(self.in_dir('fake2', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) with env_modify({'EMCC_DEBUG': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'use asm.js backend') with env_modify({'EM_LLVM_ROOT': self.in_dir('fake2', 'bin')}): self.check_working( [EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'regenerating vanilla check since other llvm') try_delete(CANONICAL_TEMP_DIR) return # TODO: the rest of this # check separate cache dirs are used restore_and_set_up() self.check_working([EMCC], '') root_cache = os.path.expanduser('~/.emscripten_cache') if os.path.exists(os.path.join(root_cache, 'asmjs')): shutil.rmtree(os.path.join(root_cache, 'asmjs')) if os.path.exists(os.path.join(root_cache, 'wasm')): shutil.rmtree(os.path.join(root_cache, 'wasm')) with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') self.assertExists(os.path.join(root_cache, 'wasm')) with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') self.assertExists(os.path.join(root_cache, 'asmjs')) shutil.rmtree(os.path.join(root_cache, 'asmjs')) self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') self.assertExists(os.path.join(root_cache, 'asmjs'))
def erase_cache(self): Cache.erase() self.assertCacheEmpty()
def erase_cache(self): Cache.erase() assert not os.path.exists(Cache.dirname)
def test_vanilla(self): restore_and_set_up() Cache.erase() with env_modify({'EMCC_DEBUG': '1'}): # see that we test vanilla status, and just once TESTING = 'testing for asm.js target' self.check_working(EMCC, TESTING) for i in range(3): output = self.check_working(EMCC, 'check tells us to use') assert TESTING not in output # if env var tells us, do what it says with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working(EMCC, 'EMCC_WASM_BACKEND tells us to use wasm backend') with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working(EMCC, 'EMCC_WASM_BACKEND tells us to use asm.js backend') def make_fake(report): with open(CONFIG_FILE, 'a') as f: f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake', 'bin') + '"\n') # BINARYEN_ROOT needs to exist in the config, even though this test # doesn't actually use it. f.write('BINARYEN_ROOT= "%s"\n' % path_from_root('tests', 'fake', 'bin')) with open(path_from_root('tests', 'fake', 'bin', 'llc'), 'w') as f: f.write('#!/bin/sh\n') f.write('echo "llc fake output\nRegistered Targets:\n%s"' % report) os.chmod(path_from_root('tests', 'fake', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) with open(path_from_root('tests', 'fake', 'bin', 'wasm-ld'), 'w') as f: f.write('#!/bin/sh\n') f.write('exit 0\n') os.chmod(path_from_root('tests', 'fake', 'bin', 'wasm-ld'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) with env_modify({'EMCC_DEBUG': '1'}): make_fake('wasm32-unknown-unknown-elf') # see that we request the right backend from llvm with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'wasm32-unknown-unknown-elf') make_fake('asmjs-unknown-emscripten') with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'asmjs-unknown-emscripten') # check the current installed one is ok restore_and_set_up() self.check_working(EMCC) output = self.check_working(EMCC, 'check tells us to use') if 'wasm backend' in output: self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'wasm32-unknown-unknown-elf') else: assert 'asm.js backend' in output self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'asmjs-unknown-emscripten') # fake llc output try_delete(path_from_root('tests', 'fake')) os.makedirs(path_from_root('tests', 'fake', 'bin')) def test_with_fake(report, expected): make_fake(report) with env_modify({'EMCC_DEBUG': '1'}): output = self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], expected) self.assertContained('config file changed since we checked vanilla', output) test_with_fake('got js backend! JavaScript (asm.js, emscripten) backend', 'check tells us to use asm.js backend') test_with_fake('got wasm32 backend! WebAssembly 32-bit', 'check tells us to use wasm backend') # use LLVM env var to modify LLVM between vanilla checks assert not os.environ.get('LLVM'), 'we need to modify LLVM env var for this' f = open(CONFIG_FILE, 'a') f.write('LLVM_ROOT = os.getenv("LLVM", "' + path_from_root('tests', 'fake1', 'bin') + '")\n') f.close() safe_ensure_dirs(path_from_root('tests', 'fake1', 'bin')) f = open(path_from_root('tests', 'fake1', 'bin', 'llc'), 'w') f.write('#!/bin/sh\n') f.write('echo "llc fake1 output\nRegistered Targets:\n%s"' % 'got js backend! JavaScript (asm.js, emscripten) backend') f.close() os.chmod(path_from_root('tests', 'fake1', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) safe_ensure_dirs(path_from_root('tests', 'fake2', 'bin')) f = open(path_from_root('tests', 'fake2', 'bin', 'llc'), 'w') f.write('#!/bin/sh\n') f.write('echo "llc fake2 output\nRegistered Targets:\n%s"' % 'got wasm32 backend! WebAssembly 32-bit') f.close() os.chmod(path_from_root('tests', 'fake2', 'bin', 'llc'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) with env_modify({'EMCC_DEBUG': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'use asm.js backend') with env_modify({'LLVM': path_from_root('tests', 'fake2', 'bin')}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-c'], 'regenerating vanilla check since other llvm') try_delete(CANONICAL_TEMP_DIR) return # TODO: the rest of this # check separate cache dirs are used restore_and_set_up() self.check_working([EMCC], '') root_cache = os.path.expanduser('~/.emscripten_cache') if os.path.exists(os.path.join(root_cache, 'asmjs')): shutil.rmtree(os.path.join(root_cache, 'asmjs')) if os.path.exists(os.path.join(root_cache, 'wasm')): shutil.rmtree(os.path.join(root_cache, 'wasm')) with env_modify({'EMCC_WASM_BACKEND': '1'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') assert os.path.exists(os.path.join(root_cache, 'wasm')) with env_modify({'EMCC_WASM_BACKEND': '0'}): self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') assert os.path.exists(os.path.join(root_cache, 'asmjs')) shutil.rmtree(os.path.join(root_cache, 'asmjs')) self.check_working([EMCC] + MINIMAL_HELLO_WORLD, '') assert os.path.exists(os.path.join(root_cache, 'asmjs'))
def test_embuilder(self): restore_and_set_up() tests = [ ([PYTHON, EMBUILDER], ['Emscripten System Builder Tool', 'build libc', 'native_optimizer'], True, []), ([PYTHON, EMBUILDER, 'build', 'waka'], 'ERROR', False, []), ([PYTHON, EMBUILDER, 'build', 'struct_info'], ['building and verifying struct_info', 'success'], True, ['generated_struct_info.json']), ([PYTHON, EMBUILDER, 'build', 'libc'], ['building and verifying libc', 'success'], True, ['libc.bc']), ([PYTHON, EMBUILDER, 'build', 'libc-mt'], ['building and verifying libc-mt', 'success'], True, ['libc-mt.bc']), ([PYTHON, EMBUILDER, 'build', 'libc-extras'], ['building and verifying libc-extras', 'success'], True, ['libc-extras.bc']), ([PYTHON, EMBUILDER, 'build', 'dlmalloc'], ['building and verifying dlmalloc', 'success'], True, ['dlmalloc.bc']), ([PYTHON, EMBUILDER, 'build', 'dlmalloc_debug'], ['building and verifying dlmalloc', 'success'], True, ['dlmalloc_debug.bc']), ([PYTHON, EMBUILDER, 'build', 'dlmalloc_threadsafe'], ['building and verifying dlmalloc_threadsafe', 'success'], True, ['dlmalloc_threadsafe.bc']), ([PYTHON, EMBUILDER, 'build', 'dlmalloc_threadsafe_debug'], ['building and verifying dlmalloc', 'success'], True, ['dlmalloc_threadsafe_debug.bc']), ([PYTHON, EMBUILDER, 'build', 'emmalloc'], ['building and verifying emmalloc', 'success'], True, ['emmalloc.bc']), ([PYTHON, EMBUILDER, 'build', 'emmalloc_debug'], ['building and verifying emmalloc', 'success'], True, ['emmalloc_debug.bc']), ([PYTHON, EMBUILDER, 'build', 'pthreads'], ['building and verifying pthreads', 'success'], True, ['pthreads.bc']), ([PYTHON, EMBUILDER, 'build', 'libcxx'], ['success'], True, ['libcxx.a']), ([PYTHON, EMBUILDER, 'build', 'libcxx_noexcept'], ['success'], True, ['libcxx_noexcept.a']), ([PYTHON, EMBUILDER, 'build', 'libcxxabi'], ['success'], True, ['libcxxabi.bc']), ([PYTHON, EMBUILDER, 'build', 'gl'], ['success'], True, ['gl.bc']), ([PYTHON, EMBUILDER, 'build', 'native_optimizer'], ['success'], True, ['optimizer.2.exe']), ([PYTHON, EMBUILDER, 'build', 'zlib'], ['building and verifying zlib', 'success'], True, ['zlib.bc']), ([PYTHON, EMBUILDER, 'build', 'libpng'], ['building and verifying libpng', 'success'], True, ['libpng.bc']), ([PYTHON, EMBUILDER, 'build', 'bullet'], ['building and verifying bullet', 'success'], True, ['bullet.bc']), ([PYTHON, EMBUILDER, 'build', 'vorbis'], ['building and verifying vorbis', 'success'], True, ['vorbis.bc']), ([PYTHON, EMBUILDER, 'build', 'ogg'], ['building and verifying ogg', 'success'], True, ['ogg.bc']), ([PYTHON, EMBUILDER, 'build', 'sdl2'], ['success'], True, ['sdl2.bc']), ([PYTHON, EMBUILDER, 'build', 'sdl2-gfx'], ['success'], True, ['sdl2-gfx.bc']), ([PYTHON, EMBUILDER, 'build', 'sdl2-image'], ['success'], True, ['sdl2-image.bc']), ([PYTHON, EMBUILDER, 'build', 'freetype'], ['building and verifying freetype', 'success'], True, ['freetype.bc']), ([PYTHON, EMBUILDER, 'build', 'harfbuzz'], ['building and verifying harfbuzz', 'success'], True, ['harfbuzz.bc']), ([PYTHON, EMBUILDER, 'build', 'icu'], ['building and verifying icu', 'success'], True, ['icu.bc']), ([PYTHON, EMBUILDER, 'build', 'sdl2-ttf'], ['building and verifying sdl2-ttf', 'success'], True, ['sdl2-ttf.bc']), ([PYTHON, EMBUILDER, 'build', 'sdl2-net'], ['building and verifying sdl2-net', 'success'], True, ['sdl2-net.bc']), ([PYTHON, EMBUILDER, 'build', 'binaryen'], ['building and verifying binaryen', 'success'], True, []), ([PYTHON, EMBUILDER, 'build', 'cocos2d'], ['building and verifying cocos2d', 'success'], True, ['libCocos2d.bc']), ([PYTHON, EMBUILDER, 'build', 'wasm-libc'], ['building and verifying wasm-libc', 'success'], True, ['wasm-libc.bc']), ] if Settings.WASM_BACKEND: tests.append(([PYTHON, EMBUILDER, 'build', 'wasm_compiler_rt'], ['building and verifying wasm_compiler_rt', 'success'], True, ['wasm_compiler_rt.a']),) Cache.erase() for command, expected, success, result_libs in tests: print(command) for lib in result_libs: if os.path.sep in lib: dirname = os.path.dirname(Cache.get_path(lib)) print(' erase dir', dirname) try_delete(dirname) else: print(' erase file', lib) try_delete(Cache.get_path(lib)) proc = run_process(command, stdout=PIPE, stderr=STDOUT, check=False) out = proc.stdout if success and proc.returncode != 0: print(out) assert (proc.returncode == 0) == success if not isinstance(expected, list): expected = [expected] for ex in expected: print(' seek', ex) assert ex in out, out for lib in result_libs: print(' verify', lib) assert os.path.exists(Cache.get_path(lib))
def test_native_optimizer(self): restore_and_set_up() def build(): return self.check_working([EMCC] + MINIMAL_HELLO_WORLD + ['-O2', '-s', 'WASM=0'], 'running js post-opts') def test(): self.assertContained('hello, world!', run_js('a.out.js')) with env_modify({'EMCC_DEBUG': '1'}): # basic usage or lack of usage for native in [None, 0, 1]: print('phase 1, part', native) Cache.erase() try: if native is not None: os.environ['EMCC_NATIVE_OPTIMIZER'] = str(native) output = build() assert ('js optimizer using native' in output) == (not not (native or native is None)), output test() if native or native is None: # None means use the default, which is to use the native optimizer assert 'building native optimizer' in output, output # compile again, no rebuild of optimizer output = build() assert 'building native optimizer' not in output assert 'js optimizer using native' in output test() finally: if native is not None: del os.environ['EMCC_NATIVE_OPTIMIZER'] # force a build failure, see we fall back to non-native for native in [1, 'g']: with env_modify({'EMCC_NATIVE_OPTIMIZER': str(native)}): print('phase 2, part', native) Cache.erase() try: # break it f = path_from_root('tools', 'optimizer', 'optimizer-main.cpp') src = open(f).read() bad = src.replace('main', '!waka waka<') assert bad != src open(f, 'w').write(bad) # first try output = build() assert 'failed to build native optimizer' in output, output if native == 1: assert 'to see compiler errors, build with EMCC_NATIVE_OPTIMIZER=g' in output assert 'waka waka' not in output else: assert 'output from attempt' in output, output assert 'waka waka' in output, output assert 'js optimizer using native' not in output test() # still works, without native optimizer # second try, see previous failure output = build() assert 'failed to build native optimizer' not in output assert 'seeing that optimizer could not be built' in output test() # still works, without native optimizer # clear cache, try again Cache.erase() output = build() assert 'failed to build native optimizer' in output test() # still works, without native optimizer finally: open(f, 'w').write(src) Cache.erase() # now it should work again output = build() assert 'js optimizer using native' in output test() # still works try_delete(CANONICAL_TEMP_DIR)