| # Copyright 2020 The Emscripten Authors. All rights reserved. |
| # Emscripten is available under two separate licenses, the MIT license and the |
| # University of Illinois/NCSA Open Source License. Both these licenses can be |
| # found in the LICENSE file. |
| |
| import os |
| import re |
| |
| from tools.shared import Settings, path_from_root, unsuffixed, NODE_JS, run_process, exit_with_error |
| |
| |
| 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] |
| run_process(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.RAW_OS: |
| support_files.append('os') |
| else: |
| support_files.append('os_sandboxed') |
| if Settings.EXPECT_MAIN: |
| support_files.append('main') |
| else: |
| 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) |