#!/usr/bin/env bash
export out=${out:-out}
. global/common.sh
noimpl() {
say "$1 is not currently implemented on your system. an exciting chance for you to contribute, no?"
exit 1
}
timestamp() { date "+%H:%M:%S %A"; }
if test "$os$arch$bits" = ""; then
say "set the following environment variables to the appropriate atoms describing your system. for help determining the appropriate atoms, see libk.md"
say ' - $os={lin|fbsd|hai|osx…}'
say ' - $arch={x86|arm|ia64|mips…}'
say ' - $bits={|32|64…}'
exit 1
fi
if test "$1" = "-C"; then
say "precleaning repo"
./clean.sh
fi
# TODO: make it possible for user to change
# default set with environment vars
modules=(kcore kmem kstr kio kgraft kfile)
target=$arch.$os
if test "$bits" != ""; then
target=$target.$bits
fi
case $os in
lin|?bsd|and|dar|osx) posix=yes; unix=yes;;
hai) posix=yes; unix=no;;
*) posix=no; unix=no;;
esac
case $os.$bits in
win.32) bin_fmt=win32;;
win.64) bin_fmt=win64;;
osx.32|dar.32) bin_fmt=macho32;;
osx.64|dar.64) bin_fmt=macho64;;
dos.*) bin_fmt=dosexe;;
none.*) bin_fmt=bin;;
*.32) bin_fmt=elf32;;
*.64) bin_fmt=elf64;;
*) say "cannot determine correct binary format to use for target $target"; exit 1;;
esac
# first, we establish the
# parameters of the build
has cc && _cc=cc
has clang && _cc=clang
has gcc && _cc=gcc
cc=${cc:-$_cc}
has m4 && _m4=m4
m4=${m4:-$_m4}
has nasm && asm=nasm
has yasm && asm=yasm
export gen=${gen:-gen}
library=${libkind:-static} # {static|shared|both}
case $library in
static) build_static_library=yes
build_shared_library=no;;
shared) build_static_library=no
build_shared_library=yes;;
both) build_static_library=yes
build_shared_library=yes;;
esac
check cc "your C compiler of choice"
check asm "an assembler that takes Intel syntax and nasm-style-macros"
check m4 "the path to your m4 installation"
export build=$(global/build-id.sh)
case $os in
lin) p_headers_syscall=${p_headers_syscall:-/usr/include/asm/unistd_${bits}.h}
p_headers_errno=${p_headers_errno:-/usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h};;
fbsd) p_headers_syscall=${p_headers_syscall:-/usr/include/sys/syscall.h}
p_headers_errno=${p_headers_errno:-/usr/include/errno.h};;
esac
check p_headers_syscall \
'the location of a header defining your syscall numbers'
check p_headers_errno \
'the location of a header defining the values of each errno symbol'
macro_compile_env="-Datom_target_arch=$arch -Datom_target_os=$os -Dtarget_posix=$posix -Dtarget_unix=$unix"
if test "$bits" != ""; then
macro_compile_env="$macro_compile_env -Datom_target_bits=$bits"
fi
comp_mac() { $m4 $macro_compile_env -I "$gen" $3 "$1" > "$2"; }
comp_asm() { $asm "-f$bin_fmt" -i "$gen" $1 -o "$2"; }
comp_co() { comp_c $1 $2 "-c -fPIC"; }
comp_c(){
src=$1
output=$2
flags=$3
$cc $src $3 -std=c11 -isystem "$out" -isystem "$gen" -isystem "arch/" -nostdlib "-L$out" "-o$output"
}
scan() { find "$1" -name "$2"; }
say "commencing libk build $build at $(timestamp)"
set -x
# get type data
mkdir -p $gen
$cc -D_emit_m4_include arch/typesize.c -o $gen/typesize
$gen/typesize > gen/typesize.m
# generate syscall tables
case $os in
lin) grep -h "#define __NR_" $p_headers_syscall | sed 's;^#define __NR_;;' > $gen/calls.tbl;;
fbsd) grep -h "#define SYS_" $p_headers_syscall | sed 's;^#define SYS_;;' | sed 's;[\t ]\+; ;' > $gen/calls.tbl;;
*) noimpl 'system call table generation';;
esac
awk -f arch/syscall.awk -v out=s <$gen/calls.tbl >$gen/system_calls.s
awk -f arch/syscall.awk -v out=h <$gen/calls.tbl >$gen/system_calls.h
# generate errno tables
grep -h "#[ ]*define[ ]\+E" $p_headers_errno | sed 's;^#[\t ]*define[\t ]\+\(E[A-Z0-9]\+\).*$;k_platform_error_\1 \1;' > $gen/error_names.tbl
cat $p_headers_errno $gen/error_names.tbl | cpp -P >$gen/error_numbers.tbl
awk -f arch/errtbl.awk <$gen/error_numbers.tbl >$gen/error_table.h
# generate symbol tables for error handling functions
mkdir -p $out/k
awk -f global/gen-conds.awk <global/modules >$out/k/internal.egroup.h
awk -f global/gen-ident.awk <global/modules >$gen/internal.ident.c
comp_co $gen/internal.ident.c $out/internal.ident.o
# first pass: copy all headers into place,
# including ones we need to generate
for mod in ${modules[@]}; do
for h in $(scan $mod '*.h'); do
base=$(basename $h)
cp "$h" "$out/k/$base"
done
for h in $(scan $mod '*.h.m'); do
base=$(basename $h)
dest=${base%%.m}
comp_mac "$h" "$out/k/$dest"
done
done
# second pass: generate manpage, html, and pdf
# versions of the documentation from the md src
mkdir -p $out/doc/{man,html,pdf}
global/build-manpage.sh libk.md
for mod in ${modules[@]}; do
for doc in $(scan $mod '*.md'); do
base="$(basename $doc)"
stem="${base%%.md}"
global/build-manpage.sh "$doc"
global/build-html.sh "$doc"
global/build-pdf.sh "$doc"
done
done
# third pass: compile sources and save the
# resulting object files to $out, tracking
# which is a runtime or function unit. exe's
# will not be compiled until a later pass
fn_objects=()
rt_objects=()
data_objects=( $out/internal.ident.o )
for mod in ${modules[@]}; do
for fn in $(scan $mod '*.fn.c'); do
base="$(basename $fn)"
dest="$out/$mod.${base%%.c}.o"
comp_co "$fn" "$dest"
fn_objects+=("$dest")
done
for rt in $(scan $mod '*.rt.c'); do
base="$(basename $rt)"
dest="$out/$mod.${base%%.c}.o"
comp_co "$rt" "$dest"
rt_objects+=("$dest")
done
for fn in $(scan $mod "*.fn.$target.s"); do
base="$(basename $fn)"
dest="$out/$mod.${base%%.s}.o"
comp_asm "$fn" "$dest"
fn_objects+=("$dest")
done
for rt in $(scan $mod "*.rt.$target.s"); do
base="$(basename $rt)"
dest="$out/$mod.${base%%.s}.o"
comp_asm "$rt" "$dest"
rt_objects+=("$dest")
done
done
# fourth pass: link the libraries that are
# configured to be built
if test $build_static_library == yes; then
for obj in ${fn_objects[@]} ${rt_objects[@]} ${data_objects[@]}; do
ar rc $out/libk.a $obj
done
ranlib $out/libk.a
fi
if test $build_shared_library == yes; then
ld -r ${rt_objects[@]} -o $out/boot.o
ld -shared ${fn_objects[@]} -o $out/libk.so
fi
# fifth pass: compile the executable tools
# against the libraries created in pass 5
for mod in ${modules[@]}; do
for exe in $(scan $mod '*.exe.c'); do
base="$(basename $exe)"
dest="$out/$mod.${base%%.exe.c}"
if test $build_shared_library == yes; then
comp_c "$out/boot.o $exe" "$dest" -lk
else
comp_c "$exe" "$dest" -lk
fi
done
done
set +x
say "all passes finished; build $build complete at $(timestamp)"