def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser):
   self.filename = filename
   self.old_env = os.environ
   os.environ = self.env.copy()
   llvm_root = self.env.get('LLVM') or LLVM_ROOT
   if lib_builder:
     env_init = self.env.copy()
     # Note that we need to pass in all the flags here because some build
     # systems (like zlib) if they see a CFLAGS it will override all their
     # default flags, including optimizations.
     env_init['CFLAGS'] = ' '.join(LLVM_FEATURE_FLAGS + [OPTIMIZATIONS] + self.extra_args)
     emcc_args = emcc_args + lib_builder('js_' + llvm_root, native=False, env_init=env_init)
   final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js'
   final = final.replace('.cpp', '')
   try_delete(final)
   cmd = [
     EMCC, filename,
     OPTIMIZATIONS,
     '-s', 'INITIAL_MEMORY=256MB',
     '-s', 'FILESYSTEM=0',
     '--closure', '1',
     '-s', 'MINIMAL_RUNTIME=1',
     '-s', 'BENCHMARK=%d' % (1 if IGNORE_COMPILATION and not has_output_parser else 0),
     '-o', final
   ] + shared_args + emcc_args + LLVM_FEATURE_FLAGS + self.extra_args
   if 'FORCE_FILESYSTEM=1' in cmd:
     cmd = [arg if arg != 'FILESYSTEM=0' else 'FILESYSTEM=1' for arg in cmd]
   if PROFILING:
     cmd += ['--profiling-funcs']
   self.cmd = cmd
   run_process(cmd, env=self.env)
   if self.binaryen_opts:
     run_binaryen_opts(final[:-3] + '.wasm', self.binaryen_opts)
   self.filename = final
Exemple #2
0
    def build(self, parent, filename, args, shared_args, emcc_args,
              native_args, native_exec, lib_builder, has_output_parser):
        self.parent = parent
        if lib_builder:
            env = {
                'CC': self.cc,
                'CXX': self.cxx,
                'CXXFLAGS': "-Wno-c++11-narrowing"
            }
            env.update(clang_native.get_clang_native_env())
            native_args = native_args + lib_builder(
                self.name, native=True, env_init=env)
        if not native_exec:
            compiler = self.cxx if filename.endswith('cpp') else self.cc
            cmd = [
                compiler, '-fno-math-errno', filename, '-o',
                filename + '.native'
            ] + self.args + shared_args + native_args + clang_native.get_clang_native_args(
            )
            # print(cmd)
            run_process(cmd, env=clang_native.get_clang_native_env())
        else:
            shutil.copyfile(native_exec, filename + '.native')
            shutil.copymode(native_exec, filename + '.native')

        final = os.path.dirname(
            filename) + os.path.sep + self.name + '_' + os.path.basename(
                filename) + '.native'
        shutil.move(filename + '.native', final)
        self.filename = final
Exemple #3
0
 def build(self, parent, filename, args, shared_args, emcc_args,
           native_args, native_exec, lib_builder, has_output_parser):
     self.filename = filename
     self.old_env = os.environ
     os.environ = self.env.copy()
     llvm_root = self.env.get('LLVM') or LLVM_ROOT
     if lib_builder:
         emcc_args = emcc_args + lib_builder(
             'js_' + llvm_root, native=False, env_init=self.env.copy())
     final = os.path.dirname(filename) + os.path.sep + self.name + (
         '_' if self.name else '') + os.path.basename(filename) + '.js'
     final = final.replace('.cpp', '')
     try_delete(final)
     cmd = [
         PYTHON, EMCC, filename, OPTIMIZATIONS, '-s', 'TOTAL_MEMORY=256MB',
         '-s', 'FILESYSTEM=0', '--closure', '1', '-s', 'MINIMAL_RUNTIME=0',
         '-s',
         'BENCHMARK=%d' %
         (1 if IGNORE_COMPILATION and not has_output_parser else 0), '-o',
         final
     ] + shared_args + emcc_args + LLVM_FEATURE_FLAGS + self.extra_args
     if 'FORCE_FILESYSTEM=1' in cmd:
         cmd = [
             arg if arg != 'FILESYSTEM=0' else 'FILESYSTEM=1' for arg in cmd
         ]
     if PROFILING:
         cmd += ['--profiling-funcs']
     self.cmd = cmd
     run_process(cmd, env=self.env)
     if self.binaryen_opts:
         run_binaryen_opts(final[:-3] + '.wasm', self.binaryen_opts)
     self.filename = final
Exemple #4
0
    def build(self, parent, filename, args, shared_args, emcc_args,
              native_args, native_exec, lib_builder, has_output_parser):
        # wasm2c doesn't want minimal runtime which the normal emscripten
        # benchmarker defaults to, as we don't have any JS anyhow
        emcc_args = emcc_args + [
            '-s', 'STANDALONE_WASM', '-s', 'MINIMAL_RUNTIME=0', '-s', 'WASM2C'
        ]

        global LLVM_FEATURE_FLAGS
        old_flags = LLVM_FEATURE_FLAGS
        try:
            # wasm2c does not support anything beyond MVP
            LLVM_FEATURE_FLAGS = []
            super(EmscriptenWasm2CBenchmarker,
                  self).build(parent, filename, args, shared_args, emcc_args,
                              native_args, native_exec, lib_builder,
                              has_output_parser)
        finally:
            LLVM_FEATURE_FLAGS = old_flags

        # move the JS away so there is no chance we run it by mistake
        shutil.move(self.filename, self.filename + '.old.js')

        base = self.filename[:-3]
        c = base + '.wasm.c'
        native = base + '.exe'

        run_process([
            'clang', c, '-o', native, OPTIMIZATIONS, '-lm',
            '-DWASM_RT_MAX_CALL_STACK_DEPTH=8000'
        ])  # for havlak

        self.filename = native
Exemple #5
0
 def try_js(args=[]):
     shared.try_delete(filename + '.js')
     js_args = [shared.EMCC, fullname, '-o', filename + '.js'
                ] + [opts] + llvm_opts + CSMITH_CFLAGS + args + ['-w']
     if TEST_BINARYEN:
         if random.random() < 0.5:
             js_args += ['-g']
         if random.random() < 0.5:
             # pick random passes
             BINARYEN_EXTRA_PASSES = [
                 "code-pushing",
                 "duplicate-function-elimination",
                 "dce",
                 "remove-unused-brs",
                 "remove-unused-names",
                 "local-cse",
                 "optimize-instructions",
                 "post-emscripten",
                 "precompute",
                 "simplify-locals",
                 "simplify-locals-nostructure",
                 "vacuum",
                 "coalesce-locals",
                 "reorder-locals",
                 "merge-blocks",
                 "remove-unused-module-elements",
                 "memory-packing",
             ]
             passes = []
             while 1:
                 passes.append(random.choice(BINARYEN_EXTRA_PASSES))
                 if random.random() < 0.1:
                     break
             js_args += [
                 '-s', 'BINARYEN_EXTRA_PASSES="' + ','.join(passes) + '"'
             ]
     if random.random() < 0.5:
         js_args += ['-s', 'ALLOW_MEMORY_GROWTH=1']
     if random.random(
     ) < 0.5 and 'ALLOW_MEMORY_GROWTH=1' not in js_args and 'BINARYEN=1' not in js_args:
         js_args += ['-s', 'MAIN_MODULE=1']
     if random.random() < 0.25:
         js_args += ['-s', 'INLINING_LIMIT=1'
                     ]  # inline nothing, for more call interaction
     if random.random() < 0.5:
         js_args += ["--memory-init-file", "0", "-s", "MEM_INIT_METHOD=2"]
     if random.random() < 0.5:
         js_args += ['-s', 'ASSERTIONS=1']
     print('(compile)', ' '.join(js_args))
     short_args = [shared.EMCC, fail_output_name] + js_args[5:]
     escaped_short_args = map(lambda x: ("'" + x + "'")
                              if '"' in x else x, short_args)
     open(fullname,
          'a').write('\n// ' + ' '.join(escaped_short_args) + '\n\n')
     try:
         shared.run_process(js_args)
         assert os.path.exists(filename + '.js')
         return js_args
     except Exception:
         return False
Exemple #6
0
    def setUpClass(cls):
        super(benchmark, cls).setUpClass()

        for benchmarker in benchmarkers:
            benchmarker.prepare()

        fingerprint = [
            'ignoring compilation'
            if IGNORE_COMPILATION else 'including compilation',
            time.asctime()
        ]
        try:
            fingerprint.append('em: ' + run_process(
                ['git', 'show'], stdout=PIPE).stdout.splitlines()[0])
        except Exception:
            pass
        try:
            with runner.chdir(os.path.expanduser('~/Dev/mozilla-central')):
                fingerprint.append('sm: ' + [
                    line for line in run_process(['hg', 'tip'], stdout=PIPE).
                    stdout.splitlines() if 'changeset' in line
                ][0])
        except Exception:
            pass
        fingerprint.append('llvm: ' + config.LLVM_ROOT)
        print('Running Emscripten benchmarks... [ %s ]' %
              ' | '.join(fingerprint))
Exemple #7
0
 def create_optimizer():
     shared.logging.debug('building native optimizer: ' + name)
     output = shared.Cache.get_path(name)
     shared.try_delete(output)
     for compiler in [
             shared.CLANG_CXX, 'g++', 'clang++'
     ]:  # try our clang first, otherwise hope for a system compiler in the path
         shared.logging.debug('  using ' + compiler)
         try:
             shared.run_process([
                 compiler,
                 shared.path_from_root('tools', 'optimizer',
                                       'parser.cpp'),
                 shared.path_from_root('tools', 'optimizer',
                                       'simple_ast.cpp'),
                 shared.path_from_root('tools', 'optimizer',
                                       'optimizer.cpp'),
                 shared.path_from_root('tools', 'optimizer',
                                       'optimizer-shared.cpp'),
                 shared.path_from_root('tools', 'optimizer',
                                       'optimizer-main.cpp'), '-O3',
                 '-std=c++11', '-fno-exceptions', '-fno-rtti', '-o',
                 output
             ] + args,
                                stdout=log_output,
                                stderr=log_output)
         except Exception as e:
             logging.debug(str(e))
             continue  # perhaps the later compilers will succeed
         # success
         return output
     shared.exit_with_error('Failed to build native optimizer')
    def test_emcc_cache_flag(self):
        restore_and_set_up()

        cache_dir_name = self.in_dir('emscripten_cache')
        self.assertFalse(os.path.exists(cache_dir_name))
        create_test_file(
            'test.c', r'''
      #include <stdio.h>
      int main() {
        printf("hello, world!\n");
        return 0;
      }
      ''')
        run_process([PYTHON, EMCC, 'test.c', '--cache', cache_dir_name],
                    stderr=PIPE)
        # The cache directory must exist after the build
        self.assertTrue(os.path.exists(cache_dir_name))
        # The cache directory must contain a built libc'
        if self.is_wasm_backend():
            self.assertTrue(
                os.path.exists(os.path.join(cache_dir_name, 'wasm_o',
                                            'libc.a')))
        else:
            self.assertTrue(
                os.path.exists(os.path.join(cache_dir_name, 'asmjs',
                                            'libc.bc')))
Exemple #9
0
    def test_emconfig(self):
        restore_and_set_up()

        fd, custom_config_filename = tempfile.mkstemp(
            prefix='.emscripten_config_')

        orig_config = open(CONFIG_FILE, 'r').read()

        # Move the ~/.emscripten to a custom location.
        with os.fdopen(fd, "w") as f:
            f.write(orig_config)

        # Make a syntax error in the original config file so that attempting to access it would fail.
        open(CONFIG_FILE, 'w').write('asdfasdfasdfasdf\n\'\'\'' + orig_config)

        temp_dir = tempfile.mkdtemp(prefix='emscripten_temp_')

        with chdir(temp_dir):
            run_process([EMCC, '--em-config', custom_config_filename] +
                        MINIMAL_HELLO_WORLD + ['-O2'])
            result = run_js('a.out.js')

        self.assertContained('hello, world!', result)

        # Clean up created temp files.
        os.remove(custom_config_filename)
        if Settings.WASM_BACKEND:
            os.remove(custom_config_filename + "_sanity_wasm")
        else:
            os.remove(custom_config_filename + "_sanity")
        shutil.rmtree(temp_dir)
Exemple #10
0
    def __enter__(self):
        # assuming this is only used for WebSocket tests at the moment, validate that
        # the ws module is installed
        child = run_process(NODE_JS + ['-e', 'require("ws");'], check=False)
        global node_ws_module_installed
        # Attempt to automatically install ws module for Node.js.
        if child.returncode != 0 and not node_ws_module_installed:
            node_ws_module_installed = True
            run_process(
                [NPM, 'install',
                 path_from_root('tests', 'sockets', 'ws')],
                cwd=os.path.dirname(EMCC))
            # Did installation succeed?
            child = run_process(NODE_JS + ['-e', 'require("ws");'],
                                check=False)
        assert child.returncode == 0, 'ws module for Node.js not installed, and automatic installation failed! Please run \'npm install\' from %s' % shared.__rootpath__

        # compile the server
        proc = run_process([
            PYTHON, EMCC,
            path_from_root('tests', self.filename), '-o', 'server.js',
            '-DSOCKK=%d' % self.listen_port
        ] + self.args)
        print('Socket server build: out:', proc.stdout or '', '/ err:',
              proc.stderr or '')

        process = Popen(NODE_JS + ['server.js'])
        self.processes.append(process)
Exemple #11
0
    def setUpClass(self):
        super(benchmark, self).setUpClass()

        fingerprint = [
            'ignoring compilation'
            if IGNORE_COMPILATION else 'including compilation',
            time.asctime()
        ]
        try:
            fingerprint.append('em: ' + run_process(
                ['git', 'show'], stdout=PIPE).stdout.splitlines()[0])
        except:
            pass
        try:
            with chdir(os.path.expanduser('~/Dev/mozilla-central')):
                fingerprint.append('sm: ' + [
                    line for line in run_process(['hg', 'tip'], stdout=PIPE).
                    stdout.splitlines() if 'changeset' in line
                ][0])
        except:
            pass
        fingerprint.append('llvm: ' + LLVM_ROOT)
        print('Running Emscripten benchmarks... [ %s ]' %
              ' | '.join(fingerprint))

        assert (os.path.exists(CLOSURE_COMPILER))

        Building.COMPILER = CLANG
        Building.COMPILER_TEST_OPTS = [OPTIMIZATIONS]
Exemple #12
0
def run():
    if shared.Settings.WASM_BACKEND:
        # The wasm backend does suffer from the same probllem as fastcomp so doesn't
        # need the filename hashing.
        cmd = [shared.LLVM_AR] + sys.argv[1:]
        return shared.run_process(cmd, stdin=sys.stdin, check=False).returncode

    try:
        args = substitute_response_files(sys.argv)
    except IOError as e:
        shared.exit_with_error(e)
    newargs = [shared.LLVM_AR] + args[1:]

    tmpdir = None
    response_filename = None

    # The 3 argmuent form of ar doesn't involve other files. For example
    # 'ar x libfoo.a'.
    if len(newargs) > 3:
        tmpdir = tempfile.mkdtemp(prefix='emar-')
        cmd = newargs[1]
        if 'r' in cmd or 'q' in cmd:
            # We are adding files to the archive.
            # Normally the output file is then arg 2, except in the case were the
            # a or b modifiers are used in which case its arg 3.
            if 'a' in cmd or 'b' in cmd:
                out_arg_index = 3
            else:
                out_arg_index = 2

            # Add a hash to colliding basename, to make them unique.
            for j in range(out_arg_index + 1, len(newargs)):
                orig_name = newargs[j]
                full_name = os.path.abspath(orig_name)
                basename = os.path.basename(full_name)

                h = hashlib.md5(full_name.encode('utf-8')).hexdigest()[:8]
                parts = basename.split('.')
                parts[0] += '_' + h
                newname = '.'.join(parts)
                full_newname = os.path.join(tmpdir, newname)
                shutil.copyfile(orig_name, full_newname)
                newargs[j] = full_newname

        if shared.DEBUG:
            print('emar:', sys.argv, '  ==>  ', newargs, file=sys.stderr)
        response_filename = create_response_file(
            newargs[3:], shared.get_emscripten_temp_dir())
        newargs = newargs[:3] + ['@' + response_filename]

    if shared.DEBUG:
        print('emar:', sys.argv, '  ==>  ', newargs, file=sys.stderr)

    rtn = shared.run_process(newargs, stdin=sys.stdin, check=False).returncode
    if tmpdir:
        shutil.rmtree(tmpdir)
        shared.try_delete(response_filename)
    return rtn
Exemple #13
0
 def test_embuilder_wasm_backend(self):
     if not Settings.WASM_BACKEND:
         self.skipTest('wasm backend only')
     restore_and_set_up()
     # the --lto flag makes us build wasm-bc
     self.do([EMCC, '--clear-cache'])
     run_process([EMBUILDER, 'build', 'libemmalloc'])
     self.assertExists(os.path.join(shared.CACHE, 'wasm'))
     self.do([EMCC, '--clear-cache'])
     run_process([EMBUILDER, 'build', 'libemmalloc', '--lto'])
     self.assertExists(os.path.join(shared.CACHE, 'wasm-lto'))
Exemple #14
0
 def build(self, parent, filename, args, shared_args, emcc_args,
           native_args, native_exec, lib_builder, has_output_parser):
     cheerp_args = [
         '-fno-math-errno',
     ]
     cheerp_args += self.args
     self.parent = parent
     if lib_builder:
         # build as "native" (so no emcc env stuff), but with all the cheerp stuff
         # set in the env
         cheerp_args = cheerp_args + lib_builder(
             self.name,
             native=True,
             env_init={
                 'CC': CHEERP_BIN + 'clang',
                 'CXX': CHEERP_BIN + 'clang++',
                 'AR': CHEERP_BIN + '../libexec/cheerp-unknown-none-ar',
                 'LD': CHEERP_BIN + 'clang',
                 'NM': CHEERP_BIN + 'llvm-nm',
                 'LDSHARED': CHEERP_BIN + 'clang',
                 'RANLIB':
                 CHEERP_BIN + '../libexec/cheerp-unknown-none-ranlib',
                 'CXXFLAGS': "-Wno-c++11-narrowing",
                 'CHEERP_PREFIX': CHEERP_BIN + '../',
             })
     if PROFILING:
         cheerp_args += ['-cheerp-pretty-code'
                         ]  # get function names, like emcc --profiling
     final = os.path.dirname(filename) + os.path.sep + self.name + (
         '_' if self.name else '') + os.path.basename(filename) + '.js'
     final = final.replace('.cpp', '')
     try_delete(final)
     dirs_to_delete = []
     cheerp_args += ['-cheerp-preexecute']
     try:
         # print(cheerp_args)
         if filename.endswith('.c'):
             compiler = CHEERP_BIN + '/clang'
         else:
             compiler = CHEERP_BIN + '/clang++'
         cmd = [compiler] + cheerp_args + [
             '-cheerp-linear-heap-size=256',
             '-cheerp-secondary-output-file=' +
             final.replace('.js', '.wasm'), filename, '-o', final
         ] + shared_args
         # print(' '.join(cmd))
         run_process(cmd, stdout=PIPE, stderr=PIPE)
         self.filename = final
         if self.binaryen_opts:
             run_binaryen_opts(final.replace('.js', '.wasm'),
                               self.binaryen_opts)
     finally:
         for dir_ in dirs_to_delete:
             try_delete(dir_)
Exemple #15
0
 def test_embuilder_wasm_backend(self):
     if not Settings.WASM_BACKEND:
         self.skipTest('wasm backend only')
     restore_and_set_up()
     root_cache = os.path.expanduser('~/.emscripten_cache')
     # the --lto flag makes us build wasm-bc
     self.do([EMCC, '--clear-cache'])
     run_process([EMBUILDER, 'build', 'libemmalloc'])
     self.assertExists(os.path.join(root_cache, 'wasm-obj'))
     self.do([EMCC, '--clear-cache'])
     run_process([EMBUILDER, 'build', 'libemmalloc', '--lto'])
     self.assertExists(os.path.join(root_cache, 'wasm-bc'))
Exemple #16
0
  def test_posix_proxy_sockets(self):
    # Build the websocket bridge server
    run_process(['cmake', path_from_root('tools', 'websocket_to_posix_proxy')])
    run_process(['cmake', '--build', '.'])
    if os.name == 'nt': # This is not quite exact, instead of "isWindows()" this should be "If CMake defaults to building with Visual Studio", but there is no good check for that, so assume Windows==VS.
      proxy_server = os.path.join(self.get_dir(), 'Debug', 'websocket_to_posix_proxy.exe')
    else:
      proxy_server = os.path.join(self.get_dir(), 'websocket_to_posix_proxy')

    with BackgroundServerProcess([proxy_server, '8080']):
      with PythonTcpEchoServerProcess('7777'):
        # Build and run the TCP echo client program with Emscripten
        self.btest(path_from_root('tests', 'websocket', 'tcp_echo_client.cpp'), expected='101', args=['-lwebsocket', '-s', 'PROXY_POSIX_SOCKETS=1', '-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1'])
Exemple #17
0
  def test_enet(self):
    # this is also a good test of raw usage of emconfigure and emmake
    shared.try_delete('enet')
    shutil.copytree(path_from_root('tests', 'enet'), 'enet')
    with chdir('enet'):
      run_process([path_from_root('emconfigure'), './configure'])
      run_process([path_from_root('emmake'), 'make'])
      enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I' + path_from_root('tests', 'enet', 'include')]

    for harness in [
      CompiledServerHarness(os.path.join('sockets', 'test_enet_server.c'), enet, 49210)
    ]:
      with harness:
        self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=enet + ['-DSOCKK=%d' % harness.listen_port])
Exemple #18
0
  def test_enet(self):
    # this is also a good test of raw usage of emconfigure and emmake
    shared.try_delete(self.in_dir('enet'))
    shutil.copytree(path_from_root('tests', 'enet'), self.in_dir('enet'))
    with chdir(self.in_dir('enet')):
      run_process([PYTHON, path_from_root('emconfigure'), './configure'])
      run_process([PYTHON, path_from_root('emmake'), 'make'])
      enet = [self.in_dir('enet', '.libs', 'libenet.a'), '-I' + path_from_root('tests', 'enet', 'include')]

    for harness in [
      CompiledServerHarness(os.path.join('sockets', 'test_enet_server.c'), enet, 49210)
    ]:
      with harness:
        self.btest(os.path.join('sockets', 'test_enet_client.c'), expected='0', args=enet + ['-DSOCKK=%d' % harness.listen_port])
Exemple #19
0
    def __enter__(self):
        # compile the server
        # NOTE empty filename support is a hack to support
        # the current test_enet
        if self.filename:
            cmd = [
                CLANG_CC,
                test_file(self.filename), '-o', 'server',
                '-DSOCKK=%d' % self.target_port
            ] + clang_native.get_clang_native_args() + self.args
            print(cmd)
            run_process(cmd, env=clang_native.get_clang_native_env())
            process = Popen([os.path.abspath('server')])
            self.processes.append(process)

        import websockify

        # start the websocket proxy
        print('running websockify on %d, forward to tcp %d' %
              (self.listen_port, self.target_port),
              file=sys.stderr)
        wsp = websockify.WebSocketProxy(verbose=True,
                                        listen_port=self.listen_port,
                                        target_host="127.0.0.1",
                                        target_port=self.target_port,
                                        run_once=True)
        self.websockify = multiprocessing.Process(target=wsp.start_server)
        self.websockify.start()
        self.processes.append(self.websockify)
        # Make sure both the actual server and the websocket proxy are running
        for _ in range(10):
            try:
                if self.do_server_check:
                    server_sock = socket.create_connection(
                        ('localhost', self.target_port), timeout=1)
                    server_sock.close()
                proxy_sock = socket.create_connection(
                    ('localhost', self.listen_port), timeout=1)
                proxy_sock.close()
                break
            except IOError:
                time.sleep(1)
        else:
            clean_processes(self.processes)
            raise Exception(
                '[Websockify failed to start up in a timely manner]')

        print('[Websockify on process %s]' % str(self.processes[-2:]))
        return self
Exemple #20
0
  def __enter__(self):
    # assuming this is only used for WebSocket tests at the moment, validate that
    # the ws module is installed
    global npm_checked
    if not npm_checked:
      child = run_process(NODE_JS + ['-e', 'require("ws");'], check=False)
      assert child.returncode == 0, '"ws" node module not found.  you may need to run npm install'
      npm_checked = True

    # compile the server
    proc = run_process([EMCC, path_from_root('tests', self.filename), '-o', 'server.js', '-DSOCKK=%d' % self.listen_port] + self.args)
    print('Socket server build: out:', proc.stdout or '', '/ err:', proc.stderr or '')

    process = Popen(NODE_JS + ['server.js'])
    self.processes.append(process)
Exemple #21
0
    def test_sdl2_mixer_mp3(self):
        shutil.copyfile(path_from_root('tests', 'sounds', 'pudinha.mp3'),
                        os.path.join(self.get_dir(), 'sound.mp3'))
        open(os.path.join(self.get_dir(), 'sdl2_mixer_mp3.c'), 'w').write(
            self.with_report_result(
                open(path_from_root('tests', 'sdl2_mixer_mp3.c')).read()))

        run_process([
            EMCC, '-O2', '--minify', '0',
            os.path.join(self.get_dir(), 'sdl2_mixer_mp3.c'), '-s',
            'USE_SDL=2', '-s', 'USE_SDL_MIXER=2', '-s',
            'SDL2_MIXER_FORMATS=["mp3"]', '-s', 'INITIAL_MEMORY=33554432',
            '--preload-file', 'sound.mp3', '-o', 'page.html'
        ])
        self.run_browser('page.html', '', '/report_result?1')
Exemple #22
0
def validate_asmjs_jsfile(filename, muteOutput):
    cmd = shared.SPIDERMONKEY_ENGINE + ['-c', filename]
    if not shared.SPIDERMONKEY_ENGINE or cmd[0] == 'js-not-found' or len(
            cmd[0].strip()) == 0:
        print(
            'Could not find SpiderMonkey engine! Please set its location to SPIDERMONKEY_ENGINE in your '
            + shared.hint_config_file_location() + ' configuration file!',
            file=sys.stderr)
        return False
    try:
        process = shared.run_process(cmd,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     stdin=subprocess.PIPE)
    except Exception as e:
        print('Executing command ' + str(cmd) +
              ' failed due to an exception: ' + str(e) + '!',
              file=sys.stderr)
        return False
    stdout = process.stdout
    stderr = process.stderr
    if not muteOutput:
        if len(stdout.strip()):
            print(stdout.strip())
        if len(stderr.strip()):
            # Pretty-print the output not to contain a spurious warning.
            warning_re = re.compile(
                re.escape('warning: successfully compiled asm.js'),
                re.IGNORECASE)
            stderr = warning_re.sub(' successfully compiled asm.js', stderr)
            print(stderr.strip(), file=sys.stderr)
    if 'successfully compiled asm.js' in stderr.lower():
        return True
    else:
        return False
Exemple #23
0
def run_on_chunk(command):
  try:
    if JS_OPTIMIZER in command: # XXX hackish
      index = command.index(JS_OPTIMIZER)
      filename = command[index + 1]
    else:
      filename = command[1]
    if os.environ.get('EMCC_SAVE_OPT_TEMP') and os.environ.get('EMCC_SAVE_OPT_TEMP') != '0':
      saved = 'save_' + os.path.basename(filename)
      while os.path.exists(saved): saved = 'input' + str(int(saved.replace('input', '').replace('.txt', ''))+1) + '.txt'
      print('running js optimizer command', ' '.join([c if c != filename else saved for c in command]), file=sys.stderr)
      shutil.copyfile(filename, os.path.join(shared.get_emscripten_temp_dir(), saved))
    if shared.EM_BUILD_VERBOSE >= 3: print('run_on_chunk: ' + str(command), file=sys.stderr)
    proc = shared.run_process(command, stdout=subprocess.PIPE)
    output = proc.stdout
    assert proc.returncode == 0, 'Error in optimizer (return code ' + str(proc.returncode) + '): ' + output
    assert len(output) and not output.startswith('Assertion failed'), 'Error in optimizer: ' + output
    filename = temp_files.get(os.path.basename(filename) + '.jo.js').name
    f = open(filename, 'w')
    f.write(output)
    f.close()
    if DEBUG and not shared.WINDOWS: print('.', file=sys.stderr) # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console.
    return filename
  except KeyboardInterrupt:
    # avoid throwing keyboard interrupts from a child process
    raise Exception()
Exemple #24
0
  def test_em_config_env_var(self):
    # emcc should be configurable directly from EM_CONFIG without any config file
    restore_and_set_up()
    create_test_file('main.cpp', '''
      #include <stdio.h>
      int main() {
        printf("hello from emcc with no config file\\n");
        return 0;
      }
    ''')

    wipe()
    with env_modify({'EM_CONFIG': get_basic_config()}):
      run_process([EMCC, 'main.cpp', '-o', 'a.out.js'])

    self.assertContained('hello from emcc with no config file', run_js('a.out.js'))
Exemple #25
0
    def build(self, parent, filename, args, shared_args, emcc_args,
              native_args, native_exec, lib_builder, has_output_parser):
        self.parent = parent
        if lib_builder:
            native_args += lib_builder(self.name,
                                       native=True,
                                       env_init={
                                           'CC': self.cc,
                                           'CXX': self.cxx
                                       })
        if not native_exec:
            compiler = self.cxx if filename.endswith('cpp') else self.cc
            cmd = [
                compiler, '-fno-math-errno', filename, '-o',
                filename + '.native'
            ] + self.args + shared_args + native_args + shared.get_clang_native_args(
            )
            proc = run_process(cmd,
                               stdout=PIPE,
                               stderr=parent.stderr_redirect,
                               env=shared.get_clang_native_env())
            if proc.returncode != 0:
                print("Building native executable with command failed",
                      ' '.join(cmd),
                      file=sys.stderr)
                print("Output: " + str(proc.stdout) + '\n' + str(proc.stderr))
        else:
            shutil.copyfile(native_exec, filename + '.native')
            shutil.copymode(native_exec, filename + '.native')

        final = os.path.dirname(
            filename) + os.path.sep + self.name + '_' + os.path.basename(
                filename) + '.native'
        shutil.move(filename + '.native', final)
        self.filename = final
def generate_symbol_file(symbol_file, lib_file):
  """Regenerate the contents of a given symbol file."""
  output = shared.run_process([shared.LLVM_NM, '-g', lib_file, '-defined-only'],
                              stdout=shared.PIPE).stdout
  new_symbols = filter_and_sort(output)
  with open(symbol_file, 'w') as f:
    f.write(new_symbols)
def handle_symbol_file(args, symbol_file):
    """Regenerate the contents of a given symbol file."""

    if args.filter_in_place:
        output = open(symbol_file).read()
    else:
        basename = os.path.splitext(os.path.basename(symbol_file))[0]
        if not basename.startswith('lib'):
            basename = 'lib' + basename
        if basename.endswith('_asmjs'):
            basename = basename.rsplit('_asmjs', 1)[0]
        basename = basename.replace('cxx', 'c++')
        cache_dir = cache.Cache().dirname
        pattern = os.path.join(cache_dir, basename + '.*')
        libs = glob.glob(pattern)
        if basename == 'libgl':
            # For libgl we generate the symbol list based on a superset of all
            # library variants.
            pattern = os.path.join(cache_dir, basename + '-*.*')
            libs += glob.glob(pattern)
        if not libs:
            print(cache_dir)
            print("%s: Unable to find library to generate symbols from" %
                  symbol_file)
            return
        print('Generating %s based on syms from: %s' % (basename, libs))
        output = ''
        for lib in libs:
            output += shared.run_process([shared.LLVM_NM, '-g', lib],
                                         stdout=shared.PIPE).stdout
    new_symbols = filter_and_sort(output)

    with open(symbol_file, 'w') as f:
        f.write(new_symbols)
Exemple #28
0
def run_on_chunk(command):
  try:
    if JS_OPTIMIZER in command: # XXX hackish
      index = command.index(JS_OPTIMIZER)
      filename = command[index + 1]
    else:
      filename = command[1]
    if os.environ.get('EMCC_SAVE_OPT_TEMP') and os.environ.get('EMCC_SAVE_OPT_TEMP') != '0':
      saved = 'save_' + os.path.basename(filename)
      while os.path.exists(saved): saved = 'input' + str(int(saved.replace('input', '').replace('.txt', ''))+1) + '.txt'
      print('running js optimizer command', ' '.join([c if c != filename else saved for c in command]), file=sys.stderr)
      shutil.copyfile(filename, os.path.join(shared.get_emscripten_temp_dir(), saved))
    if shared.EM_BUILD_VERBOSE >= 3: print('run_on_chunk: ' + str(command), file=sys.stderr)
    proc = shared.run_process(command, stdout=subprocess.PIPE)
    output = proc.stdout
    assert proc.returncode == 0, 'Error in optimizer (return code ' + str(proc.returncode) + '): ' + output
    assert len(output) and not output.startswith('Assertion failed'), 'Error in optimizer: ' + output
    filename = temp_files.get(os.path.basename(filename) + '.jo.js').name
    with open(filename, 'w') as f:
      f.write(output)
    if DEBUG and not shared.WINDOWS: print('.', file=sys.stderr) # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console.
    return filename
  except KeyboardInterrupt:
    # avoid throwing keyboard interrupts from a child process
    raise Exception()
Exemple #29
0
  def __enter__(self):
    # compile the server
    # NOTE empty filename support is a hack to support
    # the current test_enet
    if self.filename:
      proc = run_process([CLANG_CC, path_from_root('tests', self.filename), '-o', 'server', '-DSOCKK=%d' % self.target_port] + shared.get_clang_native_args() + self.args, env=shared.get_clang_native_env(), stdout=PIPE, stderr=PIPE)
      print('Socket server build: out:', proc.stdout or '', '/ err:', proc.stderr or '')
      process = Popen([os.path.abspath('server')])
      self.processes.append(process)

    # start the websocket proxy
    print('running websockify on %d, forward to tcp %d' % (self.listen_port, self.target_port), file=sys.stderr)
    wsp = websockify.WebSocketProxy(verbose=True, listen_port=self.listen_port, target_host="127.0.0.1", target_port=self.target_port, run_once=True)
    self.websockify = multiprocessing.Process(target=wsp.start_server)
    self.websockify.start()
    self.processes.append(self.websockify)
    # Make sure both the actual server and the websocket proxy are running
    for i in range(10):
      try:
        if self.do_server_check:
            server_sock = socket.create_connection(('localhost', self.target_port), timeout=1)
            server_sock.close()
        proxy_sock = socket.create_connection(('localhost', self.listen_port), timeout=1)
        proxy_sock.close()
        break
      except:
        time.sleep(1)
    else:
      clean_processes(self.processes)
      raise Exception('[Websockify failed to start up in a timely manner]')

    print('[Websockify on process %s]' % str(self.processes[-2:]))
Exemple #30
0
  def test_emcc_multiprocess_cache_access(self):
    restore_and_set_up()

    create_test_file('test.c', r'''
      #include <stdio.h>
      int main() {
        printf("hello, world!\n");
        return 0;
      }
      ''')
    cache_dir_name = self.in_dir('test_cache')
    with env_modify({'EM_CACHE': cache_dir_name}):
      tasks = []
      num_times_libc_was_built = 0
      for i in range(3):
        p = run_process([EMCC, 'test.c', '-o', '%d.js' % i], stderr=STDOUT, stdout=PIPE)
        tasks += [p]
      for p in tasks:
        print('stdout:\n', p.stdout)
        if 'generating system library: libc' in p.stdout:
          num_times_libc_was_built += 1

    # The cache directory must exist after the build
    self.assertTrue(os.path.exists(cache_dir_name))
    # The cache directory must contain a built libc
    if self.is_wasm_backend():
      self.assertTrue(os.path.exists(os.path.join(cache_dir_name, 'wasm-obj', 'libc.a')))
    else:
      self.assertTrue(os.path.exists(os.path.join(cache_dir_name, 'asmjs', 'libc.bc')))
    # Exactly one child process should have triggered libc build!
    self.assertEqual(num_times_libc_was_built, 1)
Exemple #31
0
  def do(self, command):
    print('Running: ' + ' '.join(command))
    if type(command) is not list:
      command = [command]
    if command[0] == EMCC:
      command = [PYTHON] + command

    return run_process(command, stdout=PIPE, stderr=STDOUT, check=False).stdout
Exemple #32
0
  def do(self, command):
    print('Running: ' + ' '.join(command))
    if type(command) is not list:
      command = [command]
    if command[0] == EMCC:
      command = [PYTHON] + command

    return run_process(command, stdout=PIPE, stderr=STDOUT, check=False).stdout
Exemple #33
0
def run():
    try:
        args = substitute_response_files(sys.argv)
    except IOError as e:
        shared.exit_with_error(e)
    newargs = [shared.LLVM_AR] + args[1:]

    to_delete = []

    # The 3 argmuent form of ar doesn't involve other files. For example
    # 'ar x libfoo.a'.
    if len(newargs) > 3:
        cmd = newargs[1]
        if 'r' in cmd or 'q' in cmd:
            # We are adding files to the archive.
            # Normally the output file is then arg 2, except in the case were the
            # a or b modifiers are used in which case its arg 3.
            if 'a' in cmd or 'b' in cmd:
                out_arg_index = 3
            else:
                out_arg_index = 2

            # Add a hash to colliding basename, to make them unique.
            for j in range(out_arg_index + 1, len(newargs)):
                orig_name = newargs[j]
                full_name = os.path.abspath(orig_name)
                dirname = os.path.dirname(full_name)
                basename = os.path.basename(full_name)

                h = hashlib.md5(full_name.encode('utf-8')).hexdigest()[:8]
                parts = basename.split('.')
                parts[0] += '_' + h
                newname = '.'.join(parts)
                full_newname = os.path.join(dirname, newname)
                try:
                    shutil.copyfile(orig_name, full_newname)
                    newargs[j] = full_newname
                    to_delete.append(full_newname)
                except Exception:
                    # it is ok to fail here, we just don't get hashing
                    pass

        if shared.DEBUG:
            print('emar:', sys.argv, '  ==>  ', newargs, file=sys.stderr)

        response_filename = create_response_file(
            newargs[3:], shared.get_emscripten_temp_dir())
        to_delete += [response_filename]
        newargs = newargs[:3] + ['@' + response_filename]

    if shared.DEBUG:
        print('emar:', sys.argv, '  ==>  ', newargs, file=sys.stderr)

    rtn = shared.run_process(newargs, stdin=sys.stdin, check=False).returncode
    for d in to_delete:
        shared.try_delete(d)
    return rtn
Exemple #34
0
    def do(self, command, env=None):
        print('Running: ' + ' '.join(command))
        if type(command) is not list:
            command = [command]

        return run_process(command,
                           stdout=PIPE,
                           stderr=STDOUT,
                           check=False,
                           env=env).stdout
Exemple #35
0
  def __enter__(self):
    # assuming this is only used for WebSocket tests at the moment, validate that
    # the ws module is installed
    child = run_process(NODE_JS + ['-e', 'require("ws");'], check=False)
    global node_ws_module_installed
    # Attempt to automatically install ws module for Node.js.
    if child.returncode != 0 and not node_ws_module_installed:
      node_ws_module_installed = True
      run_process([NPM, 'install', path_from_root('tests', 'sockets', 'ws')], cwd=os.path.dirname(EMCC))
      # Did installation succeed?
      child = run_process(NODE_JS + ['-e', 'require("ws");'], check=False)
    assert child.returncode == 0, 'ws module for Node.js not installed, and automatic installation failed! Please run \'npm install\' from %s' % shared.__rootpath__

    # compile the server
    proc = run_process([PYTHON, EMCC, path_from_root('tests', self.filename), '-o', 'server.js', '-DSOCKK=%d' % self.listen_port] + self.args)
    print('Socket server build: out:', proc.stdout or '', '/ err:', proc.stderr or '')

    process = Popen(NODE_JS + ['server.js'])
    self.processes.append(process)
Exemple #36
0
  def setUpClass(self):
    super(benchmark, self).setUpClass()

    fingerprint = ['ignoring compilation' if IGNORE_COMPILATION else 'including compilation', time.asctime()]
    try:
      fingerprint.append('em: ' + run_process(['git', 'show'], stdout=PIPE).stdout.splitlines()[0])
    except:
      pass
    try:
      with chdir(os.path.expanduser('~/Dev/mozilla-central')):
        fingerprint.append('sm: ' + [line for line in run_process(['hg', 'tip'], stdout=PIPE).stdout.splitlines() if 'changeset' in line][0])
    except:
      pass
    fingerprint.append('llvm: ' + LLVM_ROOT)
    print('Running Emscripten benchmarks... [ %s ]' % ' | '.join(fingerprint))

    assert(os.path.exists(CLOSURE_COMPILER))

    Building.COMPILER = CLANG
    Building.COMPILER_TEST_OPTS = [OPTIMIZATIONS]
Exemple #37
0
  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
Exemple #38
0
  def handle_static_lib(self, f):
    temp_dir = tempfile.mkdtemp('_archive_contents', 'emscripten_temp_')
    with chdir(temp_dir):
      contents = [x for x in run_process([CHEERP_BIN + 'llvm-ar', 't', f], stdout=PIPE).stdout.splitlines() if len(x)]
      shared.warn_if_duplicate_entries(contents, f)
      if len(contents) == 0:
        print('Archive %s appears to be empty (recommendation: link an .so instead of .a)' % f)
        return {
          'returncode': 0,
          'dir': temp_dir,
          'files': []
        }

      # We are about to ask llvm-ar to extract all the files in the .a archive file, but
      # it will silently fail if the directory for the file does not exist, so make all the necessary directories
      for content in contents:
        dirname = os.path.dirname(content)
        if dirname:
          shared.safe_ensure_dirs(dirname)
      proc = run_process([CHEERP_BIN + 'llvm-ar', 'xo', f], stdout=PIPE, stderr=PIPE)
      # if absolute paths, files will appear there. otherwise, in this directory
      contents = list(map(os.path.abspath, contents))
      nonexisting_contents = [x for x in contents if not os.path.exists(x)]
      if len(nonexisting_contents) != 0:
        raise Exception('llvm-ar failed to extract file(s) ' + str(nonexisting_contents) + ' from archive file ' + f + '!  Error:' + str(proc.stdout) + str(proc.stderr))

      return {
        'returncode': proc.returncode,
        'dir': temp_dir,
        'files': contents
      }

    return {
      'returncode': 1,
      'dir': None,
      'files': []
    }
def process_shell(js_engine, shell, equivalentfn_hash_info=None):
  suffix = '.eliminatedupes'

  with temp_files.get_file(suffix + '.js') as temp_file:
    f = open(temp_file, 'w')
    f.write(shell)
    f.write('\n')

    f.write(equivalentfn_hash_info)
    f.close()

    proc = shared.run_process(js_engine +
        [DUPLICATE_FUNCTION_ELIMINATOR, temp_file, '--use-hash-info', '--no-minimize-whitespace'],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  assert len(proc.stdout) > 0
  assert len(proc.stderr) == 0

  return proc.stdout
Exemple #40
0
  def minify_shell(self, shell, minify_whitespace, source_map=False):
    # Run through js-optimizer.js to find and minify the global symbols
    # We send it the globals, which it parses at the proper time. JS decides how
    # to minify all global names, we receive a dictionary back, which is then
    # used by the function processors

    shell = shell.replace('0.0', '13371337') # avoid uglify doing 0.0 => 0

    # Find all globals in the JS functions code

    if not self.profiling_funcs:
      self.globs = [m.group(1) for m in func_sig.finditer(self.js)]
      if len(self.globs) == 0:
        self.globs = [m.group(1) for m in func_sig_json.finditer(self.js)]
    else:
      self.globs = []

    with temp_files.get_file('.minifyglobals.js') as temp_file:
      f = open(temp_file, 'w')
      f.write(shell)
      f.write('\n')
      f.write('// EXTRA_INFO:' + json.dumps(self.serialize()))
      f.close()

      output = shared.run_process(self.js_engine +
          [JS_OPTIMIZER, temp_file, 'minifyGlobals', 'noPrintMetadata'] +
          (['minifyWhitespace'] if minify_whitespace else []) +
          (['--debug'] if source_map else []),
          stdout=subprocess.PIPE).stdout

    assert len(output) and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output
    #print >> sys.stderr, "minified SHELL 3333333333333333", output, "\n44444444444444444444"
    code, metadata = output.split('// EXTRA_INFO:')
    self.globs = json.loads(metadata)

    if self.symbols_file:
      mapfile = open(self.symbols_file, 'w')
      for key, value in self.globs.items():
        mapfile.write(value + ':' + key + '\n')
      mapfile.close()
      print('wrote symbol map file to', self.symbols_file, file=sys.stderr)

    return code.replace('13371337', '0.0')
Exemple #41
0
def run_on_chunk(command):
  try:
    file_suffix = '.js'
    index = command.index(DUPLICATE_FUNCTION_ELIMINATOR)
    filename = command[index + 1]

    if '--gen-hash-info' in command:
      file_suffix = '.json'

    if os.environ.get('EMCC_SAVE_OPT_TEMP') and os.environ.get('EMCC_SAVE_OPT_TEMP') != '0':
      saved = 'save_' + os.path.basename(filename)
      while os.path.exists(saved):
        saved = 'input' + str(int(saved.replace('input', '').replace('.txt', '')) + 1) + '.txt'
      print('running DFE command', ' '.join([c if c != filename else saved for c in command]), file=sys.stderr)
      shutil.copyfile(filename, os.path.join(shared.get_emscripten_temp_dir(), saved))

    if shared.EM_BUILD_VERBOSE >= 3:
      print('run_on_chunk: ' + str(command), file=sys.stderr)

    proc = shared.run_process(command, stdout=subprocess.PIPE)
    output = proc.stdout
    assert proc.returncode == 0, 'Error in optimizer (return code ' + str(proc.returncode) + '): ' + output
    assert len(output) and not output.startswith('Assertion failed'), 'Error in optimizer: ' + output
    filename = temp_files.get(os.path.basename(filename) + '.dfjo' + file_suffix).name

    f = open(filename, 'w')
    f.write(output)
    f.close()
    if DEBUG and not shared.WINDOWS:
      print('.', file=sys.stderr) # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console.
    return filename
  except KeyboardInterrupt:
    # avoid throwing keyboard interrupts from a child process
    raise Exception()
  except (TypeError, ValueError):
    formatted_lines = traceback.format_exc().splitlines()

    print(">>>>>>>>>>>>>>>>>", file=sys.stderr)
    for formatted_line in formatted_lines:
        print(formatted_line, file=sys.stderr)
    print("<<<<<<<<<<<<<<<<<", file=sys.stderr)

    raise
Exemple #42
0
  def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser):
    self.parent = parent
    if lib_builder:
      native_args += lib_builder(self.name, native=True, env_init={'CC': self.cc, 'CXX': self.cxx})
    if not native_exec:
      compiler = self.cxx if filename.endswith('cpp') else self.cc
      cmd = [
        compiler,
        '-fno-math-errno',
        filename,
        '-o', filename + '.native'
      ] + self.args + shared_args + native_args + shared.get_clang_native_args()
      proc = run_process(cmd, stdout=PIPE, stderr=parent.stderr_redirect, env=shared.get_clang_native_env())
      if proc.returncode != 0:
        print("Building native executable with command failed", ' '.join(cmd), file=sys.stderr)
        print("Output: " + str(proc.stdout) + '\n' + str(proc.stderr))
    else:
      shutil.copyfile(native_exec, filename + '.native')
      shutil.copymode(native_exec, filename + '.native')

    final = os.path.dirname(filename) + os.path.sep + self.name + '_' + os.path.basename(filename) + '.native'
    shutil.move(filename + '.native', final)
    self.filename = final
def validate_asmjs_jsfile(filename, muteOutput):
  cmd = shared.SPIDERMONKEY_ENGINE + ['-c', filename]
  if not shared.SPIDERMONKEY_ENGINE or cmd[0] == 'js-not-found' or len(cmd[0].strip()) == 0:
    print('Could not find SpiderMonkey engine! Please set its location to SPIDERMONKEY_ENGINE in your ' + shared.hint_config_file_location() + ' configuration file!', file=sys.stderr)
    return False
  try:
    process = shared.run_process(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
  except Exception as e:
    print('Executing command ' + str(cmd) + ' failed due to an exception: ' + str(e) + '!', file=sys.stderr)
    return False
  stdout = process.stdout
  stderr = process.stderr
  if not muteOutput:
    if len(stdout.strip()) > 0:
      print(stdout.strip())
    if len(stderr.strip()) > 0:
      # Pretty-print the output not to contain a spurious warning.
      warning_re = re.compile(re.escape('warning: successfully compiled asm.js'), re.IGNORECASE)
      stderr = warning_re.sub(' successfully compiled asm.js', stderr)
      print(stderr.strip(), file=sys.stderr)
  if 'successfully compiled asm.js' in stderr.lower():
    return True
  else:
    return False
Exemple #44
0
  def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser):
    self.filename = filename
    llvm_root = self.env.get('LLVM') or LLVM_ROOT
    if lib_builder:
      emcc_args = emcc_args + lib_builder('js_' + llvm_root, native=False, env_init=self.env.copy())
    open('hardcode.py', 'w').write('''
def process(filename):
  js = open(filename).read()
  replaced = js.replace("run();", "run(%s.concat(Module[\\"arguments\\"]));")
  assert js != replaced
  open(filename, 'w').write(replaced)
import sys
process(sys.argv[1])
''' % str(args[:-1])) # do not hardcode in the last argument, the default arg

    final = os.path.dirname(filename) + os.path.sep + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js'
    final = final.replace('.cpp', '')
    try_delete(final)
    cmd = [
      PYTHON, EMCC, filename,
      OPTIMIZATIONS,
      '--js-transform', 'python hardcode.py',
      '-s', 'TOTAL_MEMORY=256*1024*1024',
      '-s', 'FILESYSTEM=0',
      # '--profiling',
      '--closure', '1',
      '-s', 'BENCHMARK=%d' % (1 if IGNORE_COMPILATION and not has_output_parser else 0),
      '-o', final
    ] + shared_args + emcc_args + self.extra_args
    if 'FORCE_FILESYSTEM=1' in cmd:
      cmd = [arg if arg != 'FILESYSTEM=0' else 'FILESYSTEM=1' for arg in cmd]
    output = run_process(cmd, stdout=PIPE, stderr=PIPE, env=self.env).stdout
    assert os.path.exists(final), 'Failed to compile file: ' + output + ' (looked for ' + final + ')'
    if self.binaryen_opts:
      run_binaryen_opts(final[:-3] + '.wasm', self.binaryen_opts)
    self.filename = final
Exemple #45
0
  def test_emcc(self):
    SANITY_FAIL_MESSAGE = 'sanity check failed to run'

    # emcc should check sanity if no ${EM_CONFIG}_sanity
    restore_and_set_up()
    time.sleep(1)
    assert not os.path.exists(SANITY_FILE) # restore is just the settings, not the sanity
    output = self.check_working(EMCC)
    self.assertContained(SANITY_MESSAGE, output)
    assert os.path.exists(SANITY_FILE) # EMCC should have checked sanity successfully
    assert mtime(SANITY_FILE) > mtime(CONFIG_FILE)
    assert generate_sanity() == open(SANITY_FILE).read()
    self.assertNotContained(SANITY_FAIL_MESSAGE, output)

    # emcc run again should not sanity check, because the sanity file is newer
    output = self.check_working(EMCC)
    self.assertNotContained(SANITY_MESSAGE, output)
    self.assertNotContained(SANITY_FAIL_MESSAGE, output)

    # correct sanity contents mean we need not check
    open(SANITY_FILE, 'w').write(generate_sanity())
    output = self.check_working(EMCC)
    self.assertNotContained(SANITY_MESSAGE, output)

    # incorrect sanity contents mean we *must* check
    open(SANITY_FILE, 'w').write('wakawaka')
    output = self.check_working(EMCC)
    self.assertContained(SANITY_MESSAGE, output)

    # but with EMCC_DEBUG=1 we should check
    with env_modify({'EMCC_DEBUG': '1'}):
      output = self.check_working(EMCC)
    try_delete(CANONICAL_TEMP_DIR)

    self.assertContained(SANITY_MESSAGE, output)
    output = self.check_working(EMCC)
    self.assertNotContained(SANITY_MESSAGE, output)

    # also with -v, with or without inputs
    output = self.check_working([EMCC, '-v'], SANITY_MESSAGE)
    output = self.check_working([EMCC, '-v'] + MINIMAL_HELLO_WORLD + [], SANITY_MESSAGE)

    # Make sure the test runner didn't do anything to the setup
    output = self.check_working(EMCC)
    self.assertNotContained(SANITY_MESSAGE, output)
    self.assertNotContained(SANITY_FAIL_MESSAGE, output)

    # emcc should also check sanity if the file is outdated
    time.sleep(0.1)
    restore_and_set_up()
    assert mtime(SANITY_FILE) < mtime(CONFIG_FILE)
    output = self.check_working(EMCC)
    self.assertContained(SANITY_MESSAGE, output)
    assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE)
    self.assertNotContained(SANITY_FAIL_MESSAGE, output)

    # emcc should be configurable directly from EM_CONFIG without any config file
    restore_and_set_up()
    config = open(CONFIG_FILE, 'r').read()
    open('main.cpp', 'w').write('''
      #include <stdio.h>
      int main() {
        printf("hello from emcc with no config file\\n");
        return 0;
      }
    ''')

    wipe()
    with env_modify({'EM_CONFIG': config}):
      run_process([PYTHON, EMCC, 'main.cpp', '-o', 'a.out.js'])

    self.assertContained('hello from emcc with no config file', run_js('a.out.js'))
Exemple #46
0
  def test_nodejs_sockets_echo(self):
    # This test checks that sockets work when the client code is run in Node.js
    # Run with ./runner.py sockets.test_nodejs_sockets_echo
    if NODE_JS not in JS_ENGINES:
      self.skipTest('node is not present')

    sockets_include = '-I' + path_from_root('tests', 'sockets')

    harnesses = [
      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0'], 59162), 0),
      (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1'], 59164), 1)
    ]

    if not WINDOWS: # TODO: Python pickling bug causes WebsockifyServerHarness to not work on Windows.
      harnesses += [(WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59160), 0)]

    # Basic test of node client against both a Websockified and compiled echo server.
    for harness, datagram in harnesses:
      with harness:
        run_process([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram], stdout=PIPE, stderr=PIPE)

        out = run_js('client.js', engine=NODE_JS, full_output=True)
        self.assertContained('do_msg_read: read 14 bytes', out)

    if not WINDOWS: # TODO: Python pickling bug causes WebsockifyServerHarness to not work on Windows.
      # Test against a Websockified server with compile time configured WebSocket subprotocol. We use a Websockified
      # server because as long as the subprotocol list contains binary it will configure itself to accept binary
      # This test also checks that the connect url contains the correct subprotocols.
      print("\nTesting compile time WebSocket configuration.\n")
      for harness in [
        WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59166)
      ]:
        with harness:
          run_process([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '-s', 'SOCKET_DEBUG=1', '-s', 'WEBSOCKET_SUBPROTOCOL="base64, binary"', '-DSOCKK=59166'], stdout=PIPE, stderr=PIPE)

          out = run_js('client.js', engine=NODE_JS, full_output=True)
          self.assertContained('do_msg_read: read 14 bytes', out)
          self.assertContained(['connect: ws://127.0.0.1:59166, base64,binary', 'connect: ws://127.0.0.1:59166/, base64,binary'], out)

      # Test against a Websockified server with runtime WebSocket configuration. We specify both url and subprotocol.
      # In this test we have *deliberately* used the wrong port '-DSOCKK=12345' to configure the echo_client.c, so
      # the connection would fail without us specifying a valid WebSocket URL in the configuration.
      print("\nTesting runtime WebSocket configuration.\n")
      for harness in [
        WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include], 59168)
      ]:
        with harness:
          open(os.path.join(self.get_dir(), 'websocket_pre.js'), 'w').write('''
          var Module = {
            websocket: {
              url: 'ws://localhost:59168/testA/testB',
              subprotocol: 'text, base64, binary',
            }
          };
          ''')

          run_process([PYTHON, EMCC, path_from_root('tests', 'sockets', 'test_sockets_echo_client.c'), '-o', 'client.js', '--pre-js', 'websocket_pre.js', '-s', 'SOCKET_DEBUG=1', '-DSOCKK=12345'], stdout=PIPE, stderr=PIPE)

          out = run_js('client.js', engine=NODE_JS, full_output=True)
          self.assertContained('do_msg_read: read 14 bytes', out)
          self.assertContained('connect: ws://localhost:59168/testA/testB, text,base64,binary', out)
Exemple #47
0
 def run(self, args):
   return run_process([self.filename] + args, stdout=PIPE, stderr=PIPE, check=False).stdout
Exemple #48
0
def run_binaryen_opts(filename, opts):
  run_process([
    os.path.join(Building.get_binaryen_bin(), 'wasm-opt'),
    filename,
    '-o', filename
  ] + opts)
Exemple #49
0
  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))
Exemple #50
0
  def test_binaryen(self):
    import tools.ports.binaryen as binaryen
    tag_file = Cache.get_path('binaryen_tag_' + binaryen.TAG + '.txt')

    assert not os.environ.get('BINARYEN') # must not have binaryen env var set

    # test in 2 modes - with BINARYEN_ROOT in the config file, set to '', and without it entirely
    for binaryen_root_in_config in [1, 0]:
      print('binaryen_root_in_config:', binaryen_root_in_config)

      def prep():
        restore_and_set_up()
        print('clearing ports...')
        print(self.do([PYTHON, EMCC, '--clear-ports']))
        wipe()
        self.do([PYTHON, EMCC]) # first run stage
        try_delete(tag_file)
        # if BINARYEN_ROOT is set, we don't build the port. Check we do build it if not
        if binaryen_root_in_config:
          config = open(CONFIG_FILE).read()
          assert '''BINARYEN_ROOT = os.path.expanduser(os.getenv('BINARYEN', ''))''' in config, config # setup created it to be ''
          print('created config:')
          print(config)
          restore_and_set_up()
          config = open(CONFIG_FILE).read()
          config = config.replace('BINARYEN_ROOT', '''BINARYEN_ROOT = os.path.expanduser(os.getenv('BINARYEN', '')) # ''')
        else:
          restore_and_set_up()
          config = open(CONFIG_FILE).read()
          config = config.replace('BINARYEN_ROOT', '#')
        print('modified config:')
        print(config)
        open(CONFIG_FILE, 'w').write(config)

      print('build using embuilder')
      prep()
      run_process([PYTHON, EMBUILDER, 'build', 'binaryen'])
      assert os.path.exists(tag_file)
      run_process([PYTHON, EMCC] + MINIMAL_HELLO_WORLD + ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
      self.assertContained('hello, world!', run_js('a.out.js'))

      print('see we show an error for emmake (we cannot build natively under emmake)')
      prep()
      try_delete('a.out.js')
      out = self.do([PYTHON, path_from_root('emmake.py'), EMCC] + MINIMAL_HELLO_WORLD + ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"'])
      assert not os.path.exists(tag_file)
      assert not os.path.exists('a.out.js')
      self.assertContained('For example, for binaryen, do "python embuilder.py build binaryen"', out)

      if not binaryen_root_in_config:
        print('build on demand')
        for side_module in (False, True):
          print(side_module)
          prep()
          assert not os.path.exists(tag_file)
          try_delete('a.out.js')
          try_delete('a.out.wasm')
          cmd = [PYTHON, EMCC]
          if not side_module:
            cmd += MINIMAL_HELLO_WORLD
          else:
            # EM_ASM doesn't work in a wasm side module, build a normal program
            cmd += [path_from_root('tests', 'hello_world.c'), '-s', 'SIDE_MODULE=1']
          cmd += ['-s', 'BINARYEN=1', '-s', 'BINARYEN_METHOD="interpret-binary"']
          run_process(cmd)
          assert os.path.exists(tag_file)
          assert os.path.exists('a.out.wasm')
          if not side_module:
            assert os.path.exists('a.out.js')
            self.assertContained('hello, world!', run_js('a.out.js'))
Exemple #51
0
 def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser):
   suffix = filename.split('.')[-1]
   cheerp_temp = filename + '.cheerp.' + suffix
   code = open(filename).read()
   if 'int main()' in code:
     main_args = ''
   else:
     main_args = 'argc, (%(const)s char**)argv' % {
       'const': 'const' if 'const char *argv' in code else ''
     }
   open(cheerp_temp, 'w').write('''
     %(code)s
     void webMain() {
       // TODO: how to read from commandline?
       volatile int argc = 2;
       typedef char** charStarStar;
       volatile charStarStar argv;
       argv[0] = "./cheerp.exe";
       argv[1] = "%(arg)s";
       volatile int exit_code = main(%(main_args)s);
     }
   ''' % {
     'arg': args[-1],
     'code': code,
     'main_args': main_args
   })
   cheerp_args = [
     '-target', 'cheerp',
     '-cheerp-mode=wasm'
   ]
   cheerp_args += self.args
   self.parent = parent
   if lib_builder:
     # build as "native" (so no emcc env stuff), but with all the cheerp stuff
     # set in the env
     cheerp_args = cheerp_args + lib_builder(self.name, native=True, env_init={
       'CC': CHEERP_BIN + 'clang',
       'CXX': CHEERP_BIN + 'clang++',
       'AR': CHEERP_BIN + 'llvm-ar',
       'LD': CHEERP_BIN + 'clang',
       'NM': CHEERP_BIN + 'llvm-nm',
       'LDSHARED': CHEERP_BIN + 'clang',
       'RANLIB': CHEERP_BIN + 'llvm-ranlib',
       'CFLAGS': ' '.join(cheerp_args),
       'CXXFLAGS': ' '.join(cheerp_args),
     })
   # cheerp_args += ['-cheerp-pretty-code'] # get function names, like emcc --profiling
   final = os.path.dirname(filename) + os.path.sep + 'cheerp_' + self.name + ('_' if self.name else '') + os.path.basename(filename) + '.js'
   final = final.replace('.cpp', '')
   try_delete(final)
   dirs_to_delete = []
   try:
     for arg in cheerp_args[:]:
       if arg.endswith('.a'):
         info = self.handle_static_lib(arg)
         cheerp_args += info['files']
         dirs_to_delete += [info['dir']]
     cheerp_args = [arg for arg in cheerp_args if not arg.endswith('.a')]
     # print(cheerp_args)
     cmd = [CHEERP_BIN + 'clang++'] + cheerp_args + [
       '-cheerp-linear-heap-size=256',
       '-cheerp-wasm-loader=' + final,
       cheerp_temp,
       '-Wno-writable-strings', # for how we set up webMain
       '-o', final + '.wasm'
     ] + shared_args
     # print(' '.join(cmd))
     run_process(cmd)
     self.filename = final
     Building.get_binaryen()
     if self.binaryen_opts:
       run_binaryen_opts(final + '.wasm', self.binaryen_opts)
   finally:
     for dir_ in dirs_to_delete:
       try_delete(dir_)
Exemple #52
0
  def test_webrtc(self): # XXX see src/settings.js, this is disabled pending investigation
    self.skipTest('WebRTC support is not up to date.')
    host_src = 'webrtc_host.c'
    peer_src = 'webrtc_peer.c'

    host_outfile = 'host.html'
    peer_outfile = 'peer.html'

    host_filepath = path_from_root('tests', 'sockets', host_src)
    temp_host_filepath = os.path.join(self.get_dir(), os.path.basename(host_src))
    with open(host_filepath) as f:
      host_src = f.read()
    with open(temp_host_filepath, 'w') as f:
      f.write(self.with_report_result(host_src))

    peer_filepath = path_from_root('tests', 'sockets', peer_src)
    temp_peer_filepath = os.path.join(self.get_dir(), os.path.basename(peer_src))
    with open(peer_filepath) as f:
      peer_src = f.read()
    with open(temp_peer_filepath, 'w') as f:
      f.write(self.with_report_result(peer_src))

    open(os.path.join(self.get_dir(), 'host_pre.js'), 'w').write('''
      var Module = {
        webrtc: {
          broker: 'http://localhost:8182',
          session: undefined,
          onpeer: function(peer, route) {
            window.open('http://localhost:8888/peer.html?' + route);
            // iframe = document.createElement("IFRAME");
            // iframe.setAttribute("src", "http://localhost:8888/peer.html?" + route);
            // iframe.style.display = "none";
            // document.body.appendChild(iframe);
            peer.listen();
          },
          onconnect: function(peer) {
          },
          ondisconnect: function(peer) {
          },
          onerror: function(error) {
            console.error(error);
          }
        },
        setStatus: function(text) {
          console.log('status: ' + text);
        }
      };
    ''')

    open(os.path.join(self.get_dir(), 'peer_pre.js'), 'w').write('''
      var Module = {
        webrtc: {
          broker: 'http://localhost:8182',
          session: window.location.toString().split('?')[1],
          onpeer: function(peer, route) {
            peer.connect(Module['webrtc']['session']);
          },
          onconnect: function(peer) {
          },
          ondisconnect: function(peer) {
            // Calling window.close() from this handler hangs my browser, so run it in the next turn
            setTimeout(window.close, 0);
          },
          onerror: function(error) {
            console.error(error);
          },
        },
        setStatus: function(text) {
          console.log('status: ' + text);
        }
      };
    ''')

    run_process([PYTHON, EMCC, temp_host_filepath, '-o', host_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'host_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1'])
    run_process([PYTHON, EMCC, temp_peer_filepath, '-o', peer_outfile] + ['-s', 'GL_TESTING=1', '--pre-js', 'peer_pre.js', '-s', 'SOCKET_WEBRTC=1', '-s', 'SOCKET_DEBUG=1'])

    # note: you may need to run this manually yourself, if npm is not in the path, or if you need a version that is not in the path
    run_process([NPM, 'install', path_from_root('tests', 'sockets', 'p2p')])
    broker = Popen(NODE_JS + [path_from_root('tests', 'sockets', 'p2p', 'broker', 'p2p-broker.js')])

    expected = '1'
    self.run_browser(host_outfile, '.', ['/report_result?' + e for e in expected])

    broker.kill()