aboutsummaryrefslogtreecommitdiff
path: root/src/tools/zcc
blob: a53fe01c633659a4e8a414ba7d4c4d4181187d22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash
# zcc: compiles a ZC (ZygoteC) program into a static binary. the binary holds
# the runtime, the program and a memory map sized to them, and needs nothing
# from the system but the kernel (linux x86-64 and any host with a static
# libc). the program reads and writes through the same syscalls as zy(1).
#
#   src/tools/zcc [-o OUT] [-k] FILE.zc
#
# -o OUT    the binary to write (default: FILE without .zc)
# -k        keep the build directory and print where it is
# CC        the C compiler, one with c23 #embed (default: src/tools/findcc.sh). CFLAGS adds to -O2
#
# the build is three steps: automap sizes the map to the program and writes the
# genome (the compiled program image) for it; the micro core and its linux port
# are compiled against that map; and the link is static. make run PROG= builds
# the same image without the static link.
set -e
here="$(cd "$(dirname "$0")/../.." && pwd)"
CC=${CC:-$(sh "$here/src/tools/findcc.sh")}
out=""; keep=0
while [ $# -gt 0 ]; do
	case "$1" in
		-o) [ $# -ge 2 ] || { echo "zcc: -o needs a name" >&2; exit 2; }; out="$2"; shift 2 ;;
		-k) keep=1; shift ;;
		-h|--help) printf '%s\n' 'usage: src/tools/zcc [-o OUT] [-k] FILE.zc' 'compiles a source file into a standalone binary; links statically where supported.' 'options:' '  -o OUT      output binary path; defaults to the source basename without .zc' '  -k          keep the temporary build directory' '  --help, -h  show this help and exit' 'environment: CC selects the c compiler (one with #embed); CFLAGS adds compiler flags.'; exit 0 ;;
		-*) echo "zcc: unknown option $1" >&2; exit 2 ;;
		*) break ;;
	esac
done
[ $# -eq 1 ] || { echo "usage: src/tools/zcc [-o OUT] [-k] FILE.zc" >&2; exit 2; }
src="$1"
[ -f "$src" ] || { echo "zcc: no such file: $src" >&2; exit 1; }
case "$src" in *.zc) ;; *) echo "zcc: the source must end in .zc" >&2; exit 2 ;; esac
[ -n "$out" ] || { out="${src%.zc}"; out="$(basename "$out")"; }
case "$src" in /*) abs="$src" ;; *) abs="$PWD/$src" ;; esac

work="$(mktemp -d "${TMPDIR:-/tmp}/zcc.XXXXXX")"
cleanup() { [ "$keep" = 1 ] && echo "zcc: build kept in $work" >&2 || rm -rf "$work"; }
trap cleanup EXIT

# the map and the genome for this program only
( cd "$here" && bash src/tools/automap.sh run "$work/run" src/runtime/run.zc "$abs" ) >/dev/null
cp "$here/src/micro/micro.c" "$here/src/micro/micro_port.h" "$here/src/micro/port_linux.c" \
	"$here/src/core/fops.h" "$here/src/core/bops.h" "$here/src/core/stack.h" "$here/src/core/hold.h" "$here/src/core/genome.h" "$work/run/"

# static where the toolchain allows it; a plain link otherwise, with a note
static=-static
if ! printf 'int main(void){return 0;}\n' | $CC -x c -static -o "$work/probe" - >/dev/null 2>&1; then
	static=""
	echo "zcc: this toolchain cannot link -static; the binary is dynamic" >&2
fi
$CC -O2 -w -fwrapv -pthread -DZY_THREADS ${CFLAGS:-} $static "$work/run/micro.c" "$work/run/port_linux.c" \
	-I"$work/run" -o "$out"
echo "zcc: wrote $out ($(wc -c < "$out" | tr -d ' ') bytes)"