libk  Check-in [b5f6f19923]

Overview
Comment:updates, begin putting together error-handling mechanism
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: b5f6f199234d0ec07678fe8e9a8b102e289e1266c3e54b934fce5a73c38537e0
User & Date: lexi on 2019-08-19 01:46:21
Other Links: manifest | tags
Context
2019-08-19
02:04
add makerule, add include mode to typesize check-in: 8b84a67d85 user: lexi tags: trunk
01:46
updates, begin putting together error-handling mechanism check-in: b5f6f19923 user: lexi tags: trunk
2019-08-18
18:29
add error reporting to kiosend() check-in: b2f129d7b9 user: lexi tags: trunk
Changes

Modified arch/x86.lin.32.s from [d3081be9ee] to [a7ffc6f8bf].

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
;; abi definition file for x86 linux 32-bit
; vim: ft=nasm

; syscall32 numbers - syscall table must be created first!
%include "system_calls.s"

; syscall32 registers
%define sys.reg.n 6
%define sys.reg.0 eax
%define sys.reg.1 ebx
%define sys.reg.2 ecx
%define sys.reg.3 edx
%define sys.reg.4 esi
%define sys.reg.5 edi

%macro sys 1-6
	%assign i 0
	%rep %0
		mov sys.reg. %+ i, %1 ; i'm actually shocked this worked
		%rotate 1
		%assign i i+1
	%endrep 
	syscall
%endmacro

%define sys.call int 0x80 ; sysenter is allegedly the
  ; politically correct option but it does not actually
  ; appear to work without a whole lot of extra bullshit

; todo: learn vdsos
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Added global/build-id.sh version [5d0ff4e06b].



























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#!/usr/bin/env sh
. global/common.sh

origin=1566169297
now=$(date +%s)
delta=$(expr $now - $origin)


if test "$1" = "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
		hash="$HASH"
	elif has sha1; then
		hash=sha1
	elif has sha1sum; then
		hash=sha1sum
	else
		say "cannot find a hashing function; privacy mode cannot be used"
		exit 1
	fi

	h=$(printf "%x%s" "$delta" "$(uname -a)" | $hash)
	echo ${h:1:7}
else
	printf "%x:%s" $delta $(uname -n)
fi

Added global/common.sh version [4d96b9fc79].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
me=$0
say() { echo >&2 "($me) $1";      }
has() { which $1 >/dev/null 2>&1; return $?; }
check() {
	var=$1
	test "${!var}" == "" || return 0
	say "we were not able to detect a default value for the configuration variable \$$var. please set this variable to $2 and try again."
	exit 1
}

Added global/emit-manpage.sh version [199ffb3202].



































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#!/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/genconds.awk version [d4ceed024e].







































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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/genident.awk version [730afca5a3].









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BEGIN {
	defs = ""
	FS = ":"
	ORS = ""
	print "#include <k/internal.egroup.h>\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 global/modules version [4da066f235].

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kbuild:long:kbuild:build tool
kconf:long:kconf:config parser
kcli:long:kcli:CLI utilities
kcore:short:kc:core definitions and routines
kdb:long:kdb:database
kdbg:long:kdbg:debug toolkit
kfile:short:kf:file control
kgraft:long:kgraft:grafting tool
kio:short:kio:input/output routines
kmem:short:km:memory management routines
kmsg:long:kmsg:IPC routines
knet:long:knet:network routines
knum:short:kn:math and number tools
kproc:short:kp:process control
kstr:short:ks:string toolkit
kterm:short:kt:terminal control facility

Deleted kcli/kcli.md version [09b7990027].

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# kcli
**kcli** is a module that implements common routines used by command-line utilities, such as option parsing, usage display, and more.

## functions

### kcli_usage(kcli_set, kiochan)
kcli_usage() takes a `kcli_set` and prints a succinct usage summary to a [kiochan](../kio/kio.md).

## types

### struct kcli_set
`kcli_set` is a struct containing information about your program, such as its name, a synopsis of its function, a pointer to `argv`, and a list of `kcli_opt`s.

 * `const char* name` - program name (if null, will be determined from argv instead)
 * `size_t argc` - the number of arguments in the `argv` array.
 * `const char** argv` - the `argv` pointer passed to the `entry` function, representing the command-line arguments passed to the program.
 * `const char* desc` - program description
 * `const kcli_param* params` - a list of options expected by the program.
 * `size_t paramc` - the number of params in the list to process.
 * `const kcli_opt* opts` - a list of options expected by the program.
 * `size_t optc` - the number of options in the list to process.

a kcli_set might be used like so:

    #include <k/core.h>
    #include <k/io.h>
    #include <k/cli.h>
    stat entry(kenv e) {
    	kcli_flag aardvark;
    	kcli_flag zebra;
    	char* user;
    	char* password;
		long age;
		kcli_param params[] = {
    		{ "user", kcli_param_string, kcli_class_required,
    		  &user, "the user to log in as" }
			  // or Kcli_param(user,string,required,"the user to log in as"),

			{ "age", kcli_param_dec, kcli_class_optional,
    		  &age, "the age of the user" }
			  // or Kcli_param(age,dec,optional,"the age of the user"),
		};
    	kcli_opt options[] = {
    		{ 'a', "aardvark", kcli_opt_flag, &aardvark,
    		  "a nocturnal burrowing mammal" },
			  // or Kcli_opt(aardvark, 'a', flag, "a nocturnal burrowing mammal")
    		{ 'z', "zebra", kcli_opt_flag, &zebra,
    		  "a striped equine" },
    		{ 'p', "password", kcli_opt_string, &password,
    		  "the password to log in with" }
    	};
    	kcli_set argset = {
    		"demo", e.argc, e.argv,
    		"a demonstration of the kcli_set type",
			params, Kmsz(params),
			options, Kmsz(options)
    	},
		size_t args_parsed = kcli_parse(&argset);
		if (args_parsed == 0) { kcli_usage(&me, e.err); return 1; }

		return 0;
	}

### struct kcli_opt
a `kcli_opt` is a representation of a command-line flag and its function. each option must have a unique `id` and/or a unique `name`.

 * `char id` - the short single-character form of the flag (or NUL for no short form)
 * `const char* name` - the long string form of the flag (or NULL for no long form)
 * `kcli_opt_kind kind` - enum that describes how the flag will function
 * `void* val` - a pointer to an appropriate type to store the return value in.
 * `const char* desc` - a description of the flag's purpose and function (or NULL for no description)

#### enum kcli_opt_kind

 * `kcli_opt_none` - flag is disabled and will not be shown in usage
 * `kcli_opt_string` - flag tells kcli to add a string to the list of expected parameters; appropriate string will be returned
 * `kcli_opt_oct` - flag tells kcli to add an octal number to the list of expected parameters
 * `kcli_opt_dec` - flag tells kcli to add a decimal number to the list of expected parameters
 * `kcli_opt_hex` - flag tells kcli to add a hexdecimal number to the list of expected parameters
 * `kcli_opt_flag` - flag is an option: will return `kcli_flag_on` if entered at least once, `kcli_flag_off` otherwise.
 * `kcli_opt_toggle` - flag toggles value on and off: will return `kcli_flag_on` if entered an odd number of times, `kcli_flag_off` otherwise.
 * `kcli_opt_accumulate` - flag increments a value every time it is entered; often used to implement `-v (--verbose)`-style options (e.g. `-vvvv` would return a value of `4`).
 * `kcli_opt_enum` - flag is one of a series of enumerated values, which will be matched against a table to yield the associated integer.

### struct kcli_param
`kcli_param` describes a parameter that may be passed to the program whether or not any flags are passed.

 * `const char* name` - a short name for the parameter
 * `kcli_param_kind kind` - the kind of parameter passed
 * `kcli_class class` - whether or not the parameter is optional
 * `void* val` - a pointer to an appropriate type of variable to fill
 * `const char* desc` - a description of the parameter's function

#### enum kcli_param_kind
 * `kcli_param_none` - parameter is disabled and will not be expected or accepted
 * `kcli_param_string` - parameter will not be parsed; a raw string will be returned
 * `kcli_param_oct` - parameter will be parsed as an octal number
 * `kcli_param_dec` - parameter will be parsed as a decimal number
 * `kcli_param_hex` - parameter will be parsed as a hexadecimal number

### enum kcli_class
 * `kcli_class_forbidden` - parameter may not be passed
 * `kcli_class_optional` - parameter may or may not be passed
 * `kcli_class_required` - parameter must be passed

### enum kcli_flag
results that an option of kind `kcli_opt_flag` can return.

 * `kcli_flag_off = 0` - flag is off
 * `kcli_flag_on = 1` - flag is on
 
## macros

### Kcli_param(field, kind, class, description)
a convenience macro for filling out parameter lists.

`Kcli_param(field,a,b,"description")` is transformed into:

    { "field", kcli_param_a, kcli_class_b, &field, "description" }

### Kcli_opt(field, kind, class, description)
a convenience macro for filling out option lists.

`Kcli_opt(name,'n',string,"description")` is transformed into:

    { 'n', "name", kcli_opt_string, &name, "description" }
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































Deleted kcli/makefile version [f0df06fe05].

1
include ../modmake
<


Modified kcore/core.h from [7135ae8006] to [632e354c90].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
37
38
39
40
41
42
43


44
45
46
47
48
49
50
...
142
143
144
145
146
147
148











149
150
151
152
153
154
typedef struct kenv {
	kiochan std;
	kiochan err;
	sz argc; char** argv;
	kvar* vars;
} kenv;


/* i'm really sorry okay */
typedef
#if (__STDC_VERSION__ >= 199901L)
	_Bool bool;
#endif
enum
#if !(__STDC_VERSION__ >= 199901L)
................................................................................
}
#if !(__STDC_VERSION__ >= 199901L)
	bool /* } bool ; */
#endif
;

#ifndef KFclean


#	if (__STDC_VERSION__ >= 199901L) ||\
	   (__cplusplus      >= 201103L)
#		define KVvm_args __VA_ARGS__
#		define KVvm_spec ...
#		define KFfeat_variadic_macro
#	else
#		define KVvm_args K_TEMP_M2QD52
................................................................................
#ifdef __cplusplus
	[[noreturn]] void kstop(stat_long code);
#elif __STDC_VERSION__ >= 201103L
	_Noreturn void kstop(stat_long code);
#else
	void kstop(stat_long code);
#endif












#ifdef __cplusplus
}
#endif

#endif







<







 







>
>







 







>
>
>
>
>
>
>
>
>
>
>






17
18
19
20
21
22
23

24
25
26
27
28
29
30
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
typedef struct kenv {
	kiochan std;
	kiochan err;
	sz argc; char** argv;
	kvar* vars;
} kenv;


/* i'm really sorry okay */
typedef
#if (__STDC_VERSION__ >= 199901L)
	_Bool bool;
#endif
enum
#if !(__STDC_VERSION__ >= 199901L)
................................................................................
}
#if !(__STDC_VERSION__ >= 199901L)
	bool /* } bool ; */
#endif
;

#ifndef KFclean
#	include <k/internal.egroup.h>
#	define Kokay(cond) (((cond) % kglobal_module_offset) == 0)
#	if (__STDC_VERSION__ >= 199901L) ||\
	   (__cplusplus      >= 201103L)
#		define KVvm_args __VA_ARGS__
#		define KVvm_spec ...
#		define KFfeat_variadic_macro
#	else
#		define KVvm_args K_TEMP_M2QD52
................................................................................
#ifdef __cplusplus
	[[noreturn]] void kstop(stat_long code);
#elif __STDC_VERSION__ >= 201103L
	_Noreturn void kstop(stat_long code);
#else
	void kstop(stat_long code);
#endif

typedef u16 kcond;
/* this will probably not need to be altered,
 * as libk sports a modest number of modules,
 * and there are few enough error conditions
 * in each  that 16-bit address space should
 * be more  than enough for the  foreseeable
 * future. however if that changes, altering
 * the  definition here will effect all  the
 * necessary changes throughout the library */
bool kokay(kcond);

#ifdef __cplusplus
}
#endif

#endif

Modified kcore/kcore.md from [a610cab74a] to [a74f6a9675].

1
2
3
4





5
6
7
8
9
10
11
12
13
14
15
..
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# kcore
**kcore** is the foundation for the rest of libk. it defines types and structs that are needed by every program, and provides the stub that launches a program's "entry" function. unlike the non-core modules, kcore definitions simply use the prefix `k-`.

## entry





when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform.

## types
kcore contains fixed-width integer types (in `<k/type.h>`). these types are present on every platform. if a platform has a type with a given bit length, it will be used, otherwise, the type will round to the largest available type (except `u8` and `s8`). if you need to be absolutely certain that a type is the appropriate bit length, use sizeof to check its length in a conditional or static assert, for instance `if (sizeof(u16) == 16 / kc_byte_bits)`.

 * `u8` - an unsigned 8-bit integer, or the smallest available unsigned type
 * `s8` - a signed 8-bit integer, or the smallest available signed type
 * `u16` - an unsigned 16-bit integer
 * `s16` - a signed 16-bit integer
 * `u32` - an unsigned 32-bit integer
 * `s32` - a signed 32-bit integer
................................................................................
 * `sbig` - the largest available signed integer type. note: ubig and sbig really are the *largest* possible integer types not just the largest native types - if your compiler has extensions for 128-bit types on your arch (as GCC and clang do on x86-64), ubig and sbig will be 128 bits long even if your system word length is less than 128. so only use ubig/sbig if you really, really mean it.
 * `ubyte` - the smallest available unsigned integer type besides \_Bool
 * `sbyte` - the smallest available signed integer type besides \_Bool
 * `stat` - the type of process return values expected by the platform (usually u8 on linux)
 * `sz` - a type large enough to cover a platform's entire address space (libc equivalent size_t)
 * `offset` - a type that can contain the difference between two pointers (libc equivalent ptrdiff_t)

## constants
in `<k/type.h>`, every type has an associated min and max constant, containing the smallest and largest value that type can hold on your system. these can be access by suffixing a type with `_min` and `_max`, respectively. min and max values of native types can be accessed with the `kc_[us]` prefix - for instance, the minimum value of `signed long` is `kc_slong_min`. (`long long` can be referenced as `llong`).

 * `byte_bits` - the bit length of ubyte, sbyte, and char; that is, the number of bits in the type `sizeof` measures things in terms of. `sizeof(type) * byte_bits` will always return the number of bits in a type.


### struct kenv
`kenv` is a struct that encompasses the environment the program was launched in.
 * `kiochan std` - a stereo IO channel for reading and writing to and from stdout.
 * `kiochan err` - a mono IO channel for writing to stderr.
 * `kvar* vars` - a pointer into the program's environment

### struct kvar
`kvar` is a struct that abstracts over platform environment variables.
 * `kstr name` - the name of an environment variable
 * `kstr val` - the value of an environment variable
 * `char* platform` - a pointer into the platform's underlying representation




## functions


### kstop()

`noreturn void kstop(stat)` terminates the program immediately, returning the specified integer to the OS as an exit status. the type of integer it takes depends on your operating system. consider using the `enum kbad` defines in `<k/magic.h>`, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (`<sysexit.h>`).

## definitions

kcore is the only module that defines any terms outside the k- namespace. the only terms it so defines are native C terms like `noreturn`, which are implemented as keywords in a reserved namespace (`_` followed by an uppercase letter; in this case, `_Noreturn`). macros are then defined in new headers for the "natural" version of the term in order to avoid breaking older code. examples of this technique are `<stdbool.h>` and `<stdnoreturn.h>`. since libk is designed for new, modern code, breaking old code isn't a concern, and we turn on all these new keywords as soon as you load `<k/core.h>`.

libk attempts to find the best possible definition and implementation for these various types and keywords, abstracting across different C versions and dialects. you can go ahead and use the normal version of the keywords (e.g. `noreturn`, `bool`) no matter what kind of compiler you're using and you're guaranteed that as long as you don't go fiddling with undefined- or implementation behavior, your code will behave the same every time. at worst, it may lack a few optimizations or warnings.

(the one minor exception is `null`, a new keyword which libk uses in preference to the ugly, hard-to-type C macro `NULL`.)

`bool` is implemented as a `_Bool` typedef if `_Bool` is available, and as an enum typedef otherwise. either way, and regardless of whether `KFclean` has been defined, booleans can be used and set to the values `true`, `false`, `yes`, or `no`. `yes` and `true` are synonyms, as are `false` and `no`.

### macros

if the flag `KFclean` has not been defined, kcore defines a number of macros to abstract over nonstandard C features. for instance, the `KA*` macros can be used to specify GNU/clang attributes without worrying about compatibility, as they'll automatically be blanked under an incompatible compiler. the KA series includes:

	* `KApure` - marks a "pure" function that changes no state and only takes purely numeric arguments, allowing the compiler to avoid repetetive calls to it or even evaluate it at runtime.
	* `KAnoreturn` - the GNU/clang-specific version of `noreturn`.
	* `KAunused` - acknowledges that a variable is unused and tells the compiler to shut up about it.
	* `KAinline` - forces the compiler to inline a function whether it likes it or not.
	* `KAflatten` - placed on a function, will force-inline all function calls *made by* that function — sort of like `KAinline` in reverse.
	* `KAformat()` - specifies that the function has printf-style syntax for error-checking purposes. worst hack in history.

if you wish to add more (there are like, hundreds) please consider making a merge request. however, the generic macro KA() is also available in the interim: `KA(unused)`.

however, unlike C++ attributes, GNU-style attributes can only be placed on a function declaration, *not* its definition.



|
>
>
>
>
>
|

|
|







 







|
<

<
>

|





|





>
>
>
|
>

|



|









|



|
|
|
|
|
|




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# kcore
**kcore** is the foundation for the rest of libk. it defines types and structs that are needed by every program, and provides the stub that launches a program's "entry" function. unlike the non-core modules, kcore definitions simply use the prefix `k-`.

# description
**kcore** contains the libk runtime and headers with important typedefs, structures and enumerations.

it also provides `boot.o`, the runtime file that must be statically linked into every libk program for it to be able to load. `boot.o` is incorporated in the static library `libk.a` but for architectural reasons cannot be exported from the dynamic library `libk.so`.

# program entry point
when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform. entry may have the return type `stat` or `stat_long`. on some operating systems, they are the same; on modern versions of UNIX, however, `stat_long` will allow you to return a 32-bit exit status. most shells will truncate such statuses, but they can be retrieved be the calling process with the appropriate syscall.

# core types
kcore contains fixed-width integer types (in `<k/type.h>`). these types are present on every platform, and are not prefixed. if a platform has a type with a given bit length, that type will be used will be used, otherwise, the type will round to the largest available type (except `u8` and `s8`, which round to the smallest). if you need to be absolutely certain that a type is the appropriate bit length, use sizeof to check its length in a conditional or static assert, for instance `if (sizeof(u16) == 16 / kc_byte_bits)`.

 * `u8` - an unsigned 8-bit integer, or the smallest available unsigned type
 * `s8` - a signed 8-bit integer, or the smallest available signed type
 * `u16` - an unsigned 16-bit integer
 * `s16` - a signed 16-bit integer
 * `u32` - an unsigned 32-bit integer
 * `s32` - a signed 32-bit integer
................................................................................
 * `sbig` - the largest available signed integer type. note: ubig and sbig really are the *largest* possible integer types not just the largest native types - if your compiler has extensions for 128-bit types on your arch (as GCC and clang do on x86-64), ubig and sbig will be 128 bits long even if your system word length is less than 128. so only use ubig/sbig if you really, really mean it.
 * `ubyte` - the smallest available unsigned integer type besides \_Bool
 * `sbyte` - the smallest available signed integer type besides \_Bool
 * `stat` - the type of process return values expected by the platform (usually u8 on linux)
 * `sz` - a type large enough to cover a platform's entire address space (libc equivalent size_t)
 * `offset` - a type that can contain the difference between two pointers (libc equivalent ptrdiff_t)

 * `byte_bits` - the bit length of ubyte, sbyte, and char; that is, the number of bits in the type `sizeof` measures things in terms of. `sizeof(type) * byte_bits` will always return the number of bits in a type.



**kcore** also defines a number of important structs.

## struct kenv
`kenv` is a struct that encompasses the environment the program was launched in.
 * `kiochan std` - a stereo IO channel for reading and writing to and from stdout.
 * `kiochan err` - a mono IO channel for writing to stderr.
 * `kvar* vars` - a pointer into the program's environment

## struct kvar
`kvar` is a struct that abstracts over platform environment variables.
 * `kstr name` - the name of an environment variable
 * `kstr val` - the value of an environment variable
 * `char* platform` - a pointer into the platform's underlying representation

# constants
in `<k/type.h>`, every type has an associated min and max constant, containing the smallest and largest value that type can hold on your system. these can be access by suffixing a type with `_min` and `_max`, respectively. min and max values of native types can be accessed with the `kc_[us]` prefix - for instance, the minimum value of `signed long` is `kc_slong_min`. (`long long` can be referenced as `llong`).

# functions
kcore contains only a handful of primitive functions, most of which provide the C runtime.

## kstop()

`noreturn void kstop(stat)` terminates the program immediately, returning the specified integer to the OS as an exit status. the type of integer it takes depends on your operating system. consider using the `enum kbad` defines in `<k/magic.h>`, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (`<sysexit.h>`).

# definitions

kcore is the only module that defines any terms outside the k- namespace. the only terms it so defines are native C terms like `noreturn`, which are implemented as keywords in a reserved namespace (`_` followed by an uppercase letter; in this case, `_Noreturn`). macros are then defined in new headers for the "natural" version of the term in order to avoid breaking older code. examples of this technique are `<stdbool.h>` and `<stdnoreturn.h>`. since libk is designed for new, modern code, breaking old code isn't a concern, and we turn on all these new keywords as soon as you load `<k/core.h>`.

libk attempts to find the best possible definition and implementation for these various types and keywords, abstracting across different C versions and dialects. you can go ahead and use the normal version of the keywords (e.g. `noreturn`, `bool`) no matter what kind of compiler you're using and you're guaranteed that as long as you don't go fiddling with undefined- or implementation behavior, your code will behave the same every time. at worst, it may lack a few optimizations or warnings.

(the one minor exception is `null`, a new keyword which libk uses in preference to the ugly, hard-to-type C macro `NULL`.)

`bool` is implemented as a `_Bool` typedef if `_Bool` is available, and as an enum typedef otherwise. either way, and regardless of whether `KFclean` has been defined, booleans can be used and set to the values `true`, `false`, `yes`, or `no`. `yes` and `true` are synonyms, as are `false` and `no`.

# macros

if the flag `KFclean` has not been defined, kcore defines a number of macros to abstract over nonstandard C features. for instance, the `KA*` macros can be used to specify GNU/clang attributes without worrying about compatibility, as they'll automatically be blanked under an incompatible compiler. the KA series includes:

  * `KApure` - marks a "pure" function that changes no state and only takes purely numeric arguments, allowing the compiler to avoid repetetive calls to it or even evaluate it at runtime.
  * `KAnoreturn` - the GNU/clang-specific version of `noreturn`.
  * `KAunused` - acknowledges that a variable is unused and tells the compiler to shut up about it.
  * `KAinline` - forces the compiler to inline a function whether it likes it or not.
  * `KAflatten` - placed on a function, will force-inline all function calls *made by* that function — sort of like `KAinline` in reverse.
  * `KAformat()` - specifies that the function has printf-style syntax for error-checking purposes. worst hack in history.

if you wish to add more (there are like, hundreds) please consider making a merge request. however, the generic macro KA() is also available in the interim: `KA(unused)`.

however, unlike C++ attributes, GNU-style attributes can only be placed on a function declaration, *not* its definition.

Modified kio/io.h from [d3b54028db] to [2374315a32].

45
46
47
48
49
50
51

52
53
54
55
56
57
58

59
60
61
62
63
64
65
typedef struct kiochan {
	kiostream in;
	  // text can be read from this stream
	kiostream out;
	  // text can be written to this stream
} kiochan;


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, // 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,







>






|
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
typedef struct kiochan {
	kiostream in;
	  // text can be read from this stream
	kiostream out;
	  // text can be written to this stream
} kiochan;

#include <k/internal.egroup.h>
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,

Deleted kmath/kmath.md version [4ac5812f7c].

1
2
# kmath
kmath contains libk's functions for dealing with numbers. kmath is intended to be much more consistent and generic than libc, with support for arbitrary bases, arbitrarily sized integers, and interfaces at varying levels of abstraction. (for instance, converting numbers to strings will not require invoking a string formatting routine or IO function; string formatting routines will invoke the same conversion functions that users can.) integers larger and smaller than processor types should also be supported, through functions over arrays and bitfield structs.
<
<




Deleted kmath/makefile version [f0df06fe05].

1
include ../modmake
<


Modified kmsg/kmsg.md from [1bf7781e05] to [9e287dbaef].

1

# kmsg


>
1
2
# kmsg
kmsg is libk's inter-process communication library.

Added knum/knum.md version [608a5247b2].





>
>
1
2
# knum
knum contains libk's functions for dealing with numbers. knum is intended to be much more consistent and generic than libc, with support for arbitrary bases, arbitrarily sized integers, and interfaces at varying levels of abstraction. (for instance, converting numbers to strings will not require invoking a string formatting routine or IO function; string formatting routines will invoke the same conversion functions that users can.) integers larger and smaller than processor types should also be supported, through functions over arrays and bitfield structs.

Added knum/makefile version [f0df06fe05].



>
1
include ../modmake

Modified kproc/kproc.md from [ca8b9fab82] to [4efe5a2b89].

1

# kproc


>
1
2
# kproc
kproc is libk's library for starting, handling, and controlling userspace processes.

Modified kstr/str.h from [a9e92726f6] to [0c79e2a160].

18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
} ksraw;

typedef struct ksmut {
	sz size;
	char* ptr;
} ksmut;


typedef enum kscond {
	kscond_ok,
	kscond_fail,
	kscond_unimplemented,
	kscond_nonnumeric,
} kscond;

enum ksconv {
	ksconv_default = 0,







>

|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
} ksraw;

typedef struct ksmut {
	sz size;
	char* ptr;
} ksmut;

#include <k/internal.egroup.h>
typedef enum kscond {
	kscond_ok = kscond_id,
	kscond_fail,
	kscond_unimplemented,
	kscond_nonnumeric,
} kscond;

enum ksconv {
	ksconv_default = 0,

Modified makefile from [ed3c61cbaa] to [0343c70b67].

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
55
56
57
58
59
60
61
62
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
...
129
130
131
132
133
134
135










136
137
# TODO: calculate these using $(MAKE_HOST)
export ARCH = x86
export OS = lin
export BITS = 64
export ROOT = $(PWD)
export TMP = $(PWD)/gen



ifneq ($(BITS),)
    export TARGET = $(ARCH).$(OS).$(BITS)
else
    export TARGET = $(ARCH).$(OS)
endif

export m4 = m4



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)



objects = $(fnobjects) $(rtobjects)

header-dir = /usr/include
lib-dir = /usr/lib




unix-oses = lin fbsd dar and
posix-oses = lin fbsd dar and hai mgw

ifeq ($(findstring $(OS),$(unix-oses)),$(OS))
    export UNIX = yes
    export POSIX = yes
else
    export UNIX = no
    ifeq ($(findstring $(OS),$(posix-oses)),$(OS))
................................................................................
	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) 

clean:
	rm -rf $(TMP) $(OUT)

install: all
	install -d $(header-dir)/k -o root -g wheel
	install $(OUT)/k/* $(header-dir)/k/ -o root -g wheel -m 0644
	install -d $(lib-dir)/k -o root -g wheel
	install $(OUT)/libk.a $(OUT)/libk.so $(OUT)/boot.o \
		$(lib-dir)/k/ -o root -g wheel -m 0644


uninstall: $(header-dir)/k $(lib-dir)/k
	rm -rf $^

lists = moddirs functions assemblies fnobjects rtobjects binaries binmods POSIX
dbg:
	@echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))")

%.obj: %/makefile  $(OUT)
	cd $* && $(MAKE) obj

%.tool: %/makefile $(OUT)
	cd $* && $(MAKE) tool

%.dbg: %/makefile $(OUT)
	cd $* && $(MAKE) dbg

%.def: %/makefile $(TMP)/typesize.def \

                  $(TMP)/system_calls.h \
				  $(TMP)/system_calls.s \
				  $(TMP)/error_table.h \
				  $(OUT) $(OUT)/k
	cd $* && $(MAKE) def

.PRECIOUS: $(TMP)/system_calls.%
................................................................................

$(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) $(OUT)/k $(TMP):
	mkdir -p $@







>
>








>
>
|
|
|
|
|





|
|
|

|
|

|
|
|

|
|
|
|

|
|
|
|

>
>
|

<
|
>
>
>


|







 







|








>




|

<
|
|
>




|



|









>







 







>
>
>
>
>
>
>
>
>
>


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
55
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
..
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# 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))
................................................................................
	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.%
................................................................................

$(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 $@

Modified modmake from [0390aebc43] to [2d5c92fb6a].

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
#- modmake
# this is the master makefile that controls the building of each
# libk module. it is included from each k*/makefile.
# vim: ft=make



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))

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%)

obj: $(cobjects:%.c=${OUT}/$(mod).%.o) \
	 $(sobjects:%.s=${OUT}/$(mod).%.o)
tool: $(tools:%.exe.c=${OUT}/$(mod).%) \
	  ${OUT}/libk.a

def: $(headers:%=${OUT}/k/%)





>
>











<
<
<
<
<
<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17












18
19
20
21
22
23
24
#- 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/%)