libk  Check-in [a14ceee056]

Overview
Comment:development milestone
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a14ceee05626ca2753894004bbfa8747de98b37c29a0f92c83687fdd93e76db2
User & Date: lexi on 2019-06-27 21:39:17
Other Links: manifest | tags
Context
2019-06-27
22:14
fixes for shared building check-in: ec9b2b74b3 user: lexi tags: trunk
21:39
development milestone check-in: a14ceee056 user: lexi tags: trunk
12:21
more fixes check-in: 93014cedbc user: lexi tags: trunk
Changes

Modified arch/makefile from [657c34aa94] to [0ea82c6f52].

     1         -linux-headers = /usr/include/asm/
     2         -calls.x86.lin.32.s: $(linux-headers)/unistd_32.h
     3         -	grep "#define __NR_" $< | sed "s;^#define __NR_;%define sys.;" > $@
     4         -calls.x86.lin.64.s: $(linux-headers)/unistd_64.h
     5         -	grep "#define __NR_" $< | sed "s;^#define __NR_;%define sys.;" > $@
            1  +lin-headers = /usr/include/asm
            2  +fbsd-headers = /usr/include/sys
            3  +
            4  +${TMP}:
            5  +	mkdir -p ${TMP}
            6  +
            7  +${TMP}/calls.x86.lin.32.s: $(lin-headers)/unistd_32.h ${TMP}
            8  +	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
            9  +${TMP}/calls.x86.lin.64.s: $(lin-headers)/unistd_64.h ${TMP}
           10  +	grep "#define __NR_" $< | sed 's;^#define __NR_;%define sys.;' > $@
           11  +${TMP}/calls.x86.fbsd.%.s: $(fbsd-headers)/syscall.h ${TMP}
           12  +	grep "#define	SYS_" $< | sed 's;^#define	SYS_;%define sys.;' > $@

Modified arch/x86.lin.64.s from [2b600a2718] to [f2e5b4d4ec].

     1      1   ;; abi definition file for x86 linux 64-bit
     2      2   ; vim: ft=nasm
     3      3   
     4      4   ; syscall64 numbers - syscall table must be created first!
     5      5   %include "calls.x86.lin.64.s"
     6      6   
     7         -; syscall ops
     8         -%define sys.call syscall
            7  +; linux uses the common x86-64 ABI
            8  +%include "x86.syscall.64.s"
     9      9   
    10         -; register order for syscall convention
    11         -%define sys.reg.n 7
    12         -%define sys.reg.ret rax
    13         -%define sys.reg.0 rax
    14         -%define sys.reg.1 rdi
    15         -%define sys.reg.2 rsi
    16         -%define sys.reg.3 rdx
    17         -%define sys.reg.4 r10
    18         -%define sys.reg.5 r8
    19         -%define sys.reg.6 r9
    20         -
    21         -; register order for ccall convention
    22         -%define ccall.reg.ct 6
    23         -%define ccall.reg.ret rdi
    24         -%define ccall.reg.0 rdi
    25         -%define ccall.reg.1 rsi
    26         -%define ccall.reg.2 rdx
    27         -%define ccall.reg.3 rcx
    28         -%define ccall.reg.4 r8
    29         -%define ccall.reg.5 r9
    30         -
    31         -%macro sys 1-8
    32         -; syscall64 wrapper, ex. `sys sys.write, 1, msg, msg.len`
    33         -	%assign i 0
    34         -	%rep %0
    35         -		mov sys.reg. %+ i, %1 ; i'm actually shocked this worked
    36         -		%rotate 1
    37         -		%assign i i+1
    38         -	%endrep 
    39         -	syscall
    40         -%endmacro
    41         -
    42         -%macro sys.prep 1-8
    43         -	; for when we need to modify parameters before we
    44         -	; make the actual call.
    45         -	%assign i 0
    46         -	%rep %0
    47         -		mov sys.reg. %+ i, %1
    48         -		%rotate 1
    49         -		%assign i i+1
    50         -	%endrep
    51         -%endmacro
    52         -
    53         -%macro ccall 1-*
    54         -	%if %0 > ccall.reg.ct
    55         -		%assign ct ccall.reg.ct
    56         -	%else
    57         -		%assign ct %0-1
    58         -	%endif
    59         -	%assign i 0
    60         -	%rotate 1
    61         -	%rep ct
    62         -		; if the function is well-behaved, all its arguments fit
    63         -		; in registers. if not, things get ugly. see below.
    64         -		mov ccall.reg. %+ i, %1
    65         -		%assign i i+1
    66         -		%rotate 1
    67         -	%endrep
    68         -	%if %0 > ccall.reg.ct
    69         -		; if there are more parameters to a C function than the
    70         -		; number of permitted registers, they must be pushed in
    71         -		; reverse order to the stack.
    72         -		; keep your function signatures under control, people.
    73         -		%assign ct (%0-ct)-1
    74         -		%rotate ct
    75         -		%rep ct
    76         -			%rotate -1
    77         -			push %1
    78         -		%endrep
    79         -		%rotate ct
    80         -		push rsp ; it's our responsibility to preserve the stack
    81         -	%endif
    82         -	call %1
    83         -	%if %0 > ccall.reg.ct
    84         -		; the extra arguments are still on the stack; time to
    85         -		; dump them back into the Garbage Zone
    86         -		pop rsp
    87         -	%endif
    88         -%endmacro

Modified kcore/boot.c from [878278ef2e] to [6007ea2ce5].

     1         -#include "core.h"
            1  +#include <k/core.h>
     2      2   extern stat entry(kenv);
     3      3   
     4      4   stat _boot(unsigned int argc, char** argv) {
     5         -	kenv e = { argc, argv };
            5  +	kenv e = { 
            6  +		// todo: determine terminal class and set term vs ansi correctly!
            7  +		{ {kiostream_term, 0}, {kiostream_term, 1} }, // chan std
            8  +		{ {kiostream_closed},  {kiostream_term, 2} }, // chan err
            9  +		argc, argv,
           10  +		null // no environment yet
           11  +	};
     6     12   	return entry(e);
     7     13   }
     8     14   	

Modified kcore/core.h from [bb457bb91b] to [cb5067b74b].

     1      1   #ifndef KIcore
     2      2   #define KIcore
            3  +#include <k/type.h>
            4  +#include <k/io.h>
            5  +#include <k/str.h>
            6  +
            7  +static void* const null = (void*)0;
     3      8   
     4         -typedef unsigned long long sz;
     5         -typedef unsigned char stat;
            9  +typedef struct kvar {
           10  +	ksraw name;
           11  +	ksraw val;
           12  +	char* platform;
           13  +} kvar;
     6     14   
     7     15   typedef struct kenv {
     8         -	sz argc;
     9         -	char** argv;
           16  +	kiochan std;
           17  +	kiochan err;
           18  +	sz argc; char** argv;
           19  +	kvar* vars;
    10     20   } kenv;
    11     21   
    12     22   #endif

Modified kcore/kcore.md from [28c0315020] to [d664110812].

     1      1   # kcore
     2      2   **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.
     3      3   
     4      4   ## entry
     5      5   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.
     6      6   
     7      7   ## types
     8         -kcore contains fixed-width integer types. note that the available of each depends on your platform; compilation will fail if e.g. you try to use a u64 or a u128 on a 32-bit platform, so where exact lengths are not required, you may wish to use the built-in C types instead.
            8  +kcore contains fixed-width integer types (in <k/type.h>). note that the availability of each depends on your platform; compilation will fail if e.g. you try to use a u64 or a u128 on a 32-bit platform, so where exact lengths are not required, you may wish to use the built-in C types instead.
     9      9   
    10     10    * `u8` - an unsigned 8-bit integer
    11     11    * `s8` - a signed 8-bit integer
    12     12    * `u16` - an unsigned 16-bit integer
    13     13    * `s16` - a signed 16-bit integer
    14     14    * `u32` - an unsigned 32-bit integer
    15     15    * `s32` - a signed 32-bit integer
................................................................................
    21     21    * `sword` - a signed integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64)
    22     22    * `stat` - the type of process return values expected by the platform (usually u8 on linux)
    23     23   
    24     24   ### struct kenv
    25     25   `kenv` is a struct that encompasses the environment the program was launched in.
    26     26    * `kiochan std` - a stereo IO channel for reading and writing to and from stdout.
    27     27    * `kiochan err` - a mono IO channel for writing to stderr.
    28         - * `kvar* env` - a pointer into the program's environment
           28  + * `kvar* vars` - a pointer into the program's environment
    29     29   
    30     30   ### struct kvar
    31     31   `kvar` is a struct that abstracts over platform environment variables.
    32     32    * `kstr name` - the name of an environment variable
    33     33    * `kstr val` - the value of an environment variable
    34     34    * `char* platform` - a pointer into the platform's underlying representation

Modified kcore/makefile from [f0df06fe05] to [a535931ecd].

            1  +## kcore/makefile
            2  +# kcore has to include, among other things, a replacement
            3  +# for stddef.h, and that can't be written in portable C,
            4  +# so we're generating it at build time.
            5  +#
            6  +# look, imma just be straight with you. the mechanism we're
            7  +# using to generate these headers is unbelievably heinous.
            8  +# it's inelegant, it's gross, and it's horrible. in the long
            9  +# term this NEEDS to be replaced with a bespoke solution
           10  +# instead of makefile gibberish. hopefully tho this will be
           11  +# enough in the short term for libk to get going, enough that
           12  +# someone more competent than me will someday be interested
           13  +# in fixing this horrorshow.
           14  +#
           15  +# until them: i'm sorry.
           16  +# very sincerely yours, lexi hale
           17  +
           18  +gen-headers = type.h
           19  +
     1     20   include ../modmake
           21  +
           22  +${OUT}/k/type.h: ${TMP}/type.${TARGET}.i
           23  +	cp $< $@
           24  +
           25  +# generating C source in make… yaaay
           26  +define arch =
           27  +${TMP}/type.$(1).%.$(2).i: type.$(1).$(2).i def.%.i ${TMP}
           28  +	echo '#ifndef KItype' > $$@
           29  +	echo '#define KItype' >> $$@
           30  +	cat def.$$*.i >> $$@
           31  +	cat $$< >> $$@
           32  +	echo '#endif' >> $$@
           33  +endef
           34  +
           35  +$(eval $(call arch,x86,32))
           36  +$(eval $(call arch,x86,64))
           37  +

Modified kgraft/exe.attach.c from [a7ffc6f8bf] to [572a900790].

            1  +#include <k/core.h>
            2  +stat entry(kenv e) {
            3  +	return 0;
            4  +}

Modified kio/io.h from [247977844e] to [824a86b217].

     1      1   #ifndef KIio
     2      2   #define KIio
            3  +/* <k/io.h>
            4  + * ~ lexi hale <lexi@hale.su>
            5  + * this header declares IO primitive functions and
            6  + * structures. it is the same for all platforms.
            7  + * platform-specific code is found in the *.platform.h
            8  + * files.
            9  + */
           10  +
           11  +#include <k/type.h>
           12  +
           13  +typedef enum kiostream_kind {
           14  +	kiostream_closed,
           15  +	  // this kiostream cannot be written to
           16  +	kiostream_file,
           17  +	  // this kiostream represents a file
           18  +	kiostream_sock,
           19  +	  // this kiostream is attached to a socket,
           20  +	  // UNIX, IP, or otherwise
           21  +	kiostream_term,
           22  +	  // this socket is being used to communicate
           23  +	  // directly with a human being
           24  +	kiostream_ansi,
           25  +	  // like kiostream_term, but can also understand
           26  +	  // ANSI control codes
           27  +	kiostream_other
           28  +	  // no fuckin idea
           29  +} kiostream_kind;
           30  +
           31  +typedef struct kiostream {
           32  +	kiostream_kind kind;
           33  +	#include "kiostream.platform.h"
           34  +} kiostream;
           35  +
           36  +typedef struct kiochan {
           37  +	kiostream in;
           38  +	  // text can be read from this stream
           39  +	kiostream out;
           40  +	  // text can be written to this stream
           41  +} kiochan;
           42  +
           43  +unsigned long long kiosend(kiochan); // send data to a channel
           44  +unsigned long long kiorecv(kiochan); // receive data from a channel
           45  +
           46  +typedef enum kiocond {
           47  +	kiocond_ok,
           48  +	  // success
           49  +    kiocond_fail,
           50  +	  // action failed
           51  +} kiocond;
     3     52   
     4     53   #endif

Modified kio/makefile from [f0df06fe05] to [86c8f24ac7].

            1  +gen-headers = kiostream.platform.h
            2  +
     1      3   include ../modmake
            4  +
            5  +ifeq (${POSIX},yes)
            6  +api = posix
            7  +else
            8  +api = ${OS}
            9  +endif
           10  +
           11  +${OUT}/k/kiostream.platform.h: kiostream.$(api).i
           12  +	cp $< $@

Modified kmem/kmem.md from [9a7772ee1a] to [9ed4178122].

    50     50    
    51     51   the convenience function `kmstat(void*) → kmptr` wraps a pointer to a static object in a `kmptr` struct.
    52     52   
    53     53   ### kmcell
    54     54   
    55     55   `kmcell` is a stub struct used to disambiguate between source types.a "source" is an object that can hold an allocated object, such as the heap, a memory pool, a fixed-length array on stack, or a fixed-length global array. all values produced by a kmem allocation function point to within a `kmcell`.
    56     56   
    57         - * `kmptr_kind kind` - kind of cell
    58         - * `size_t sz` - kind of cell (data plus all fields)
           57  + * `kmkind kind` - kind of cell
           58  + * `size_t size` - size of cell (data plus all fields)
    59     59    * `kmshred shred` - shredding flag
    60     60   
    61     61   ### kmref
    62     62   
    63     63   `kmref` is a struct that constitutes the in-memory representation of a reference-counted cell.
    64     64   
    65     65    * `kmkind kind = kmkind_ref` - kind of cell

Modified kmem/mem.h from [dc631dc568] to [4d62b7403b].

     1      1   #ifndef KImem
     2      2   #define KImem
            3  +#include <k/type.h>
            4  +
            5  +typedef enum kmkind {
            6  +	kmkind_none,
            7  +	kmkind_heap,
            8  +	kmkind_pool,
            9  +	kmkind_ref,
           10  +	kmkind_tree
           11  +} kmkind;
           12  +
           13  +typedef enum kmshred {
           14  +	kmshred_yes,
           15  +	kmshred_no
           16  +} kmshred;
           17  +
           18  +typedef struct kmcell {
           19  +	kmkind kind;
           20  +	sz size;
           21  +	kmshred shred;
           22  +	sz refs;
           23  +	struct kmcell* src;
           24  +	char data[];
           25  +} kmcell;
           26  +
           27  +typedef struct kmptr {
           28  +	kmkind kind;
           29  +	kmshred shred;
           30  +	void* ref;
           31  +	kmcell* cell;
           32  +} kmptr;
     3     33   
     4     34   #endif

Modified kstr/kstr.md from [8ba3da6088] to [b3e2b4c4d7].

     2      2   
     3      3   **kstr** is the libk string library. it uses the **short** naming convention with the glyph `s`. **kstr** implies `#include <k/mem.h>`.
     4      4   
     5      5   ## types
     6      6   
     7      7   ### struct kstr
     8      8   `struct kstr` is a structure for holding pascal strings (length-prefixed strings). it is the basic libk string type. **note:** if `ptr.ref` ≠ NULL and `sz` = 0, the string's length is unknown and should be calculated by any function that operates on a kstr, storing the result in the object if possible.
     9         - * `size_t sz` - length of string, excluding any null terminator
            9  + * `sz size` - length of string, excluding any null terminator
    10     10    * `kmptr ptr` - pointer to string in memory
    11     11   
    12     12   ### struct ksraw
    13     13   `struct ksraw` is like `kstr` except it uses raw `char` pointers instead of a `kmptr`.
    14         - * `size_t sz` - length of string, excluding any null terminator
           14  + * `sz size` - length of string, excluding any null terminator
    15     15    * `char* ptr` - pointer to string in memory
    16     16   
    17     17   ### struct ksbuf
    18     18   `struct ksbuf` is a structure used to hold buffers.
    19         - * `size_t sz` - maximum size of buffer, including any null terminator
           19  + * `sz size` - maximum size of buffer, including any null terminator
    20     20    * `char* buf` - region of memory to store buffer in
    21     21    * `ksalloc strat` - allocation strategy
    22     22    * `kmkind rule` - kind of allocator to use. only needs to be set if `where` is NULL. see [kmem](../kmem/kmem.md).
    23     23    * `kmcell* where` - where to allocate the object, in case of pool or tree allocation.
    24     24   
    25     25   ### struct kschain
    26     26   `struct kschain` is a structure used for string accumulators that works by aggregating pointers to strings, instead of copying the strings themselves.
    27     27    * `kschain_kind kind` - kind of chain
    28     28    * `kmkind rule` - kind of allocation to use if `kind` ≠ `kschain_kind_linked`
    29     29    * `pstr* ptrs` - pointer to pointer list
    30         - * `size_t ptrc` - number of pointers
    31         - * `size_t sz` - total amount of space in `ptrs`
           30  + * `sz ptrc` - number of pointers
           31  + * `sz size` - total amount of space in `ptrs`
    32     32   
    33     33   #### enum kschain_kind
    34     34    * `kschain_kind_block` - occupies a single block of memory
    35     35    * `kschain_kind_linked` - uses a linked list, allocated and deallocated as necessary
    36     36   
    37     37   ### enum ksalloc
    38     38   `enum ksalloc` is an enumerator that tells libk what strategy to use when filling a `ksbuf` or `kschain` struct.
................................................................................
    61     61   	char* src = <...>;
    62     62   	kmbuf buf = { sizeof mem, &mem, kmkind_none };
    63     63       kstr chain[] = {
    64     64   		Kstr("<a href=\""), { 0, src }, Kstr("\">"),
    65     65   			ksref(text),
    66     66   		Kstr("</a>")
    67     67   	};
    68         -	char* html = kscomp([Kmsz(chain)](../kmem/kmem.md), chain, &buf);
           68  +	char* html = kscomp(Kmsz(chain), chain, &buf);
    69     69   
    70     70   kscomp will only calculate the length of individual strings if they are not already known. when it needs to calculate the length of a string, it will store that length in the original array so repeated calls can be made without needing to repeatedly calculate the lengths. this is not always desirable, so the variant `kscompc` exists, which is exactly the same as `kscomp` in every respect except that `chain` is not altered in any way.
    71     71   
    72     72   ### macros
    73     73   if `KFclean` is not set when <k/str.h> is included, the following macros are defined.
    74     74   
    75     75    * `Kstr(string)` - the compile-time equivalent to `kstr()`. `Kstr` takes a literal string and inserts the text `{ sizeof (string), string }` into the document, suitable for initializing a kstr.

Modified kstr/str.h from [21d6720beb] to [f7e947c0d1].

     1      1   #ifndef KIstr
     2      2   #define KIstr
     3      3   
            4  +#include <k/mem.h>
            5  +
            6  +typedef struct kstr {
            7  +	sz size;
            8  +	kmptr ptr;
            9  +} kstr;
           10  +
           11  +typedef struct ksraw {
           12  +	sz size;
           13  +	char* ptr;
           14  +} ksraw;
     4     15   #endif

Modified libk.md from [d834bc0082] to [523e766d88].

    17     17   ## goals
    18     18   
    19     19   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.
    20     20   
    21     21    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.
    22     22    2. **file manipulation.** libc's file manipulation primitives are a relic of a bygone age and in dire need of upgrading.
    23     23    3. **terminal manipulation.** libc has no provision for simple output formatting, a task that requires a combination of ANSI codes and in some cases pty manipulation with POSIX APIs, both of which are somewhat dark wizardry. this situation forces many innocent coders to drag in the entire unholy bulk of the aptly named library `ncurses`, much of whose code has been utterly obsolete for the last twenty years and whose API is one of the most singularly hateful ones in existence. libk therefore should offer a simple, straightforward way to do gracefully-degrading terminal sorcery.
    24         - 0. **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))
    25         - 0. **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.
    26         - 0. **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.
           24  + 4. **memory management.** the single memory management function `malloc()` provided by libc is absolutely pitiful. this is 2019. modern applications have much more exotic allocation needs, and a standard library should offer a range of allocators and management techniques, as well as abstract pointer objects so that pointers to objects of different allocation types (including static or stack allocation!) can be mixed freely and safely.
           25  + 5. **intrinsic reentrancy.** because *jesus christ,* libc.
           26  + 6. **interprocess communication.** libc offers no useful IPC abstractions over the paltry array of tools POSIX &co. give us to work with. we can do better.
           27  + 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))
           28  + 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.
           29  + 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.
           30  + 10. **sane error-handling.** every time you type `errno` god murders a puppy.
    27     31   
    28     32   ## naming conventions
    29     33   
    30     34   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!
    31     35   
    32     36   libk is designed to fix this (in hindsight) glaring error.
    33     37   
................................................................................
    62     66    * FreeBSD: `fbsd`
    63     67    * NetBSD: `nbsd`
    64     68    * OpenBSD: `obsd`
    65     69    * Darwin/Mac OS X/iOS: `dar`
    66     70    * MS-DOS: `dos`
    67     71    * FreeDOS: `fdos`
    68     72    * Windows: `win`
           73  + * Windows MinGW: `mgw`
    69     74   
    70     75   #### file extensions
    71     76   
    72     77    * C function implementations: `*.c`
    73     78    * C module headers: `*.h`
    74     79    * ancillary C headers: `*.inc.h`
    75     80    * assembly code: `*.s`
................................................................................
    89     94   libk uses only three languages: C (\*.c, \*.h), yasm (\*.s), and make (makefile).
    90     95   
    91     96   other assemblers will probably be necessary for the more exotic targets, however.
    92     97   
    93     98   ## repository structure
    94     99   
    95    100   libk uses a strict directory structure for code, and deviations from this structure will not be tolerated without extremely good reason.
          101  +
          102  +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.
    96    103   
    97    104   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).
    98    105   
    99    106   each function should be kept in a separate file within its module's directory. when OS or architecture-specific code is needed, the file's name should be a list of one or more of the fields [arch, OS, bits, format] separated by a `.` -- for instance, the 32-bit x86 haiku version of a function called `write` defined in assembly would be named `write.x86.hai.32.s`. however, if a function has an extraordinarily large number of versions, they may instead be stored in a folder with the same name as the function.
   100    107   
   101    108   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.
   102    109   
................................................................................
   154    161   
   155    162   **libk.so** will build the dynamically linked form of libk, according to the build variables set
   156    163   
   157    164   **libk.a** will build the statically linked form of libk, according to the build variables set
   158    165   
   159    166   **tool** will build the executables used for modules such as `kgraft`.
   160    167   
   161         -there is no **clean** target. to clean the repository, simply delete the directory `out/`.
          168  +**clean** will delete the `tmp` and `out` trees.
   162    169   
   163    170   ## authors
   164    171   
   165    172   so far, this is a one-woman show. contributions are welcome however.
   166    173   
   167    174    * lexi hale <lexi@hale.su>
   168    175   

Modified makefile from [0ee3372ddd] to [2300652a5e].

     1      1   export OUT = $(PWD)/out
     2      2   
     3      3   export ARCH = x86
     4      4   export OS = lin
     5      5   export BITS = 64
            6  +export TMP = $(PWD)/tmp
     6      7   
     7      8   export TARGET = $(ARCH).$(OS).$(BITS)
     8      9   
     9     10   moddirs = $(wildcard k*)
    10         -modules = $(moddirs:k%=%)
    11         -headers = $(moddirs:k%=$(OUT)/k/%.h)
    12         -objects = $(modules:%=$(OUT)/k%.o)
    13         -makefiles = $(moddirs:%=%/makefile)
    14         -
    15     11   binaries = $(wildcard */exe.*.c)
    16     12   binmods = $(sort $(dir $(binaries)))
    17     13   
    18         -all: obj defs tool
           14  +posix-oses = lin fbsd dar and hai mgw
           15  +
           16  +ifeq ($(findstring $(OS),$(posix-oses)),$(OS))
           17  +export POSIX = yes
           18  +else
           19  +export POSIX = no
           20  +endif
           21  +
           22  +# include libgcc.a in gcc builds, just in case
           23  +ifeq ($(CC),gcc)
           24  +export COMPLIB = -lgcc
           25  +endif
           26  +
           27  +all: defs obj tool
    19     28   obj: $(moddirs:%=%.obj)
    20         -defs: $(headers)
    21         -tool: $(binmods:%=%.tool)
           29  +defs: $(moddirs:%=%.def)
           30  +tool: $(OUT)/libk.a $(binmods:%=%.tool) 
           31  +clean:
           32  +	rm -rf $(TMP) $(OUT)
    22     33   
    23         -lists = moddirs modules headers objects makefiles binaries binmods
           34  +lists = moddirs objects binaries binmods POSIX
    24     35   dbg:
    25     36   	@echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))")
    26     37   
    27     38   %.obj: %/makefile ${TARGET}.calls $(OUT)
    28     39   	cd $* && $(MAKE) obj
    29     40   
    30     41   %.tool: %/makefile $(OUT)
    31     42   	cd $* && $(MAKE) tool
    32     43   
    33     44   %.dbg: %/makefile $(OUT)
    34     45   	cd $* && $(MAKE) dbg
           46  +
           47  +%.def: %/makefile $(OUT) $(OUT)/k
           48  +	cd $* && $(MAKE) def
    35     49   
    36     50   %.calls: arch/makefile
    37         -	cd arch && make calls.$*.s
           51  +	cd arch && $(MAKE) $(TMP)/calls.$*.s
    38     52   
    39         -$(OUT)/libk.so: mods $(OUT)
    40         -	$(CC) -shared -o $@ $(objects)
           53  +$(OUT)/libk.so: obj $(OUT)
           54  +	$(CC) -shared -nostdlib $(COMPLIB) -o $@ $(OUT)/*.o
    41     55   
    42         -$(OUT)/libk.a: mods $(OUT)
    43         -	# using `ar c` and ranlib here instead of
    44         -	# `ar cs` in case `ar` isn't the GNU version
    45         -	ar c $@ $(objects)
           56  +$(OUT)/libk.a: obj $(OUT)
           57  +	# using `ar rc` and ranlib here instead of
           58  +	# `ar rcs` in case `ar` isn't the GNU version
           59  +	ar rc $@ $(OUT)/*.o
    46     60   	ranlib $@
    47     61   
    48         -$(OUT)/k/%.h: k%/makefile $(OUT)/k
    49         -	cd k$* && $(MAKE) $@
    50         -
    51     62   $(OUT) $(OUT)/k:
    52     63   	mkdir -p $@

Modified modmake from [e72fb78502] to [adae292a57].

     2      2   # this is the master makefile that controls the building of each
     3      3   # libk module. it is included from each k*/makefile.
     4      4   # vim: ft=make
     5      5   
     6      6   mod = $(notdir $(PWD))
     7      7   src = $(wildcard *.c) $(wildcard *.s)
     8      8   bare = $(mod:k%=%)
            9  +headers = $(wildcard *.h) $(gen-headers)
     9     10   
    10     11   tools    = $(filter     exe.%.c,   $(src))
    11     12   nontools = $(filter-out exe.%.c,   $(src))
    12     13   cobjects = $(filter     %.c,       $(nontools))
    13     14   sobjects = $(filter %.${TARGET}.s, $(nontools))
    14     15   
           16  +cflags = -isystem ${OUT} -nostdlib ${COMPLIB} -L${OUT} -lk
           17  +
    15     18   obj: $(cobjects:%.c=${OUT}/$(mod).%.o) \
    16     19   	 $(sobjects:%.s=${OUT}/$(mod).%.o)
    17         -tool: $(tools:exe.%.c=${OUT}/$(mod).%)
           20  +tool: $(tools:exe.%.c=${OUT}/$(mod).%) \
           21  +	  ${OUT}/libk.a
           22  +
           23  +def: $(headers:%=${OUT}/k/%)
    18     24   
    19     25   dbg:
    20     26   	@echo tools = $(tools)
    21     27   	@echo TARGET = ${TARGET}
    22     28   	@echo cobjects = $(cobjects)
    23     29   	@echo sobjects = $(sobjects)
           30  +	@echo headers = $(headers)
    24     31   	@echo mod = $(mod)
    25     32   
    26     33   ${OUT}/$(mod).%.o: %.c
    27         -	$(CC) -c $< -o $@
           34  +	$(CC) $(cflags) -c $< -o $@
    28     35   
    29         -${OUT}/k/$(bare).h: $(bare).h
           36  +${OUT}/k/%.h: %.h
    30     37   	cp $< $@
    31     38   
    32     39   ${OUT}/$(mod).%: exe.%.c
    33         -	$(CC) $< -o $@
           40  +	$(CC) $(cflags) $< -o $@
           41  +
           42  +${TMP}:
           43  +	mkdir -p ${TMP}
    34     44   
    35     45   #- assembly
    36     46   # compiling  the assembly  code will  be  faster but  a lot  more
    37     47   # complex, given the  nature of assembly and the  large number of
    38     48   # platforms  targeted.  we need  to  add  build rules  for  every
    39     49   # arch.OS[.bits] tuple;  since this  is a fairly  repetetive task
    40     50   # that  requires ugly  make  rules,  we're just  going  to use  a
................................................................................
    43     53   # ${OUT} = ultimate build directory
    44     54   # $(mod) = module name
    45     55   #      % = function name
    46     56   #   $(1) = arch tuple
    47     57   arch = ${OUT}/$(mod).%.$(1).o: %.$(1).s
    48     58   # invoke with $(call arch,tuple). do not
    49     59   # put spaces between either term though!
           60  +
           61  +ifeq ($(debug),yes)
           62  +yasm-flags = -gdwarf2
           63  +endif
    50     64   
    51     65   #-- linux
    52     66   # linux uses the ELF{32,64} binary format,  and generating these
    53     67   # from yasm is trivial.  linux only supports one ABI per format,
    54     68   # at least with ELF, so that's all we need to do.
    55     69   
    56     70   #${OUT}/$(mod).%.x86.lin.32.o: %.x86.lin.32.s
    57     71   $(call arch,x86.lin.32)
    58         -	yasm -gdwarf2 -felf32 $< -o $@
           72  +	yasm $(yasm-flags) -felf32 -i${TMP} $< -o $@
    59     73   
    60     74   #${OUT}/$(mod).%.x86.lin.64.o: %.x86.lin.64.s
    61     75   $(call arch,x86.lin.64)
    62         -	yasm -gdwarf2 -felf64 $< -o $@
           76  +	yasm $(yasm-flags) -felf64 -i${TMP} $< -o $@
    63     77   
    64     78   #-- freebsd
    65     79   # the freebsd ABI is different, so it will require different code
    66     80   # (though there might be ways to minimize that). freebsd uses the
    67     81   # same binary format as Linux  (though it also supports a.out and
    68     82   # COFF) but because freebsd can interpret multiple different ABIs
    69     83   # the  object files  need to  be "branded"  with the  correct one