def create_gl():
   prev_cxx = os.environ.get('EMMAKEN_CXX')
   if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
   o = in_temp('gl.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
   if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
   return o
Exemple #2
0
 def create_malloc(out_name):
     o = in_temp(out_name)
     cflags = ['-O2', '-fno-builtin']
     if shared.Settings.USE_PTHREADS:
         cflags += ['-s', 'USE_PTHREADS=1']
     if shared.Settings.EMSCRIPTEN_TRACING:
         cflags += ['--tracing']
     if shared.Settings.SPLIT_MEMORY:
         cflags += ['-DMSPACES', '-DONLY_MSPACES']
     if shared.Settings.DEBUG_LEVEL >= 3:
         cflags += ['-UNDEBUG', '-DDLMALLOC_DEBUG']
         # TODO: consider adding -DEMMALLOC_DEBUG, but that is quite slow
     else:
         cflags += ['-DNDEBUG']
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', malloc_source()), '-o', o
     ] + cflags)
     if shared.Settings.SPLIT_MEMORY:
         split_malloc_o = in_temp('sm' + out_name)
         check_call([
             shared.PYTHON, shared.EMCC,
             shared.path_from_root('system', 'lib', 'split_malloc.cpp'),
             '-o', split_malloc_o, '-O2'
         ])
         lib = in_temp('lib' + out_name)
         shared.Building.link([o, split_malloc_o], lib)
         shutil.move(lib, o)
     return o
Exemple #3
0
  def build_native(subdir):
    shared.Building.ensure_no_emmake('We cannot build the native system library in "%s" when under the influence of emmake/emconfigure. To avoid this, create system dirs beforehand, so they are not auto-built on demand. For example, for binaryen, do "python embuilder.py build binaryen"' % subdir)

    old = os.getcwd()

    try:
      os.chdir(subdir)

      cmake_build_type = 'Release'

      # Configure
      check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.'])

      # Check which CMake generator CMake used so we know which form to pass parameters to make/msbuild/etc. build tool.
      generator = re.search('CMAKE_GENERATOR:INTERNAL=(.*)$', open('CMakeCache.txt', 'r').read(), re.MULTILINE).group(1)

      # Make variants support '-jX' for number of cores to build, MSBuild does /maxcpucount:X
      num_cores = str(shared.Building.get_num_cores())
      make_args = []
      if 'Makefiles' in generator and 'NMake' not in generator:
        make_args = ['--', '-j', num_cores]
      elif 'Visual Studio' in generator:
        make_args = ['--config', cmake_build_type, '--', '/maxcpucount:' + num_cores]

      # Kick off the build.
      check_call(['cmake', '--build', '.'] + make_args)
    finally:
      os.chdir(old)
Exemple #4
0
def run():
    if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
        print('''\
emconfigure is a helper for configure, setting various environment
variables so that emcc etc. are used. Typical usage:

  emconfigure ./configure [FLAGS]

(but you can run any command instead of configure)''',
              file=sys.stderr)
        return 1

    args = sys.argv[1:]

    if 'cmake' in args:
        print(
            'error: use `emcmake` rather then `emconfigure` for cmake projects',
            file=sys.stderr)
        return 1

    env = building.get_building_env()
    # When we configure via a ./configure script, don't do config-time
    # compilation with emcc, but instead do builds natively with Clang. This
    # is a heuristic emulation that may or may not work.
    env['EMMAKEN_JUST_CONFIGURE'] = '1'
    print('configure: ' + shared.shlex_join(args), file=sys.stderr)
    try:
        shared.check_call(args, env=env)
        return 0
    except CalledProcessError as e:
        return e.returncode
Exemple #5
0
 def create_dlmalloc(out_name, clflags):
     o = in_temp(out_name)
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', o
     ] + clflags)
     return o
Exemple #6
0
 def create_gl(libname):  # libname is ignored, this is just one .o file
     o = in_temp('gl.o')
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'gl.c'), '-o', o
     ])
     return o
Exemple #7
0
def symbolize_address_dwarf(module, address):
    vma_adjust = get_codesec_offset(module)
    cmd = [
        LLVM_SYMBOLIZER, '-e', module.filename, f'--adjust-vma={vma_adjust}',
        str(address)
    ]
    check_call(cmd)
Exemple #8
0
 def create_gl():
     o = in_temp('gl.o')
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'gl.c'), '-o', o
     ])
     return o
Exemple #9
0
 def create_gl():
   prev_cxx = os.environ.get('EMMAKEN_CXX')
   if prev_cxx: os.environ['EMMAKEN_CXX'] = ''
   o = in_temp('gl.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
   if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx
   return o
Exemple #10
0
def run():
  if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
    print('''\
emmake is a helper for make, setting various environment
variables so that emcc etc. are used. Typical usage:

  emmake make [FLAGS]

(but you can run any command instead of make)''', file=sys.stderr)
    return 1

  args = sys.argv[1:]
  env = building.get_building_env()

  # On Windows prefer building with mingw32-make instead of make, if it exists.
  if utils.WINDOWS:
    if args[0] == 'make':
      mingw32_make = utils.which('mingw32-make')
      if mingw32_make:
        args[0] = mingw32_make

    if 'mingw32-make' in args[0]:
      env = building.remove_sh_exe_from_path(env)

  # On Windows, run the execution through shell to get PATH expansion and
  # executable extension lookup, e.g. 'sdl2-config' will match with
  # 'sdl2-config.bat' in PATH.
  print('make: ' + ' '.join(args), file=sys.stderr)
  try:
    shared.check_call(args, shell=utils.WINDOWS, env=env)
    return 0
  except CalledProcessError as e:
    return e.returncode
Exemple #11
0
  def build_native(subdir):
    shared.Building.ensure_no_emmake('We cannot build the native system library in "%s" when under the influence of emmake/emconfigure. To avoid this, create system dirs beforehand, so they are not auto-built on demand. For example, for binaryen, do "python embuilder.py build binaryen"' % subdir)

    old = os.getcwd()

    try:
      os.chdir(subdir)

      cmake_build_type = 'Release'

      # Configure
      check_call(['cmake', '-DCMAKE_BUILD_TYPE=' + cmake_build_type, '.'])

      # Check which CMake generator CMake used so we know which form to pass parameters to make/msbuild/etc. build tool.
      generator = re.search('CMAKE_GENERATOR:INTERNAL=(.*)$', open('CMakeCache.txt', 'r').read(), re.MULTILINE).group(1)

      # Make variants support '-jX' for number of cores to build, MSBuild does /maxcpucount:X
      num_cores = str(shared.Building.get_num_cores())
      make_args = []
      if 'Makefiles' in generator and 'NMake' not in generator:
        make_args = ['--', '-j', num_cores]
      elif 'Visual Studio' in generator:
        make_args = ['--config', cmake_build_type, '--', '/maxcpucount:' + num_cores]

      # Kick off the build.
      check_call(['cmake', '--build', '.'] + make_args)
    finally:
      os.chdir(old)
Exemple #12
0
 def create_dlmalloc(out_name):
     o = in_temp(out_name)
     cflags = ['-O2']
     if shared.Settings.USE_PTHREADS:
         cflags += ['-s', 'USE_PTHREADS=1']
     if shared.Settings.EMSCRIPTEN_TRACING:
         cflags += ['--tracing']
     if shared.Settings.SPLIT_MEMORY:
         cflags += ['-DMSPACES', '-DONLY_MSPACES']
     if shared.Settings.DEBUG_LEVEL:
         cflags += ['-DDLMALLOC_DEBUG']
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', o
     ] + cflags)
     if shared.Settings.SPLIT_MEMORY:
         split_malloc_o = in_temp('sm' + out_name)
         check_call([
             shared.PYTHON, shared.EMCC,
             shared.path_from_root('system', 'lib', 'split_malloc.cpp'),
             '-o', split_malloc_o, '-O2'
         ])
         lib = in_temp('lib' + out_name)
         shared.Building.link([o, split_malloc_o], lib)
         shutil.move(lib, o)
     return o
Exemple #13
0
 def create_al(libname):  # libname is ignored, this is just one .o file
     o = in_temp('al.o')
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'al.c'), '-o', o, '-Os'
     ] + get_cflags())
     return o
Exemple #14
0
 def create_dlmalloc_split(libname):
   dlmalloc_o = in_temp('dl' + libname)
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', dlmalloc_o, '-O2', '-DMSPACES', '-DONLY_MSPACES'])
   split_malloc_o = in_temp('sm' + libname)
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'split_malloc.cpp'), '-o', split_malloc_o, '-O2'])
   lib = in_temp(libname)
   shared.Building.link([dlmalloc_o, split_malloc_o], lib)
   return lib
Exemple #15
0
 def create_dlmalloc_split(libname):
   dlmalloc_o = in_temp('dl' + libname)
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', dlmalloc_o, '-O2', '-DMSPACES', '-DONLY_MSPACES'])
   split_malloc_o = in_temp('sm' + libname)
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'split_malloc.cpp'), '-o', split_malloc_o, '-O2'])
   lib = in_temp(libname)
   shared.Building.link([dlmalloc_o, split_malloc_o], lib)
   return lib
Exemple #16
0
 def create_libc_extras(
         libname):  # libname is ignored, this is just one .o file
     o = in_temp('libc_extras.o')
     check_call([
         shared.PYTHON, shared.EMCC,
         shared.path_from_root('system', 'lib', 'libc', 'extras.c'), '-o', o
     ] + get_cflags())
     return o
Exemple #17
0
def run():
    if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
        print('''\
emcmake is a helper for cmake, setting various environment
variables so that emcc etc. are used. Typical usage:

  emcmake cmake [FLAGS]
''',
              file=sys.stderr)
        return 1

    args = sys.argv[1:]

    def has_substr(args, substr):
        return any(substr in s for s in args)

    # Append the Emscripten toolchain file if the user didn't specify one.
    if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
        args.append('-DCMAKE_TOOLCHAIN_FILE=' + utils.path_from_root(
            'cmake', 'Modules', 'Platform', 'Emscripten.cmake'))

    if not has_substr(args, '-DCMAKE_CROSSCOMPILING_EMULATOR'):
        node_js = config.NODE_JS[0]
        args.append(f'-DCMAKE_CROSSCOMPILING_EMULATOR={node_js}')

    # On Windows specify MinGW Makefiles or ninja if we have them and no other
    # toolchain was specified, to keep CMake from pulling in a native Visual
    # Studio, or Unix Makefiles.
    if utils.WINDOWS and '-G' not in args:
        if utils.which('mingw32-make'):
            args += ['-G', 'MinGW Makefiles']
        elif utils.which('ninja'):
            args += ['-G', 'Ninja']
        else:
            print(
                'emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G',
                file=sys.stderr)
            return 1

    # CMake has a requirement that it wants sh.exe off PATH if MinGW Makefiles
    # is being used. This happens quite often, so do this automatically on
    # behalf of the user. See
    # http://www.cmake.org/Wiki/CMake_MinGW_Compiler_Issues
    if utils.WINDOWS and 'MinGW Makefiles' in args:
        env = building.remove_sh_exe_from_path(os.environ)
    else:
        env = None

    print('configure: ' + shared.shlex_join(args), file=sys.stderr)
    try:
        shared.check_call(args, env=env)
        return 0
    except CalledProcessError as e:
        return e.returncode
Exemple #18
0
 def create_malloc(out_name):
   o = in_temp(out_name)
   cflags = ['-O2', '-fno-builtin']
   if shared.Settings.USE_PTHREADS:
     cflags += ['-s', 'USE_PTHREADS=1']
   if shared.Settings.EMSCRIPTEN_TRACING:
     cflags += ['--tracing']
   if shared.Settings.DEBUG_LEVEL >= 3:
     cflags += ['-UNDEBUG', '-DDLMALLOC_DEBUG']
     # TODO: consider adding -DEMMALLOC_DEBUG, but that is quite slow
   else:
     cflags += ['-DNDEBUG']
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', malloc_source()), '-o', o] + cflags + get_cflags())
   return o
Exemple #19
0
def print_sizes(js_file):
    if not os.path.isfile(js_file):
        return error('Input JS file %s not foune' % js_file)
    if not js_file.endswith('.js'):
        return error('Input file %s does not have a JS extension' % js_file)

    basename = js_file[:-3]

    # Find the JS file size
    st = os.stat(js_file)
    js_size = st.st_size

    # Find the rest of the sizes
    wasm_file = basename + '.wasm'
    if not os.path.isfile(wasm_file):
        return error('Wasm file %s not found' % wasm_file)

    sizes = shared.check_call([LLVM_SIZE, '-format=sysv', wasm_file],
                              stdout=subprocess.PIPE).stdout
    # llvm-size may emit some number of blank lines (after the total), ignore them
    lines = [line for line in sizes.splitlines() if line]

    # Last line is the total. Add the JS size.
    total = int(lines[-1].split()[-1])
    total += js_size

    for line in lines[:-1]:
        print(line)

    print('JS\t\t%s\t0' % js_size)
    print('Total\t\t%s' % total)
Exemple #20
0
def run():
    if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
        print('''\
emcmake is a helper for cmake, setting various environment
variables so that emcc etc. are used. Typical usage:

  emcmake cmake [FLAGS]
''',
              file=sys.stderr)
        return 1

    args = sys.argv[1:]

    def has_substr(args, substr):
        return any(substr in s for s in args)

    # Append the Emscripten toolchain file if the user didn't specify one.
    if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
        args.append(
            '-DCMAKE_TOOLCHAIN_FILE=' +
            utils.path_from_root('cmake/Modules/Platform/Emscripten.cmake'))

    if not has_substr(args, '-DCMAKE_CROSSCOMPILING_EMULATOR'):
        node_js = config.NODE_JS[0]
        args.append(f'-DCMAKE_CROSSCOMPILING_EMULATOR={node_js}')

    # On Windows specify MinGW Makefiles or ninja if we have them and no other
    # toolchain was specified, to keep CMake from pulling in a native Visual
    # Studio, or Unix Makefiles.
    if utils.WINDOWS and '-G' not in args:
        if utils.which('mingw32-make'):
            args += ['-G', 'MinGW Makefiles']
        elif utils.which('ninja'):
            args += ['-G', 'Ninja']
        else:
            print(
                'emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G',
                file=sys.stderr)
            return 1

    print('configure: ' + shared.shlex_join(args), file=sys.stderr)
    try:
        shared.check_call(args)
        return 0
    except CalledProcessError as e:
        return e.returncode
Exemple #21
0
def run():
  if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'):
    print('''\
emcmake is a helper for cmake, setting various environment
variables so that emcc etc. are used. Typical usage:

  emcmake cmake [FLAGS]
''', file=sys.stderr)
    return 1

  args = sys.argv[1:]

  def has_substr(args, substr):
    return any(substr in s for s in args)

  # Append the Emscripten toolchain file if the user didn't specify one.
  if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
    args.append('-DCMAKE_TOOLCHAIN_FILE=' + utils.path_from_root('cmake/Modules/Platform/Emscripten.cmake'))

  if not has_substr(args, '-DCMAKE_CROSSCOMPILING_EMULATOR'):
    node_js = config.NODE_JS[0]
    # In order to allow cmake to run code built with pthreads we need to pass some extra flags to node.
    # Note that we also need --experimental-wasm-bulk-memory which is true by default and hence not added here
    # See https://github.com/emscripten-core/emscripten/issues/15522
    args.append(f'-DCMAKE_CROSSCOMPILING_EMULATOR={node_js};--experimental-wasm-threads')

  # On Windows specify MinGW Makefiles or ninja if we have them and no other
  # toolchain was specified, to keep CMake from pulling in a native Visual
  # Studio, or Unix Makefiles.
  if utils.WINDOWS and not any(arg.startswith('-G') for arg in args):
    if utils.which('mingw32-make'):
      args += ['-G', 'MinGW Makefiles']
    elif utils.which('ninja'):
      args += ['-G', 'Ninja']
    else:
      print('emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G', file=sys.stderr)
      return 1

  print('configure: ' + shared.shlex_join(args), file=sys.stderr)
  try:
    shared.check_call(args)
    return 0
  except CalledProcessError as e:
    return e.returncode
Exemple #22
0
 def create_malloc(out_name):
   o = in_temp(out_name)
   cflags = ['-O2', '-fno-builtin']
   if shared.Settings.USE_PTHREADS:
     cflags += ['-s', 'USE_PTHREADS=1']
   if shared.Settings.EMSCRIPTEN_TRACING:
     cflags += ['--tracing']
   if shared.Settings.SPLIT_MEMORY:
     cflags += ['-DMSPACES', '-DONLY_MSPACES']
   if shared.Settings.DEBUG_LEVEL >= 3:
     cflags += ['-UNDEBUG', '-DDLMALLOC_DEBUG']
     # TODO: consider adding -DEMMALLOC_DEBUG, but that is quite slow
   else:
     cflags += ['-DNDEBUG']
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', malloc_source()), '-o', o] + cflags + get_cflags())
   if shared.Settings.SPLIT_MEMORY:
     split_malloc_o = in_temp('sm' + out_name)
     check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'split_malloc.cpp'), '-o', split_malloc_o, '-O2'] + get_cflags())
     lib = in_temp('lib' + out_name)
     create_lib(lib, [o, split_malloc_o])
     shutil.move(lib, o)
   return o
Exemple #23
0
def run():
    args = substitute_response_files(sys.argv)
    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

            contents = set()
            if os.path.exists(newargs[out_arg_index]):
                cmd = [shared.LLVM_AR, 't', newargs[out_arg_index]]
                output = shared.check_call(cmd, stdout=shared.PIPE).stdout
                contents.update(output.split('\n'))

            # 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)
                if basename not in contents:
                    contents.add(basename)
                    continue
                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)
                assert not os.path.exists(full_newname)
                try:
                    shutil.copyfile(orig_name, full_newname)
                    newargs[j] = full_newname
                    to_delete.append(full_newname)
                    contents.add(newname)
                except Exception:
                    # it is ok to fail here, we just don't get hashing
                    contents.add(basename)
                    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)

    try:
        return shared.run_process(newargs, stdin=sys.stdin,
                                  check=False).returncode
    finally:
        for d in to_delete:
            shared.try_delete(d)
Exemple #24
0
 def create_al(libname): # libname is ignored, this is just one .o file
   o = in_temp('al.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'al.c'), '-o', o, '-Os'] + get_cflags())
   return o
Exemple #25
0
 def create_libc_extras(libname): # libname is ignored, this is just one .o file
   o = in_temp('libc_extras.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'libc', 'extras.c'), '-o', o] + get_cflags())
   return o
Exemple #26
0
 def create_gl():
   o = in_temp('gl.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
   return o
Exemple #27
0
def generate_object_file(data_files):
    embed_files = [f for f in data_files if f.mode == 'embed']
    assert embed_files

    asm_file = shared.replace_suffix(options.obj_output, '.s')

    used = set()
    for f in embed_files:
        f.c_symbol_name = '__em_file_data_%s' % to_c_symbol(f.dstpath, used)

    with open(asm_file, 'w') as out:
        out.write(
            '# Emscripten embedded file data, generated by tools/file_packager.py\n'
        )

        for f in embed_files:
            if DEBUG:
                err('embedding %s at %s' % (f.srcpath, f.dstpath))

            size = os.path.getsize(f.srcpath)
            dstpath = to_asm_string(f.dstpath)
            srcpath = to_unix_path(f.srcpath)
            out.write(
                dedent(f'''
      .section .rodata.{f.c_symbol_name},"",@

      # The name of file
      {f.c_symbol_name}_name:
      .asciz "{dstpath}"
      .size {f.c_symbol_name}_name, {len(dstpath)+1}

      # The size of the file followed by the content itself
      {f.c_symbol_name}:
      .incbin "{srcpath}"
      .size {f.c_symbol_name}, {size}
      '''))

        out.write(
            dedent('''
      # A list of triples of:
      # (file_name_ptr, file_data_size, file_data_ptr)
      # The list in null terminate with a single 0
      .globl __emscripten_embedded_file_data
      .export_name __emscripten_embedded_file_data, __emscripten_embedded_file_data
      .section .rodata.__emscripten_embedded_file_data,"",@
      __emscripten_embedded_file_data:
      .p2align 2
      '''))

        for f in embed_files:
            # The `.dc.a` directive gives us a pointer (address) sized entry.
            # See https://sourceware.org/binutils/docs/as/Dc.html
            out.write(
                dedent(f'''\
        .dc.a {f.c_symbol_name}_name
        .int32 {os.path.getsize(f.srcpath)}
        .dc.a {f.c_symbol_name}
        '''))

        ptr_size = 4
        elem_size = (2 * ptr_size) + 4
        total_size = len(embed_files) * elem_size + 4
        out.write(
            dedent(f'''\
      .dc.a 0
      .size __emscripten_embedded_file_data, {total_size}
      '''))
    shared.check_call([
        shared.LLVM_MC, '-filetype=obj', '-triple=' + shared.get_llvm_target(),
        '-o', options.obj_output, asm_file
    ])
Exemple #28
0
 def create_dlmalloc(out_name, clflags):
   o = in_temp(out_name)
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', o] + clflags)
   return o
Exemple #29
0
 def create_gl(libname): # libname is ignored, this is just one .o file
   o = in_temp('gl.o')
   check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
   return o
Exemple #30
0
def do_wasm2c(infile):
  assert Settings.STANDALONE_WASM
  WASM2C = NODE_JS + [path_from_root('node_modules', 'wasm2c', 'wasm2c.js')]
  WASM2C_DIR = path_from_root('node_modules', 'wasm2c')
  c_file = unsuffixed(infile) + '.wasm.c'
  h_file = unsuffixed(infile) + '.wasm.h'
  cmd = WASM2C + [infile, '-o', c_file]
  check_call(cmd)
  total = '''\
/*
* This file was generated by emcc+wasm2c. To compile it, use something like
*
*   $CC FILE.c -O2 -lm -DWASM_RT_MAX_CALL_STACK_DEPTH=8000
*/
'''
  SEP = '\n/* ==================================== */\n'

  def bundle_file(total, filename):
    with open(filename) as f:
      total += '// ' + filename + '\n' + f.read() + SEP
    return total

  # hermeticize the C file, by bundling in the wasm2c/ includes
  headers = [
    (WASM2C_DIR, 'wasm-rt.h'),
    (WASM2C_DIR, 'wasm-rt-impl.h'),
    ('', h_file)
  ]
  for header in headers:
    total = bundle_file(total, os.path.join(header[0], header[1]))
  # add the wasm2c output
  with open(c_file) as read_c:
    c = read_c.read()
  total += c + SEP
  # add the wasm2c runtime
  total = bundle_file(total, os.path.join(WASM2C_DIR, 'wasm-rt-impl.c'))
  # add the support code
  support_files = ['base']
  if Settings.AUTODEBUG:
    support_files.append('autodebug')
  if Settings.EXPECT_MAIN:
    # TODO: add an option for direct OS access. For now, do that when building
    #       an executable with main, as opposed to a library
    support_files.append('os')
    support_files.append('main')
  else:
    support_files.append('os_sandboxed')
    support_files.append('reactor')
    # for a reactor, also append wasmbox_* API definitions
    with open(h_file, 'a') as f:
      f.write('''
// wasmbox_* API
// TODO: optional prefixing
extern void wasmbox_init(void);
''')
  for support_file in support_files:
    total = bundle_file(total, path_from_root('tools', 'wasm2c', support_file + '.c'))
  # remove #includes of the headers we bundled
  for header in headers:
    total = total.replace('#include "%s"\n' % header[1], '/* include of %s */\n' % header[1])
  # generate the necessary invokes
  invokes = []
  for sig in re.findall(r"\/\* import\: 'env' 'invoke_(\w+)' \*\/", total):
    all_func_types = get_func_types(total)

    def name(i):
      return 'a' + str(i)

    wabt_sig = sig[0] + 'i' + sig[1:]
    typed_args = [s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))]
    full_typed_args = ['u32 fptr'] + typed_args
    types = [s_to_c(sig[i]) for i in range(1, len(sig))]
    args = [name(i) for i in range(1, len(sig))]
    c_func_type = s_to_c(sig[0]) + ' (*)(' + (', '.join(types) if types else 'void') + ')'
    if sig not in all_func_types:
      exit_with_error('could not find signature ' + sig + ' in function types ' + str(all_func_types))
    type_index = all_func_types[sig]

    invokes.append(r'''
IMPORT_IMPL(%(return_type)s, Z_envZ_invoke_%(sig)sZ_%(wabt_sig)s, (%(full_typed_args)s), {
  VERBOSE_LOG("invoke\n"); // waka
  u32 sp = Z_stackSaveZ_iv();
  if (next_setjmp >= MAX_SETJMP_STACK) {
    abort_with_message("too many nested setjmps");
  }
  u32 id = next_setjmp++;
  int result = setjmp(setjmp_stack[id]);
  %(declare_return)s
  if (result == 0) {
    %(receive)sCALL_INDIRECT(w2c___indirect_function_table, %(c_func_type)s, %(type_index)s, fptr %(args)s);
    /* if we got here, no longjmp or exception happened, we returned normally */
  } else {
    /* A longjmp or an exception took us here. */
    Z_stackRestoreZ_vi(sp);
    Z_setThrewZ_vii(1, 0);
  }
  next_setjmp--;
  %(return)s
});
''' % {
      'return_type': s_to_c(sig[0]) if sig[0] != 'v' else 'void',
      'sig': sig,
      'wabt_sig': wabt_sig,
      'full_typed_args': ', '.join(full_typed_args),
      'type_index': type_index,
      'c_func_type': c_func_type,
      'args': (', ' + ', '.join(args)) if args else '',
      'declare_return': (s_to_c(sig[0]) + ' returned_value = 0;') if sig[0] != 'v' else '',
      'receive': 'returned_value = ' if sig[0] != 'v' else '',
      'return': 'return returned_value;' if sig[0] != 'v' else ''
    })

  total += '\n'.join(invokes)
  # write out the final file
  with open(c_file, 'w') as out:
    out.write(total)
Exemple #31
0
def generate_object_file(data_files):
    embed_files = [f for f in data_files if f.mode == 'embed']
    assert embed_files

    asm_file = shared.replace_suffix(options.obj_output, '.s')

    used = set()
    for f in embed_files:
        f.c_symbol_name = '__em_file_data_%s' % to_c_symbol(f.dstpath, used)

    with open(asm_file, 'w') as out:
        out.write(
            '# Emscripten embedded file data, generated by tools/file_packager.py\n'
        )

        for f in embed_files:
            if DEBUG:
                err('embedding %s at %s' % (f.srcpath, f.dstpath))

            size = os.path.getsize(f.srcpath)
            dstpath = to_asm_string(f.dstpath)
            srcpath = to_unix_path(f.srcpath)
            out.write(
                dedent(f'''
      .section .rodata.{f.c_symbol_name},"",@

      # The name of file
      {f.c_symbol_name}_name:
      .asciz "{dstpath}"
      .size {f.c_symbol_name}_name, {len(dstpath)+1}

      # The size of the file followed by the content itself
      {f.c_symbol_name}:
      .incbin "{srcpath}"
      .size {f.c_symbol_name}, {size}
      '''))

        if options.wasm64:
            align = 3
            ptr_type = 'i64'
            bits = 64
        else:
            align = 2
            ptr_type = 'i32'
            bits = 32
        out.write(
            dedent(f'''
      .functype _emscripten_fs_load_embedded_files ({ptr_type}) -> ()
      .section .text,"",@
      init_file_data:
        .functype init_file_data () -> ()
        global.get __emscripten_embedded_file_data@GOT
        call _emscripten_fs_load_embedded_files
        end_function

      # Run init_file_data on startup.
      # See system/lib/README.md for ordering of system constructors.
      .section .init_array.49,"",@
      .p2align {align}
      .int{bits} init_file_data

      # A list of triples of:
      # (file_name_ptr, file_data_size, file_data_ptr)
      # The list in null terminate with a single 0
      .globl __emscripten_embedded_file_data
      .export_name __emscripten_embedded_file_data, __emscripten_embedded_file_data
      .section .rodata.__emscripten_embedded_file_data,"",@
      __emscripten_embedded_file_data:
      .p2align {align}
      '''))

        for f in embed_files:
            # The `.dc.a` directive gives us a pointer (address) sized entry.
            # See https://sourceware.org/binutils/docs/as/Dc.html
            out.write(
                dedent(f'''\
        .p2align %s
        .dc.a {f.c_symbol_name}_name
        .p2align %s
        .int32 {os.path.getsize(f.srcpath)}
        .p2align %s
        .dc.a {f.c_symbol_name}
        ''' % (align, align, align)))

        ptr_size = 4
        elem_size = (2 * ptr_size) + 4
        total_size = len(embed_files) * elem_size + 4
        out.write(
            dedent(f'''\
      .dc.a 0
      .size __emscripten_embedded_file_data, {total_size}
      '''))
    if options.wasm64:
        target = 'wasm64-unknown-emscripten'
    else:
        target = 'wasm32-unknown-emscripten'
    shared.check_call([
        shared.LLVM_MC, '-filetype=obj', '-triple=' + target, '-o',
        options.obj_output, asm_file
    ])
Exemple #32
0
def do_wasm2c(infile):
    assert Settings.STANDALONE_WASM
    WASM2C = NODE_JS + [path_from_root('node_modules', 'wasm2c', 'wasm2c.js')]
    WASM2C_DIR = path_from_root('node_modules', 'wasm2c')
    c_file = unsuffixed(infile) + '.wasm.c'
    h_file = unsuffixed(infile) + '.wasm.h'
    cmd = WASM2C + [infile, '-o', c_file]
    check_call(cmd)
    total = '''\
/*
* This file was generated by emcc+wasm2c. To compile it, use something like
*
*   $CC FILE.c -O2 -lm -DWASM_RT_MAX_CALL_STACK_DEPTH=8000
*/
'''
    SEP = '\n/* ==================================== */\n'

    def bundle_file(total, filename):
        with open(filename) as f:
            total += '// ' + filename + '\n' + f.read() + SEP
        return total

    # hermeticize the C file, by bundling in the wasm2c/ includes
    headers = [(WASM2C_DIR, 'wasm-rt.h'), (WASM2C_DIR, 'wasm-rt-impl.h'),
               ('', h_file)]
    for header in headers:
        total = bundle_file(total, os.path.join(header[0], header[1]))
    # add the wasm2c output
    with open(c_file) as read_c:
        c = read_c.read()
    total += c + SEP
    # add the wasm2c runtime
    total = bundle_file(total, os.path.join(WASM2C_DIR, 'wasm-rt-impl.c'))
    # add the support code
    support_files = ['base']
    if Settings.AUTODEBUG:
        support_files.append('autodebug')
    if Settings.EXPECT_MAIN:
        # TODO: add an option for direct OS access. For now, do that when building
        #       an executable with main, as opposed to a library
        support_files.append('os')
        support_files.append('main')
    else:
        support_files.append('os_sandboxed')
        support_files.append('reactor')
        # for a reactor, also append wasmbox_* API definitions
        with open(h_file, 'a') as f:
            f.write('''
// wasmbox_* API
// TODO: optional prefixing
extern void wasmbox_init(void);
''')
    for support_file in support_files:
        total = bundle_file(
            total, path_from_root('tools', 'wasm2c', support_file + '.c'))
    # remove #includes of the headers we bundled
    for header in headers:
        total = total.replace('#include "%s"\n' % header[1],
                              '/* include of %s */\n' % header[1])
    # generate the necessary invokes
    invokes = []
    for sig in re.findall(r"\/\* import\: 'env' 'invoke_(\w+)' \*\/", total):

        def s_to_c(s):
            if s == 'v':
                return 'void'
            elif s == 'i':
                return 'u32'
            elif s == 'j':
                return 'u64'
            elif s == 'f':
                return 'f32'
            elif s == 'd':
                return 'f64'
            else:
                exit_with_error('invalid sig element:' + str(s))

        def name(i):
            return 'a' + str(i)

        wabt_sig = sig[0] + 'i' + sig[1:]
        typed_args = ['u32 fptr'] + [
            s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))
        ]
        types = ['u32'] + [s_to_c(sig[i]) for i in range(1, len(sig))]
        args = ['fptr'] + [name(i) for i in range(1, len(sig))]
        invokes.append(
            '%s_INVOKE_IMPL(%sZ_envZ_invoke_%sZ_%s, (%s), (%s), (%s), Z_dynCall_%sZ_%s);'
            % ('VOID' if sig[0] == 'v' else 'RETURNING',
               (s_to_c(sig[0]) + ', ') if sig[0] != 'v' else '', sig, wabt_sig,
               ', '.join(typed_args), ', '.join(types), ', '.join(args), sig,
               wabt_sig))
    total += '\n'.join(invokes)
    # write out the final file
    with open(c_file, 'w') as out:
        out.write(total)
Exemple #33
0
def do_wasm2c(infile):
    assert settings.STANDALONE_WASM
    WASM2C = config.NODE_JS + [path_from_root('node_modules/wasm2c/wasm2c.js')]
    WASM2C_DIR = path_from_root('node_modules/wasm2c')
    c_file = unsuffixed(infile) + '.wasm.c'
    h_file = unsuffixed(infile) + '.wasm.h'
    cmd = WASM2C + [infile, '-o', c_file]
    check_call(cmd)
    total = '''\
/*
 * This file was generated by emcc+wasm2c. To compile it, use something like
 *
 *   $CC FILE.c -O2 -lm -DWASM_RT_MAX_CALL_STACK_DEPTH=8000
 */
'''
    SEP = '\n/* ==================================== */\n'

    def bundle_file(filename):
        nonlocal total
        with open(filename) as f:
            total += '// ' + filename + '\n' + f.read() + SEP

    # hermeticize the C file, by bundling in the wasm2c/ includes
    headers = [(WASM2C_DIR, 'wasm-rt.h'), (WASM2C_DIR, 'wasm-rt-impl.h'),
               ('', h_file)]
    for header in headers:
        bundle_file(os.path.join(header[0], header[1]))
    # add the wasm2c output
    bundle_file(c_file)
    # add the wasm2c runtime
    bundle_file(os.path.join(WASM2C_DIR, 'wasm-rt-impl.c'))
    # add the support code
    support_files = ['base.c']
    if settings.AUTODEBUG:
        support_files.append('autodebug.c')
    if settings.EXPECT_MAIN:
        # TODO: add an option for direct OS access. For now, do that when building
        #       an executable with main, as opposed to a library
        support_files.append('os.c')
        support_files.append('main.c')
    else:
        support_files.append('os_sandboxed.c')
        support_files.append('reactor.c')
        # for a reactor, also append wasmbox_* API definitions
        with open(h_file, 'a') as f:
            f.write('''
// wasmbox_* API
// TODO: optional prefixing
extern void wasmbox_init(void);
''')
    for support_file in support_files:
        bundle_file(path_from_root(f'tools/wasm2c/{support_file}'))
    # remove #includes of the headers we bundled
    for header in headers:
        total = total.replace('#include "%s"\n' % header[1],
                              '/* include of %s */\n' % header[1])
    # generate the necessary invokes
    invokes = []
    for sig in re.findall(r"\/\* import\: 'env' 'invoke_(\w+)' \*\/", total):
        all_func_types = get_func_types(total)

        def name(i):
            return 'a' + str(i)

        wabt_sig = sig[0] + 'i' + sig[1:]
        typed_args = [
            s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))
        ]
        full_typed_args = ['u32 fptr'] + typed_args
        types = [s_to_c(sig[i]) for i in range(1, len(sig))]
        args = [name(i) for i in range(1, len(sig))]
        c_func_type = s_to_c(
            sig[0]) + ' (*)(' + (', '.join(types) if types else 'void') + ')'
        if sig not in all_func_types:
            exit_with_error('could not find signature ' + sig +
                            ' in function types ' + str(all_func_types))
        type_index = all_func_types[sig]

        invokes.append(
            r'''
IMPORT_IMPL(%(return_type)s, Z_envZ_invoke_%(sig)sZ_%(wabt_sig)s, (%(full_typed_args)s), {
  VERBOSE_LOG("invoke\n"); // waka
  u32 sp = WASM_RT_ADD_PREFIX(Z_stackSaveZ_iv)();
  if (next_setjmp >= MAX_SETJMP_STACK) {
    abort_with_message("too many nested setjmps");
  }
  u32 id = next_setjmp++;
  int result = setjmp(setjmp_stack[id]);
  %(declare_return)s
  if (result == 0) {
    %(receive)sCALL_INDIRECT(w2c___indirect_function_table, %(c_func_type)s, %(type_index)s, fptr %(args)s);
    /* if we got here, no longjmp or exception happened, we returned normally */
  } else {
    /* A longjmp or an exception took us here. */
    WASM_RT_ADD_PREFIX(Z_stackRestoreZ_vi)(sp);
    WASM_RT_ADD_PREFIX(Z_setThrewZ_vii)(1, 0);
  }
  next_setjmp--;
  %(return)s
});
''' % {
                'return_type':
                s_to_c(sig[0]) if sig[0] != 'v' else 'void',
                'sig':
                sig,
                'wabt_sig':
                wabt_sig,
                'full_typed_args':
                ', '.join(full_typed_args),
                'type_index':
                type_index,
                'c_func_type':
                c_func_type,
                'args': (', ' + ', '.join(args)) if args else '',
                'declare_return':
                (s_to_c(sig[0]) +
                 ' returned_value = 0;') if sig[0] != 'v' else '',
                'receive':
                'returned_value = ' if sig[0] != 'v' else '',
                'return':
                'return returned_value;' if sig[0] != 'v' else ''
            })

    total += '\n'.join(invokes)

    # adjust sandboxing
    TRAP_OOB = 'TRAP(OOB)'
    assert total.count(TRAP_OOB) == 2
    if settings.WASM2C_SANDBOXING == 'full':
        pass  # keep it
    elif settings.WASM2C_SANDBOXING == 'none':
        total = total.replace(TRAP_OOB, '{}')
    elif settings.WASM2C_SANDBOXING == 'mask':
        assert not settings.ALLOW_MEMORY_GROWTH
        assert (settings.INITIAL_MEMORY &
                (settings.INITIAL_MEMORY - 1)) == 0, 'poewr of 2'
        total = total.replace(TRAP_OOB, '{}')
        MEM_ACCESS = '[addr]'
        assert total.count(MEM_ACCESS) == 3, '2 from wasm2c, 1 from runtime'
        total = total.replace(MEM_ACCESS,
                              '[addr & %d]' % (settings.INITIAL_MEMORY - 1))
    else:
        exit_with_error('bad sandboxing')

    # adjust prefixing: emit simple output that works with multiple libraries,
    # each compiled into its own single .c file, by adding 'static' in some places
    # TODO: decide on the proper pattern for this in an upstream discussion in
    #       wasm2c; another option would be to prefix all these things.
    for rep in [
            'uint32_t wasm_rt_register_func_type(',
            'void wasm_rt_trap(',
            'void wasm_rt_allocate_memory(',
            'uint32_t wasm_rt_grow_memory(',
            'void wasm_rt_allocate_table(',
            'jmp_buf g_jmp_buf',
            'uint32_t g_func_type_count',
            'FuncType* g_func_types',
            'uint32_t wasm_rt_call_stack_depth',
            'uint32_t g_saved_call_stack_depth',
    ]:
        # remove 'extern' from declaration
        total = total.replace('extern ' + rep, rep)
        # add 'static' to implementation
        old = total
        total = total.replace(rep, 'static ' + rep)
        assert old != total, f'did not find "{rep}"'

    # write out the final file
    with open(c_file, 'w') as out:
        out.write(total)