101 lines
2.6 KiB
Plaintext
101 lines
2.6 KiB
Plaintext
// compile.ce — compile a .cm module to native .dylib via QBE
|
|
//
|
|
// Usage:
|
|
// cell --core . compile.ce <file.cm>
|
|
//
|
|
// Produces <file>.dylib in the current directory.
|
|
|
|
var fd = use('fd')
|
|
var os = use('os')
|
|
|
|
if (length(args) < 1) {
|
|
print('usage: cell --core . compile.ce <file.cm>')
|
|
return
|
|
}
|
|
|
|
var file = args[0]
|
|
var base = file
|
|
if (ends_with(base, '.cm')) {
|
|
base = text(base, 0, length(base) - 3)
|
|
}
|
|
|
|
var safe = replace(replace(base, '/', '_'), '-', '_')
|
|
var symbol = 'js_' + safe + '_use'
|
|
var tmp = '/tmp/qbe_' + safe
|
|
var ssa_path = tmp + '.ssa'
|
|
var s_path = tmp + '.s'
|
|
var o_path = tmp + '.o'
|
|
var rt_o_path = '/tmp/qbe_rt.o'
|
|
var dylib_path = base + '.dylib'
|
|
var cwd = fd.getcwd()
|
|
var rc = 0
|
|
|
|
// Step 1: emit QBE IL
|
|
print('emit qbe...')
|
|
rc = os.system('cd ' + cwd + ' && ./cell --core . --emit-qbe ' + file + ' > ' + ssa_path)
|
|
if (rc != 0) {
|
|
print('failed to emit qbe il')
|
|
return
|
|
}
|
|
|
|
// Step 2: post-process — insert dead labels after ret/jmp, append wrapper
|
|
// Use awk via shell to avoid blob/slurpwrite issues with long strings
|
|
print('post-process...')
|
|
var awk_cmd = `awk '
|
|
/^[[:space:]]*ret / || /^[[:space:]]*jmp / { need_label=1; print; next }
|
|
need_label && /^[[:space:]]*[^@}]/ && NF > 0 {
|
|
print "@_dead_" dead_id; dead_id++; need_label=0
|
|
}
|
|
/^@/ || /^}/ || NF==0 { need_label=0 }
|
|
{ print }
|
|
' ` + ssa_path + ` > ` + tmp + `_fixed.ssa`
|
|
rc = os.system(awk_cmd)
|
|
if (rc != 0) {
|
|
print('post-process failed')
|
|
return
|
|
}
|
|
|
|
// Append wrapper function
|
|
var wrapper_cmd = `printf '\nexport function l $` + symbol + `(l %%ctx) {\n@entry\n %%frame =l alloc8 4096\n %%result =l call $cell_main(l %%ctx, l %%frame)\n ret %%result\n}\n' >> ` + tmp + `_fixed.ssa`
|
|
rc = os.system(wrapper_cmd)
|
|
if (rc != 0) {
|
|
print('wrapper append failed')
|
|
return
|
|
}
|
|
|
|
// Step 3: compile QBE IL to assembly
|
|
print('qbe compile...')
|
|
rc = os.system('~/.local/bin/qbe -o ' + s_path + ' ' + tmp + '_fixed.ssa')
|
|
if (rc != 0) {
|
|
print('qbe compilation failed')
|
|
return
|
|
}
|
|
|
|
// Step 4: assemble
|
|
print('assemble...')
|
|
rc = os.system('cc -c ' + s_path + ' -o ' + o_path)
|
|
if (rc != 0) {
|
|
print('assembly failed')
|
|
return
|
|
}
|
|
|
|
// Step 5: compile runtime stubs (cached — skip if already built)
|
|
if (!fd.is_file(rt_o_path)) {
|
|
print('compile runtime stubs...')
|
|
rc = os.system('cc -c ' + cwd + '/qbe_rt.c -o ' + rt_o_path + ' -fPIC')
|
|
if (rc != 0) {
|
|
print('runtime stubs compilation failed')
|
|
return
|
|
}
|
|
}
|
|
|
|
// Step 6: link dylib
|
|
print('link...')
|
|
rc = os.system('cc -shared -fPIC -undefined dynamic_lookup ' + o_path + ' ' + rt_o_path + ' -o ' + cwd + '/' + dylib_path)
|
|
if (rc != 0) {
|
|
print('linking failed')
|
|
return
|
|
}
|
|
|
|
print('built: ' + dylib_path)
|