blob: 761730a5610bcdc94b7595540d190181abeec6ef [file] [log] [blame]
# 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)