ADDED build.sh Index: build.sh ================================================================== --- build.sh +++ build.sh @@ -0,0 +1,212 @@ +#!/usr/bin/env bash +. global/common.sh +noimpl() { + say "$1 is not currently implemented on your system. an exciting chance for you to contribute, no?" + exit 1 +} + +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 + +# 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;; +esac + +# first, we establish the +# parameters of the build +has gcc && _cc=gcc +has clang && _cc=clang +has cc && _cc=cc +cc=${cc:-$_cc} +has m4 && _m4=m4 +m4=${m4:-$_m4} +has yasm && asm=yasm +has nasm && asm=nasm +export out=${out:-out} +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 + +for mod in ${modules[@]}; do + say "building libk with $mod" +done + +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_clib $1 $2 -c; } +comp_clib(){ + src=$1 + output=$2 + flags=$3 + $cc $src $3 -std=c11 -isystem "$out" -isystem "$gen" -isystem "arch/" -fPIC -nostdlib "-L$out" "-o$output" +} + +scan() { find "$1" -name "$2"; } + +# now we make sure all the appropriate +# directories exist + +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 $out/k/internal.egroup.h +awk -f global/gen-ident.awk $gen/internal.ident.c +comp_co $gen/internal.ident.c $out/internal.ident.o + +# first pass: copy all raw headers into place +for mod in ${modules[@]}; do + for h in $(scan $mod '*.h'); do + base=$(basename $h) + cp "$h" "$out/k/$base" + done +done + +# second pass: run macro headers through m4 and +# copy the resulting file into place + +for mod in ${modules[@]}; do + for h in $(scan $mod '*.h.m'); do + base=$(basename $h) + dest=${base%%.m} + comp_mac "$h" "$out/k/$dest" + done +done + +# third 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" + # TODO html + # TODO pdf + done +done + +# fourth 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 + +echo fns: ${fn_objects[@]} +echo rts: ${rt_objects[@]} ADDED clean.sh Index: clean.sh ================================================================== --- clean.sh +++ clean.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +. global/common.sh + +out=${out:-out} +gen=${gen:-gen} + +say "cleaning libk build artifacts" + +set -x +rm -r $out +rm -r $gen Index: global/build-id.sh ================================================================== --- global/build-id.sh +++ global/build-id.sh @@ -4,11 +4,11 @@ origin=1566169297 now=$(date +%s) delta=$(expr $now - $origin) -if test "$1" = "private"; then +if test "$id_mode" = "private"; then # for privacy's sake, we're not to show # the hostname. instead, we calculate a # hash based on the time delta and the # output of uname -a for extra entropy if has "$HASH"; then ADDED global/build-manpage.sh Index: global/build-manpage.sh ================================================================== --- global/build-manpage.sh +++ global/build-manpage.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env sh +(test -d global && test -f build.sh) || { + echo >&2 "($0) run $me from root of libk source directory" + exit 1 +} + +. global/common.sh +test "$out" = "" && { + say "\$out environment variable must be set to your build directory - are you running this script by hand? run make doc in the root directory instead!" + exit 2 +} + +if ! has cmark; then + say "to generate documentation for libk, install the cmark package and try again" + exit 3 +fi + + +file="$1" +filename="$(basename "$file")" +stem=${filename%%.md} +mandest="$out/doc/man" +section=${section:-4} +out="$mandest/$stem.$section" +desc_rec="$(grep -m1 "^$name:" global/modules)" +if test $? -eq 0; then + desc=" - $(echo $desc_rec | cut -d: -f4)" +else + desc="" +fi +date="$(date -r"$file" "+%d %A %Y")" + +mkdir -p "$mandest" + +echo >"$out" ".TH ${name^^} \"$section\" \"$date\" \"hale.su libk [r$build]\" \"modules\"" + +echo >>"$out" ".SH NAME" +echo >>"$out" "$stem$desc" +echo >>"$out" ".SH SYNOPSIS" + +dhead=$(grep -m1 -n "^# description$" "$file") +if test $? -eq 0; then + descline=$(echo "$dhead" | cut -d: -f1) + offset=1 +else + descline=$(grep -m2 -n "^#" "$file" | tail -n1 | cut -d: -f1) + offset=0 +fi + +tail -n+2 $file | head -n$(expr $descline - 2) | cmark -t man >>"$out" + +echo >>"$out" ".SH DESCRIPTION" + +tail -n+$(expr $descline + $offset) "$file" | cmark -t man >> "$out" + +if has gzip; then + gzip -f "$out" + out="$out.gz" +fi + +say "wrote manpage for $stem to $out" DELETED global/emit-manpage.sh Index: global/emit-manpage.sh ================================================================== --- global/emit-manpage.sh +++ global/emit-manpage.sh @@ -1,49 +0,0 @@ -#!/usr/bin/env sh -(test -d global && test -d $1) || { - echo >&2 "($0) run $me from root of libk source directory" - exit 1 -} - -. global/common.sh -test "$OUT" = "" && { - say "\$OUT environment variable must be set to your build directory - are you running this script by hand? run make doc in the root directory instead!" - exit 2 -} - -if ! has cmark; then - say "to generate documentation for libk, install the cmark package and try again" - exit 3 -fi - - -name=$1 -mandest=$OUT/doc/man -out=$2 -file=$name/$name.md -desc="$(grep -m1 "^$name:" global/modules | cut -d: -f4)" -date="$(date -r"$file" "+%d %A %Y")" - -mkdir -p $mandest - -echo >$out ".TH ${name^^} \"$section\" \"$date\" \"hale.su libk [r$BUILD]\" \"modules\"" - -echo >>$out ".SH NAME" -echo >>$out "$name - $desc" -echo >>$out ".SH SYNOPSIS" - -dhead=$(grep -m1 -n "^# description$" $file) -if test $? -eq 0; then - descline=$(echo "$dhead" | cut -d: -f1) - offset=1 -else - descline=$(grep -m2 -n "^#" $file | tail -n1 | cut -d: -f1) - offset=0 -fi - -tail -n+2 $file | head -n$(expr $descline - 2) | cmark -t man >> $out - -echo >>$out ".SH DESCRIPTION" - -tail -n+$(expr $descline + $offset) $file | cmark -t man >> $out - -say "wrote manpage for $name to $file" ADDED global/gen-conds.awk Index: global/gen-conds.awk ================================================================== --- global/gen-conds.awk +++ global/gen-conds.awk @@ -0,0 +1,19 @@ +BEGIN { FS=":" + offset = 0x7F + + print "#ifndef KIglobal_cond" + print "#define KIglobal_cond" + print "typedef enum kglobal_cond {" + printf("kglobal_module_offset = 0x%x,\n", offset) +} + +$2 == "short" { printf("\t%scond_id = 0x%x,\n", $3, offset*NR) } +$2 == "long" { printf("\t%s_cond_id = 0x%x,\n", $3, offset*NR) } + +END { + print "} kglobal_cond;" + print "extern struct kglobal_module_record" + print "\t{ const char* name, * desc, ** error_list }" + print "\tkglobal_module_ident[];" + print "#endif" +} ADDED global/gen-ident.awk Index: global/gen-ident.awk ================================================================== --- global/gen-ident.awk +++ global/gen-ident.awk @@ -0,0 +1,20 @@ +BEGIN { + defs = "" + FS = ":" + ORS = "" + print "#include \n" + print "extern const char" +} + +{ + if (NR != 1) sep = "," + print sep"\n\t*"$1"_error_strings[]" + defs = defs "\t{ \""$1"\", \"k "$4"\", "$1"_error_strings },\n" +} + +END { + print ";\n" + print "struct kglobal_module_record kglobal_module_ident[] = {\n" + print defs + print "};" +} DELETED global/genconds.awk Index: global/genconds.awk ================================================================== --- global/genconds.awk +++ global/genconds.awk @@ -1,19 +0,0 @@ -BEGIN { FS=":" - offset = 0x7F - - print "#ifndef KIglobal_cond" - print "#define KIglobal_cond" - print "typedef enum kglobal_cond {" - printf("kglobal_module_offset = 0x%x,\n", offset) -} - -$2 == "short" { printf("\t%scond_id = 0x%x,\n", $3, offset*NR) } -$2 == "long" { printf("\t%s_cond_id = 0x%x,\n", $3, offset*NR) } - -END { - print "} kglobal_cond;" - print "extern struct kglobal_module_record" - print "\t{ const char* name, * desc, ** error_list }" - print "\tkglobal_module_ident[];" - print "#endif" -} DELETED global/genident.awk Index: global/genident.awk ================================================================== --- global/genident.awk +++ global/genident.awk @@ -1,20 +0,0 @@ -BEGIN { - defs = "" - FS = ":" - ORS = "" - print "#include \n" - print "extern const char" -} - -{ - if (NR != 1) sep = "," - print sep"\n\t*"$1"_error_strings[]" - defs = defs "\t{ \""$1"\", \"k "$4"\", "$1"_error_strings },\n" -} - -END { - print ";\n" - print "struct kglobal_module_record kglobal_module_ident[] = {\n" - print defs - print "};" -} ADDED install.sh Index: install.sh ================================================================== --- install.sh +++ install.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +. global/common.sh + +say "this component of the build system does not yet exist" Index: kcore/type.h.m ================================================================== --- kcore/type.h.m +++ kcore/type.h.m @@ -2,10 +2,11 @@ dnl ~ lexi hale dnl this file gathers information on the environment it's dnl being compiled in, defining types that our code dnl needs. it will be emitted as . dnl vim: ft=c +include(`typesize.m') changequote(`“',`”') #ifndef KItype #define KItype /* we define 64-bit types first due to an oddity in how DELETED kio/io.h Index: kio/io.h ================================================================== --- kio/io.h +++ kio/io.h @@ -1,88 +0,0 @@ -#ifndef KIio -#define KIio -/* - * ~ lexi hale - * this header declares IO primitive functions and - * structures. it is the same for all platforms. - * platform-specific code is found in the *.platform.h - * files. - */ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum kiostream_kind { - kiostream_closed, - // this kiostream cannot be written to - kiostream_file, - // this kiostream represents a file - kiostream_sock, - // this kiostream is attached to a socket, - // UNIX, IP, or otherwise - kiostream_term, - // this socket is being used to communicate - // directly with a human being - kiostream_ansi, - // like kiostream_term, but can also understand - // ANSI control codes - kiostream_pipe, - // this kiostream sends or receives data to - // another running process - kiostream_other - // no fuckin idea -} kiostream_kind; - -typedef struct kiostream { - kiostream_kind kind; - #include "kiostream.platform.h" -} kiostream; - -typedef struct kiochan { - kiostream in; - // text can be read from this stream - kiostream out; - // text can be written to this stream -} kiochan; - -#include -typedef enum kiocond { - /* to check if a call failed, perform (x >= kiocond_fail) where x - * is that call's return value. more typically however you should - * select explicitly against kiocond_ok or kiocond_partial, since - * those situations will usually need to be handled differently. */ - - kiocond_ok = kiocond_id, // success - - kiocond_partial, // partial read or write - kiocond_poll, // call would block - kiocond_interrupt, // call was interrupted by signal - - kiocond_fail, // action failed - unspecified reason - kiocond_fail_closed_stream, // action failed because stream is closed - kiocond_fail_invalid, - kiocond_fail_io, - kiocond_fail_no_peer, - kiocond_fail_no_space, - kiocond_fail_forbidden, - kiocond_fail_over_quota, - kiocond_fail_pfault, - kiocond_fail_too_big, - kiocond_fail_stream_mismatch, -} kiocond; - -kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel -kiocond kiorecv(kiochan, ksraw*); // receive data from a channel -kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel - // kmkind is only used if kmcell* is null -kiocond kiocon(kiochan, kiochan); // connect one channel to another - -#ifdef __cplusplus -} -#endif - -#endif ADDED kio/io.h.m Index: kio/io.h.m ================================================================== --- kio/io.h.m +++ kio/io.h.m @@ -0,0 +1,90 @@ +#ifndef KIio +#define KIio +/* + * ~ lexi hale + * this header declares IO primitive functions and + * structures. it is the same for all platforms. + * platform-specific code is found in the *.platform.h + * files. + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum kiostream_kind { + kiostream_closed, + // this kiostream cannot be written to + kiostream_file, + // this kiostream represents a file + kiostream_sock, + // this kiostream is attached to a socket, + // UNIX, IP, or otherwise + kiostream_term, + // this socket is being used to communicate + // directly with a human being + kiostream_ansi, + // like kiostream_term, but can also understand + // ANSI control codes + kiostream_pipe, + // this kiostream sends or receives data to + // another running process + kiostream_other + // no fuckin idea +} kiostream_kind; + +typedef struct kiostream { + kiostream_kind kind; + ifelse(target_posix,`yes',` + int platform_fd; + ')dnl +} kiostream; + +typedef struct kiochan { + kiostream in; + // text can be read from this stream + kiostream out; + // text can be written to this stream +} kiochan; + +#include +typedef enum kiocond { + /* to check if a call failed, perform (x >= kiocond_fail) where x + * is that call's return value. more typically however you should + * select explicitly against kiocond_ok or kiocond_partial, since + * those situations will usually need to be handled differently. */ + + kiocond_ok = kiocond_id, // success + + kiocond_partial, // partial read or write + kiocond_poll, // call would block + kiocond_interrupt, // call was interrupted by signal + + kiocond_fail, // action failed - unspecified reason + kiocond_fail_closed_stream, // action failed because stream is closed + kiocond_fail_invalid, + kiocond_fail_io, + kiocond_fail_no_peer, + kiocond_fail_no_space, + kiocond_fail_forbidden, + kiocond_fail_over_quota, + kiocond_fail_pfault, + kiocond_fail_too_big, + kiocond_fail_stream_mismatch, +} kiocond; + +kiocond kiosend(kiochan, ksraw, sz*); // send data to a channel +kiocond kiorecv(kiochan, ksraw*); // receive data from a channel +kmptr kiorecvall(kiochan, kmcell*, kmkind); // automatically allocate a bufer for a channel + // kmkind is only used if kmcell* is null +kiocond kiocon(kiochan, kiochan); // connect one channel to another + +#ifdef __cplusplus +} +#endif + +#endif DELETED kio/kiostream.posix.i Index: kio/kiostream.posix.i ================================================================== --- kio/kiostream.posix.i +++ kio/kiostream.posix.i @@ -1,1 +0,0 @@ -int platform_fd; // using posix syscalls for low-level IO ADDED legacy/kiostream.posix.i Index: legacy/kiostream.posix.i ================================================================== --- legacy/kiostream.posix.i +++ legacy/kiostream.posix.i @@ -0,0 +1,1 @@ +int platform_fd; // using posix syscalls for low-level IO ADDED legacy/makefile Index: legacy/makefile ================================================================== --- legacy/makefile +++ legacy/makefile @@ -0,0 +1,157 @@ +export OUT = $(PWD)/out + +# TODO: calculate these using $(MAKE_HOST) +export ARCH = x86 +export OS = lin +export BITS = 64 +export ROOT = $(PWD) +export TMP = $(PWD)/gen + +export BUILD = $(shell global/build-id.sh) $(build-host) + +ifneq ($(BITS),) + export TARGET = $(ARCH).$(OS).$(BITS) +else + export TARGET = $(ARCH).$(OS) +endif + +export m4 = m4 + +include makerule + +moddirs := $(wildcard k*) +binaries := $(wildcard k*/*.exe.c) +functions := $(wildcard k*/*.fn.c) +assemblies := $(wildcard k*/*.fn.$(TARGET).s) +binmods := $(sort $(dir $(binaries))) + +# i'm sorry +collect = $(strip $(foreach dir,$(moddirs),$(wildcard $(dir)/*.$1))) +transform = $(strip $(foreach dir,$(moddirs),$(patsubst $(dir)/%.$1,$(subst @,$(dir),$2),$(wildcard $(dir)/*.$1)))) + +m-hdr-macs := $(call collect,h.m) +m-c-src-macs := $(call collect,c.m) +m-s-src-macs := $(call collect,$(TARGET).s.m) + +m-c-sources := $(call transform,c.m,$(TMP)/@.%.c) +m-s-sources := $(call transform,$(TARGET).s.m,$(TMP)/@.%.$(TARGET).s) + +m-headers := $(call transform,h.m,$(OUT)/k/%.h) +m-c-objects := $(call transform,c.m,$(OUT)/@.%.o) +m-s-objects := $(call transform,$(TARGET).s.m,$(OUT)/@.%.$(TARGET).o) + +fnobjects := $(call transform,fn.c,$(OUT)/@.%.fn.o) \ + $(call transform,fn.c.m,$(OUT)/@.%.fn.o) \ + $(call transform,fn.$(TARGET).s,$(OUT)/@.%.fn.$(TARGET).o) \ + $(call transform,fn.$(TARGET).s.m,$(OUT)/@.%.fn.$(TARGET).o) + +rtobjects := $(call transform,rt.c,$(OUT)/@.%.rt.o) \ + $(call transform,rt.c.m,$(OUT)/@.%.rt.o) \ + $(call transform,rt.$(TARGET).s,$(OUT)/@.%.rt.$(TARGET).o) \ + $(call transform,rt.$(TARGET).s.m,$(OUT)/@.%.rt.$(TARGET).o) + +docs := $(wildcard k*/*.md) +docs-out := $(patsubst %.md,$(OUT)/doc/man/%.4.gz,$(notdir $(docs))) +objects := $(fnobjects) $(rtobjects) + +prefix ?= /usr +d-header = $(prefix)/include +d-lib = $(prefix)/lib +d-share = $(prefix)/share + +unix-oses = lin fbsd dar and +posix-oses = lin fbsd dar and hai mgw cyg + +ifeq ($(findstring $(OS),$(unix-oses)),$(OS)) + export UNIX = yes + export POSIX = yes +else + export UNIX = no + ifeq ($(findstring $(OS),$(posix-oses)),$(OS)) + export POSIX = yes + else + export POSIX = no + endif +endif + +# include libgcc.a in gcc builds, just in case +ifeq ($(CC),gcc) + export COMPLIB = -lgcc +endif + +all: $(OUT) defs obj tool lib.static $(OUT)/boot.o lib.shared +lib.static: defs obj $(OUT)/libk.a +lib.shared: defs obj $(OUT)/libk.so +obj: $(moddirs:%=%.obj) +defs: $(moddirs:%=%.def) +tool: $(OUT)/boot.o $(OUT)/libk.a $(binmods:%=%.tool) +doc: $(docs-out) +clean: + rm -rf $(TMP) $(OUT) + +install: all + install -d $(header-dir)/k $(share-dir)/k -o root -g wheel -m 0755 + install $(OUT)/k/* $(header-dir)/k/ -o root -g wheel -m 0644 + install $(OUT)/libk.a $(OUT)/libk.so \ + $(lib-dir) -o root -g wheel -m 0644 + install $(OUT)/boot.o $(share-dir)/k/boot.o -o root -g wheel -m 0644 + +uninstall: $(header-dir)/k $(lib-dir)/k + rm -rf $^ + +lists = BUILD moddirs functions assemblies fnobjects rtobjects binaries binmods POSIX docs docs-out +dbg: + @echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))") + +%.obj: %/makefile $(OUT)/internal.ident.o $(OUT) + cd $* && $(MAKE) obj + +%.tool: %/makefile $(OUT) + cd $* && $(MAKE) tool + +%.dbg: %/makefile $(OUT) + cd $* && $(MAKE) dbg + +%.def: %/makefile $(TMP)/typesize.def \ + $(OUT)/k/internal.egroup.h \ + $(TMP)/system_calls.h \ + $(TMP)/system_calls.s \ + $(TMP)/error_table.h \ + $(OUT) $(OUT)/k + cd $* && $(MAKE) def + +.PRECIOUS: $(TMP)/system_calls.% +$(TMP)/system_calls.%: arch/makefile + $(MAKE) -C arch $@ + +$(TMP)/error_table.h: arch/makefile + $(MAKE) -C arch $@ + +$(TMP)/typesize.def: arch/makefile $(TMP) + $(MAKE) -C arch $@ + +$(OUT)/libk.so: $(fnobjects) + ld -shared $(COMPLIB) -o $@ $^ + @# $(CC) -shared -fPIC -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o + +$(OUT)/boot.o: $(rtobjects) + ld -r $^ -o $(OUT)/boot.o + +$(OUT)/libk.a: $(fnobjects) $(rtobjects) + @# using `ar rc` and ranlib here instead of + @# `ar rcs` in case `ar` isn't the GNU version + ar rc $@ $^ + ranlib $@ + +$(OUT)/man/doc: + mkdir -p $@ + +$(OUT)/k/internal.egroup.h: global/modules global/gen-conds.awk $(OUT)/k + awk -f global/gen-conds.awk <$< >$@ +$(TMP)/internal.ident.c: global/modules global/gen-ident.awk $(OUT)/k/internal.egroup.h $(TMP) + awk -f global/gen-ident.awk <$< >$@ +$(OUT)/%.o: $(TMP)/%.c $(OUT) + $(CC) $(cflags) -c $< -o $@ + +$(OUT) $(OUT)/k $(TMP): + mkdir -p $@ ADDED legacy/makerule Index: legacy/makerule ================================================================== --- legacy/makerule +++ legacy/makerule @@ -0,0 +1,29 @@ +#- makerule +# this file contains definitions shared between modmake and +# the top-leve makefile +# vim: ft=make + +ARCH ?= ${ARCH} +BITS ?= ${BITS} +OS ?= ${OS} + +POSIX ?= ${POSIX} +UNIX ?= ${UNIX} + +ROOT ?= ${ROOT} +TMP ?= ${TMP} +OUT ?= ${OUT} + +m4 ?= ${m4} + +cflags = -std=c11 -isystem $(OUT) -isystem $(TMP) -isystem $(ROOT)/arch -fPIC -nostdlib $(COMPLIB) -L$(OUT) + +m-env = atom_target_arch=$(ARCH) +m-env += atom_target_os=$(OS) +ifneq ($(BITS),) #!!! ifdef does NOT work with environment variables + m-env += atom_target_bits=$(BITS) +endif +m-env += target_posix=$(POSIX) +m-env += target_unix=$(UNIX) + +m-comp = $(m4) $(m-env:%=-D%) ADDED legacy/modmake Index: legacy/modmake ================================================================== --- legacy/modmake +++ legacy/modmake @@ -0,0 +1,120 @@ +#- modmake +# this is the master makefile that controls the building of each +# libk module. it is included from each k*/makefile. +# vim: ft=make + +include ../makerule + +mod = $(notdir $(PWD)) +src = $(wildcard *.c) $(wildcard *.s) $(filter-out %.h,$(patsubst %.m,%,$(wildcard *.m))) +bare = $(mod:k%=%) +headers = $(wildcard *.h) $(gen-headers) $(patsubst %.m,%,$(wildcard *.h.m)) + +tools = $(filter %.exe.c, $(src)) +nontools = $(filter-out %.exe.c, $(src)) +cobjects = $(filter %.c, $(nontools)) +sobjects = $(filter %.${TARGET}.s, $(nontools)) + +obj: $(cobjects:%.c=${OUT}/$(mod).%.o) \ + $(sobjects:%.s=${OUT}/$(mod).%.o) +tool: $(tools:%.exe.c=${OUT}/$(mod).%) \ + ${OUT}/libk.a + +def: $(headers:%=${OUT}/k/%) + +dbg: + @echo src = $(src) + @echo tools = $(tools) + @echo TARGET = ${TARGET} + @echo cobjects = $(cobjects) + @echo sobjects = $(sobjects) + @echo headers = $(headers) + @echo m-comp = $(m-comp) + @echo m-env = $(m-env) "$(m-env:%=-D%)" + @echo mod = $(mod) + +${OUT}/k/%.h: %.h.m + $(m-comp) $< > $@ + +.PRECIOUS: ${TMP}/$(mod).% +${TMP}/$(mod).%: %.m ${TMP} + $(m-comp) $< > $@ + +${OUT}/$(mod).%.o: ${TMP}/$(mod).%.c + $(CC) $(cflags) -c $< -o $@ + +${OUT}/$(mod).%.o: %.c $(bare).h + $(CC) $(cflags) -c $< -o $@ + +${OUT}/k/%.h: %.h + cp $< $@ + +${OUT}/$(mod).%: %.exe.c + $(CC) $(cflags) $< ${OUT}/libk.a -o $@ + +${TMP}: + mkdir -p ${TMP} + +#- assembly +# compiling the assembly code will be faster but a lot more +# complex, given the nature of assembly and the large number of +# platforms targeted. we need to add build rules for every +# arch.OS[.bits] tuple; since this is a fairly repetetive task +# that requires ugly make rules, we're just going to use a +# function to generate these. + +# ${OUT} = ultimate build directory +# $(mod) = module name +# % = function name +# $(1) = arch tuple +arch = ${OUT}/$(mod).%.$(1).o: $2%.$(1).s +# invoke with $(call arch,tuple). do not +# put spaces between either term though! + +ifeq ($(debug),yes) +yasm-flags = -gdwarf2 +endif + +yasm = yasm $(yasm-flags) -f$1 -i${TMP} $< -o $@ + +#-- linux +# linux uses the ELF{32,64} binary format, and generating these +# from yasm is trivial. linux only supports one ABI per format, +# at least with ELF, so that's all we need to do. + + +$(call arch,x86.lin.32,) + $(call yasm,elf32) + +$(call arch,x86.lin.64,) + $(call yasm,elf64) + +$(call arch,x86.lin.32,${TMP}/$(mod).) + $(call yasm,elf32) + +$(call arch,x86.lin.64,${TMP}/$(mod).) + $(call yasm,elf64) + +#-- freebsd +# the freebsd ABI is different, so it will require different code +# (though there might be ways to minimize that). freebsd uses the +# same binary format as Linux (though it also supports a.out and +# COFF) but because freebsd can interpret multiple different ABIs +# the object files need to be "branded" with the correct one +# using the tool brandelf (`brandelf -t [ABI]`) + +$(call arch,x86.fbsd.32,) + $(call yasm,elf32) + brandelf -t FreeBSD $@ + +$(call arch,x86.fbsd.64,) + $(call yasm,elf64) + brandelf -t FreeBSD $@ + +$(call arch,x86.fbsd.32,${TMP}/$(mod).) + $(call yasm,elf32) + brandelf -t FreeBSD $@ + +$(call arch,x86.fbsd.64,${TMP}/$(mod).) + $(call yasm,elf64) + brandelf -t FreeBSD $@ Index: libk.md ================================================================== --- libk.md +++ libk.md @@ -14,11 +14,11 @@ libk aims to offer a better, safer, and most importantly, less unpleasant foundation for modern code in C or any other language. it also aims to be much smaller, simpler, and faster than glibc to build so that there's no arduous bootstrapping process for new architectures. currently, the only dependency on libc in any form is `arch/typesize.c`, a small binary tool which uses libc IO routines to print type information it calculates; however, this could also be augmented to use POISX IO routines, or even potentially libk IO routines to remove any external dependency at all -- the work would be nontrivial, but fully feasible. further, the file it creates can also _in extremis_ be created by hand. the final compiled libc binaries and headers do not depend on or reference libc in any way; typesize is only a makedepend. -## goals +# goals libk's goals are far-reaching, and suggestions are welcome. note however that libk is *not* intended to be a kitchen-sink library like libiberty. it's meant to do one thing, and to it well: to provide an easy- and pleasant-to-use foundation for modern open source projects. below is a list of some of the project's major goals. 1. **IO.** libc's basic input/output mechanisms are dreadful, built at entirely the wrong level of abstraction. libk is intended to make many more primitives available to the user, and offer a sliding scale of abstraction so libk is suitable for a wide range of needs. 2. **file manipulation.** libc's file manipulation primitives are a relic of a bygone age and in dire need of upgrading. @@ -29,11 +29,11 @@ 7. **tooling.** libk is intended as more than just a library. it's also intended to work with some basic tooling to automate tasks that current binary tooling is inadequate for -- for instance, embedding binary data into a program binary. (see module [kgraft](kgraft)) 8. **modularity.** libk is not part of the C specification and it isn't always going to be practical for developers to expect the entire library to be present on the end-user's computer. so libk is designed to be usable in many different ways -- as a traditional library, as a static library, in full form or with only components needed by the developer, to be distributed either on its own or as part of a binary. 9. **compatibility.** code that links against libk should be able to compile and run on any operating system. in the ideal case (Linux or FreeBSD) it will be able to do so without touching any other system libraries; for less ideal environments like Windows, libk will when necessary abstract over system libraries or libc itself. 10. **sane error-handling.** every time you type `errno` god murders a puppy. -## dependencies +# dependencies libk is designed to be as portable and depedency-free as possible. ideally, it will be possible to compile code against libk using nothing but libk itself. compiling libk is also designed to be as easy as possible. it has only two external dependencies, the macro processor [m4], needed for compile-time header generation, and the [GNU make] utility, whose advanced features are needed to perform the relatively complex task of building all of libk from the ground up. @@ -40,11 +40,11 @@ [m4]: http://www.gnu.org/software/m4 [GNU make]: http://www.gnu.org/software/make a different macro processor, gpp, was used in early versions of libk, however, it was so obscure and took so much overly fragile infrastructure to make it work that the cleaner syntax just wasn't worth it; i've since deleted the gpp infra and ported the macro files to m4. -## naming conventions +# naming conventions one of the most frustrating things about libc is its complete and total *lack* of a naming convention. in C, every function and global is injected into a single global namespace, including macros. this means that every libc header you include scatters words all over that namespace, potentially clobbering your function with a macro! libk is designed to fix this (in hindsight) glaring error. @@ -63,19 +63,20 @@ 1. the possible values of enumeration types are always preceded by the name of the enumeration type and an underscore. for instance, the enum `ksalloc` has a value named `ksalloc_static`. **exception:** an enum named `_kind`, where `` is a struct type, may simply use the prefix `_`. 2. macros begin with the uppercase letter `K` -- e.g. `Kmacro`. macros that can be defined by the user to alter the behavior of the api should begin with `KF` if they are on/off flags, or `KV` otherwise. 3. capital letters are only used in macro prefixes. 4. low-level function names are prefixed with the API they call into. for example, the function that performs the POSIX syscall `write` is named `kio_posix_fd_write`. a wrapper around the Windows function `CreateProcess()` might be called `kproc_win_createprocess`. -### atoms +## atoms libk uses the concept of "atoms" (small, regular strings of text) to standardize common references, such as operating systems or processor architectures. -#### operating systems +### operating systems these atoms will be used to reference operating systems. * Linux: `lin` + 1. aaaa * Haiku: `hai` * Android: `and` * FreeBSD: `fbsd` * NetBSD: `nbsd` * OpenBSD: `obsd` @@ -83,38 +84,51 @@ * MS-DOS: `dos` * FreeDOS: `fdos` * Windows: `win` * Windows MinGW: `mgw` -#### file extensions +### file extensions * C function implementations: `*.c` * C module headers: `*.h` * ancillary C headers: `*.inc.h` * assembly code: `*.s` -#### arches +### arches these atoms will be used to reference particular system architectures. these will mostly be used in the filenames of assembly code. + * Intel/AMD x86: `x86` + * ARM: `arm` (aarch64 is specified by `os=arm bits=64`) + * MIPS: `mips` + * Itanium: `ia64` (no bits) + * PowerPC: `ppc` -## macros +# localization + +libk does not interface, respect, or wrap system locale APIs in any way. localization, for the most part, is the responsibility of the developer. this is necessary in order to prevent hidden state from accreting, which lets us make certain invariant guarantees about library behavior that can prevent highly confusing bugs or potentially even have security implications. + +this is not to say that libk supports only one language, one calendar, and one culture. mechanisms will exist to produce localized output; however, they require the developer to explicitly pass localization flags and state. that is to say, they are stateless and opt-in only. the user changing an environment variable will never cause, e.g., decimal points to turn into commas unless the coder explicitly specified that behavior. + +libk uses UTF8 exclusively. it has no concept of codepages or non-unicode charsets. + +# macros libk will not in any circumstance use macros to encode magic numbers, instead using typedef'd enums. all libk macros begin with the uppercase letter `K` -- e.g. `Kmacro`. macros that can be defined by the user to alter the behavior of the api should begin with `KF` if they are on/off flags, or `KV` otherwise. **macros should only be defined by the libk headers if the flag `KFclean` is *not* defined at the time of inclusion.** include guards take the form of the bare module name prefixed by `KI`. so to test if `k/term.h` has been included, you could write `#ifdef KIterm`. -## languages +# languages -libk uses only three languages: C (\*.c, \*.h), yasm (\*.s), and make (makefile). +libk uses only five widely-used and standardized computer languages: C (\*.c, \*.h), yasm (\*.s), awk (\*.awk), commonmark (\*.md), and bash (\*.sh). further languages may not be introduced into the project without explicit advance approval of the maintainer herself. other assemblers will probably be necessary for the more exotic targets, however. -## repository structure +# repository structure libk uses a strict directory structure for code, and deviations from this structure will not be tolerated without extremely good reason. -total segregation is maintained between source code, temporary files, and output objects. source is found in module directories (`k*/`). the destination for temporary files and output objects are retargetable via the `make` parameters `TMP= OUT=`, but default to `tmp/` and `out/`, which are excluded from repo with fossil's `ignore-glob` setting. +total segregation is maintained between source code, temporary files, and output objects. source is found in module directories (`k*/`). the destination for temporary files and output objects are retargetable via the environment variables `gen= out=`, but default to `gen/` and `out/`, which are excluded from repo with fossil's `ignore-glob` settingapproval of the maintainer herself. all libk code is dispersed into modules: `kcore` for internals, `kio` for I/O, `kgraft` for binary packing, etc. each module has a folder in the root directory. (libk does not have submodules.) inside each module's directory should be a header with the same name as the module (see **naming conventions** above). each function should be kept in a separate file within its module's directory. the file's name should consist of the dot-separated fields [name, class, "c"] for C sources, or [name, class, arch, OS, bits, format, "s"] for assembly sources, where "name" is the name of the function without the module prefix and "class" is `rt` if the file is part of the libk runtime, or `fn` otherwise. this distinction is necessary because while the static library `libk.a` can include runtime objects, the shared library `libk.so` cannot. examples: @@ -122,29 +136,31 @@ * a runtime assembly file called `boot` in the module `kcore` for x86-64 linux would be named `kcore/boot.rt.x86.lin.64.s` * the 32-bit x86 haiku version of a function called `kiowrite` defined in assembly would be named `kio/write.fn.x86.hai.32.s`. each module should have a header named the same thing as the module except without the `k` prefix. (e.g. the header for `kio` is `kio/io.h`) located in its folder. this is the header that the end-user will be importing, and should handle any user-defined flags to present the API the user has selected. -each module directory should contain a makefile that can build that module. see **makefiles** below. all makefiles should be named `makefile` (**not** `Makefile`). - each module should contain a markdown file. this file's name should be the name of the parent directory suffixed with `.md`; for instance, `kterm` should contain the file `kterm/kterm.md`. this file should document the module as thoroughly as possible each module may contain any number of files of the name `*.exe.c`. this files will be treated as *tools* by the build system and compiled as executables, rather than libraries. they should be compiled to `out/$module.$tool` the repository root and each module may also contain the directory `misc`. this directory may be used to store miscellaneous data such as ABI references, developer discussions, and roadmaps. if the `misc` directory is deleted, this must not affect the library or build system's function in any way - that is, nothing outside a `misc` folder may reference a `misc` folder or anything inside it, including documentation. the `misc` directory should be removed when its contents are no longer needed. in most cases, the repository wiki and forum should be used instead of the `misc` folder. the folder `arch` in the root of the repository contains syscall tables and ABI implementations for various architectures. -## makefiles +## build sysem -libk uses `make` as its build system. makefiles should be handwritten. there will be one global makefile in the root of the repository, and one makefile for each module. +libk uses a very simple build system. the entire project is built with the `build.sh` script in the project root. `build.sh` need not be modified so long as all you're adding is functions, runtime stubs, headers, documentation files, or macro files in line with the standard naming convention. it will need to be modified to add or remove modules. it does not track dependencies, recompiling the entire project in one fell swoop. while in theory this could be slow and inefficient, in practice, it's not meaningfully slower on the average run than the old make-based system was. -each rule should be prefixed with ${OUT}, to allow retargeting of the build-dir with the OUT environment variable. this is particularly important since the makefiles chain. +the shell-based build system was chosen for a number of reason. firstly, libk originally used a GNU make-based build system, but this was unwieldy and unreliably - make simply does not have the necessary capabilities to build a project of this nature. the original build system relied heavily on recursion, which is impossible to use while preserving idempotency. multithreaded building was likewise impossible. -the rest is TBD. +relying on make also had a number of subtler downsides. GNU make's capacities vary significantly across versions, and not all users will necessarily have access to the correct version in their repos. even a version as recent as make 4.1 couldn't build a project that build without issue in 4.2. given that libk is explicitly intended to be widely portable, this variance was alarming. make is also very indirect - it's a pain in the ass to tell it what to do sometimes, and it's well nigh on impossible to decipher the intricate way in which a sufficiently complex set of makefiles interlocks. this is both user- and developer-hostile. by contrast, a simple, linear build script with clearly delineated functions makes the build process much easier to understand, and therefore to tweak should a user need to modify some aspect of the process to compile `libk` on her system. -## design principles +finally, make simply has a smaller install base than `bash`. with the `build.sh` build system, more people can successfully build libk with less effort. + +any time you make a change to the build script, always specify precisely what changed in your commit log and what affects this might have on the surrounding code. be sure to comment any new code as thoroughly as you can. the goal is that anyone who is familiar with bash should be able to learn the build process simply by reading `build.sh`. + +# design principles there are four overriding principles that guide the design of libk. 1. it should be easy to write code that uses it. 2. it should be easy to read code that uses it. @@ -170,21 +186,26 @@ this makes code much more legible and has the added benefit of making the definitions easier to expand at a later date if new functionality is needed without breaking the API or ABI. ## build process -libk has a number of targets. all files generated by a `make` invocation will be stored in the folder "out" at the root of the repository. this directory may be deleted entirely to clean the repository. +to build libk, you must invoke `build.sh` with the proper parameters. at minimum you must set the following environment variables: -**defs** will create the directory `out/k/` and populate it with module header files. the `k/` directory shall be suitable to copy to `/usr/include` or similar. these header files will copied by building the `${OUT}/$(module).h` target of each module's makefile. + * `os={atom}` - an atom representing the operating system you are building libk for + * `arch={atom}` - an atom representing the processor architecture you are building libk for + * `bits={atom}` - if your processor has multiple variants with different word lengths (such as x86-32 vs. x86-64), specify the word length in this variable; otherwise, leave it unset. -**libk.so** will build the dynamically linked form of libk, according to the build variables set +further optional variables may be set to control the build process and determine what targets it produces. + * `library=static {static|shared|both}` - this variable controls whether the build process will produce `libk.a`, `libk.so`, or both. + * `out=out {path}` - an alternate path to store build artifacts in + * `gen=gen {path}` - an alternate path to store generated source in + * `cc= {executable}` - the compiler to compile C sources with + * `m4= {executable}` - the m4 binary to compile the macro sources with + * `asm= {executable}` - the assembler to assemble the assembly listings with. it must take Intel-syntax input and handle nasm-style macros. only `yasm` and `nasm` are likely to be viable. -**libk.a** will build the statically linked form of libk, according to the build variables set - -**tool** will build the executables used for modules such as `kgraft`. - -**clean** will delete the `tmp` and `out` trees. +two other shell scripts complete the build system: + * `install.sh` - installs compiled libraries, objects, documentation, and headers into the appropriate directories. ## authors so far, this is a one-woman show. contributions are welcome however. @@ -192,11 +213,11 @@ ## caveats the main coder, lexi hale, is first and foremost a writer, not a coder. this is a side-project of hers and will remain so unless it picks up a significant amount of attention. -while PRs adding support for Windows, OS X, and other operating systems will be gratefully accepted, the maintainer is a Linux and FreeBSD developer, will not be writing such support infrastructure herself, and has limited ability to vet code for those platforms. +while MRs adding support for Windows, OS X, and other operating systems will be gratefully accepted, the maintainer is a Linux and FreeBSD developer, will not be writing such support infrastructure herself, and has limited ability even to vet code for those platforms. ## license libk is released under the terms of the [GNU AGPLv3](LICENSE). contributors do not relinquish ownership of the code they contribute, but agree to release it under the same terms as the overall project license. DELETED makefile Index: makefile ================================================================== --- makefile +++ makefile @@ -1,157 +0,0 @@ -export OUT = $(PWD)/out - -# TODO: calculate these using $(MAKE_HOST) -export ARCH = x86 -export OS = lin -export BITS = 64 -export ROOT = $(PWD) -export TMP = $(PWD)/gen - -export BUILD = $(shell global/build-id.sh) $(build-host) - -ifneq ($(BITS),) - export TARGET = $(ARCH).$(OS).$(BITS) -else - export TARGET = $(ARCH).$(OS) -endif - -export m4 = m4 - -include makerule - -moddirs := $(wildcard k*) -binaries := $(wildcard k*/*.exe.c) -functions := $(wildcard k*/*.fn.c) -assemblies := $(wildcard k*/*.fn.$(TARGET).s) -binmods := $(sort $(dir $(binaries))) - -# i'm sorry -collect = $(strip $(foreach dir,$(moddirs),$(wildcard $(dir)/*.$1))) -transform = $(strip $(foreach dir,$(moddirs),$(patsubst $(dir)/%.$1,$(subst @,$(dir),$2),$(wildcard $(dir)/*.$1)))) - -m-hdr-macs := $(call collect,h.m) -m-c-src-macs := $(call collect,c.m) -m-s-src-macs := $(call collect,$(TARGET).s.m) - -m-c-sources := $(call transform,c.m,$(TMP)/@.%.c) -m-s-sources := $(call transform,$(TARGET).s.m,$(TMP)/@.%.$(TARGET).s) - -m-headers := $(call transform,h.m,$(OUT)/k/%.h) -m-c-objects := $(call transform,c.m,$(OUT)/@.%.o) -m-s-objects := $(call transform,$(TARGET).s.m,$(OUT)/@.%.$(TARGET).o) - -fnobjects := $(call transform,fn.c,$(OUT)/@.%.fn.o) \ - $(call transform,fn.c.m,$(OUT)/@.%.fn.o) \ - $(call transform,fn.$(TARGET).s,$(OUT)/@.%.fn.$(TARGET).o) \ - $(call transform,fn.$(TARGET).s.m,$(OUT)/@.%.fn.$(TARGET).o) - -rtobjects := $(call transform,rt.c,$(OUT)/@.%.rt.o) \ - $(call transform,rt.c.m,$(OUT)/@.%.rt.o) \ - $(call transform,rt.$(TARGET).s,$(OUT)/@.%.rt.$(TARGET).o) \ - $(call transform,rt.$(TARGET).s.m,$(OUT)/@.%.rt.$(TARGET).o) - -docs := $(wildcard k*/*.md) -docs-out := $(patsubst %.md,$(OUT)/doc/man/%.4.gz,$(notdir $(docs))) -objects := $(fnobjects) $(rtobjects) - -prefix ?= /usr -d-header = $(prefix)/include -d-lib = $(prefix)/lib -d-share = $(prefix)/share - -unix-oses = lin fbsd dar and -posix-oses = lin fbsd dar and hai mgw cyg - -ifeq ($(findstring $(OS),$(unix-oses)),$(OS)) - export UNIX = yes - export POSIX = yes -else - export UNIX = no - ifeq ($(findstring $(OS),$(posix-oses)),$(OS)) - export POSIX = yes - else - export POSIX = no - endif -endif - -# include libgcc.a in gcc builds, just in case -ifeq ($(CC),gcc) - export COMPLIB = -lgcc -endif - -all: $(OUT) defs obj tool lib.static $(OUT)/boot.o lib.shared -lib.static: defs obj $(OUT)/libk.a -lib.shared: defs obj $(OUT)/libk.so -obj: $(moddirs:%=%.obj) -defs: $(moddirs:%=%.def) -tool: $(OUT)/boot.o $(OUT)/libk.a $(binmods:%=%.tool) -doc: $(docs-out) -clean: - rm -rf $(TMP) $(OUT) - -install: all - install -d $(header-dir)/k $(share-dir)/k -o root -g wheel -m 0755 - install $(OUT)/k/* $(header-dir)/k/ -o root -g wheel -m 0644 - install $(OUT)/libk.a $(OUT)/libk.so \ - $(lib-dir) -o root -g wheel -m 0644 - install $(OUT)/boot.o $(share-dir)/k/boot.o -o root -g wheel -m 0644 - -uninstall: $(header-dir)/k $(lib-dir)/k - rm -rf $^ - -lists = BUILD moddirs functions assemblies fnobjects rtobjects binaries binmods POSIX docs docs-out -dbg: - @echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))") - -%.obj: %/makefile $(OUT)/internal.ident.o $(OUT) - cd $* && $(MAKE) obj - -%.tool: %/makefile $(OUT) - cd $* && $(MAKE) tool - -%.dbg: %/makefile $(OUT) - cd $* && $(MAKE) dbg - -%.def: %/makefile $(TMP)/typesize.def \ - $(OUT)/k/internal.egroup.h \ - $(TMP)/system_calls.h \ - $(TMP)/system_calls.s \ - $(TMP)/error_table.h \ - $(OUT) $(OUT)/k - cd $* && $(MAKE) def - -.PRECIOUS: $(TMP)/system_calls.% -$(TMP)/system_calls.%: arch/makefile - $(MAKE) -C arch $@ - -$(TMP)/error_table.h: arch/makefile - $(MAKE) -C arch $@ - -$(TMP)/typesize.def: arch/makefile $(TMP) - $(MAKE) -C arch $@ - -$(OUT)/libk.so: $(fnobjects) - ld -shared $(COMPLIB) -o $@ $^ - @# $(CC) -shared -fPIC -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o - -$(OUT)/boot.o: $(rtobjects) - ld -r $^ -o $(OUT)/boot.o - -$(OUT)/libk.a: $(fnobjects) $(rtobjects) - @# using `ar rc` and ranlib here instead of - @# `ar rcs` in case `ar` isn't the GNU version - ar rc $@ $^ - ranlib $@ - -$(OUT)/man/doc: - mkdir -p $@ - -$(OUT)/k/internal.egroup.h: global/modules global/genconds.awk $(OUT)/k - awk -f global/genconds.awk <$< >$@ -$(TMP)/internal.ident.c: global/modules global/genident.awk $(OUT)/k/internal.egroup.h $(TMP) - awk -f global/genident.awk <$< >$@ -$(OUT)/%.o: $(TMP)/%.c $(OUT) - $(CC) $(cflags) -c $< -o $@ - -$(OUT) $(OUT)/k $(TMP): - mkdir -p $@ DELETED makerule Index: makerule ================================================================== --- makerule +++ makerule @@ -1,29 +0,0 @@ -#- makerule -# this file contains definitions shared between modmake and -# the top-leve makefile -# vim: ft=make - -ARCH ?= ${ARCH} -BITS ?= ${BITS} -OS ?= ${OS} - -POSIX ?= ${POSIX} -UNIX ?= ${UNIX} - -ROOT ?= ${ROOT} -TMP ?= ${TMP} -OUT ?= ${OUT} - -m4 ?= ${m4} - -cflags = -std=c11 -isystem $(OUT) -isystem $(TMP) -isystem $(ROOT)/arch -fPIC -nostdlib $(COMPLIB) -L$(OUT) - -m-env = atom_target_arch=$(ARCH) -m-env += atom_target_os=$(OS) -ifneq ($(BITS),) #!!! ifdef does NOT work with environment variables - m-env += atom_target_bits=$(BITS) -endif -m-env += target_posix=$(POSIX) -m-env += target_unix=$(UNIX) - -m-comp = $(m4) $(m-env:%=-D%) DELETED modmake Index: modmake ================================================================== --- modmake +++ modmake @@ -1,120 +0,0 @@ -#- modmake -# this is the master makefile that controls the building of each -# libk module. it is included from each k*/makefile. -# vim: ft=make - -include ../makerule - -mod = $(notdir $(PWD)) -src = $(wildcard *.c) $(wildcard *.s) $(filter-out %.h,$(patsubst %.m,%,$(wildcard *.m))) -bare = $(mod:k%=%) -headers = $(wildcard *.h) $(gen-headers) $(patsubst %.m,%,$(wildcard *.h.m)) - -tools = $(filter %.exe.c, $(src)) -nontools = $(filter-out %.exe.c, $(src)) -cobjects = $(filter %.c, $(nontools)) -sobjects = $(filter %.${TARGET}.s, $(nontools)) - -obj: $(cobjects:%.c=${OUT}/$(mod).%.o) \ - $(sobjects:%.s=${OUT}/$(mod).%.o) -tool: $(tools:%.exe.c=${OUT}/$(mod).%) \ - ${OUT}/libk.a - -def: $(headers:%=${OUT}/k/%) - -dbg: - @echo src = $(src) - @echo tools = $(tools) - @echo TARGET = ${TARGET} - @echo cobjects = $(cobjects) - @echo sobjects = $(sobjects) - @echo headers = $(headers) - @echo m-comp = $(m-comp) - @echo m-env = $(m-env) "$(m-env:%=-D%)" - @echo mod = $(mod) - -${OUT}/k/%.h: %.h.m - $(m-comp) $< > $@ - -.PRECIOUS: ${TMP}/$(mod).% -${TMP}/$(mod).%: %.m ${TMP} - $(m-comp) $< > $@ - -${OUT}/$(mod).%.o: ${TMP}/$(mod).%.c - $(CC) $(cflags) -c $< -o $@ - -${OUT}/$(mod).%.o: %.c $(bare).h - $(CC) $(cflags) -c $< -o $@ - -${OUT}/k/%.h: %.h - cp $< $@ - -${OUT}/$(mod).%: %.exe.c - $(CC) $(cflags) $< ${OUT}/libk.a -o $@ - -${TMP}: - mkdir -p ${TMP} - -#- assembly -# compiling the assembly code will be faster but a lot more -# complex, given the nature of assembly and the large number of -# platforms targeted. we need to add build rules for every -# arch.OS[.bits] tuple; since this is a fairly repetetive task -# that requires ugly make rules, we're just going to use a -# function to generate these. - -# ${OUT} = ultimate build directory -# $(mod) = module name -# % = function name -# $(1) = arch tuple -arch = ${OUT}/$(mod).%.$(1).o: $2%.$(1).s -# invoke with $(call arch,tuple). do not -# put spaces between either term though! - -ifeq ($(debug),yes) -yasm-flags = -gdwarf2 -endif - -yasm = yasm $(yasm-flags) -f$1 -i${TMP} $< -o $@ - -#-- linux -# linux uses the ELF{32,64} binary format, and generating these -# from yasm is trivial. linux only supports one ABI per format, -# at least with ELF, so that's all we need to do. - - -$(call arch,x86.lin.32,) - $(call yasm,elf32) - -$(call arch,x86.lin.64,) - $(call yasm,elf64) - -$(call arch,x86.lin.32,${TMP}/$(mod).) - $(call yasm,elf32) - -$(call arch,x86.lin.64,${TMP}/$(mod).) - $(call yasm,elf64) - -#-- freebsd -# the freebsd ABI is different, so it will require different code -# (though there might be ways to minimize that). freebsd uses the -# same binary format as Linux (though it also supports a.out and -# COFF) but because freebsd can interpret multiple different ABIs -# the object files need to be "branded" with the correct one -# using the tool brandelf (`brandelf -t [ABI]`) - -$(call arch,x86.fbsd.32,) - $(call yasm,elf32) - brandelf -t FreeBSD $@ - -$(call arch,x86.fbsd.64,) - $(call yasm,elf64) - brandelf -t FreeBSD $@ - -$(call arch,x86.fbsd.32,${TMP}/$(mod).) - $(call yasm,elf32) - brandelf -t FreeBSD $@ - -$(call arch,x86.fbsd.64,${TMP}/$(mod).) - $(call yasm,elf64) - brandelf -t FreeBSD $@