Comment: | add a bunch of code, port the header mechanism to gpp; add a fuckton of definitions and compatibility header code; notably, add core function kstop and x86.lin.{32,64} impl. update docs accordingly |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
e794c5edef00e56053792a71a97b4e5b |
User & Date: | lexi on 2019-06-29 09:31:50 |
Other Links: | manifest | tags |
2019-07-26
| ||
09:51 | major update. fix ridiculous old type size determination mechanism. mmap is still broken and i'm not sure why; the syscall does not appear to be going through correctly - see posix_mmap, kmheapa, and kcore/testbin.exe.fn check-in: 6479e060a3 user: lexi tags: trunk | |
2019-06-29
| ||
09:31 | add a bunch of code, port the header mechanism to gpp; add a fuckton of definitions and compatibility header code; notably, add core function kstop and x86.lin.{32,64} impl. update docs accordingly check-in: e794c5edef user: lexi tags: trunk | |
2019-06-28
| ||
04:52 | fix stupid bullshit that was including boot.o in libk.a which already HAS the runtime shit ohmyGOD check-in: de8e1eb5d2 user: lexi tags: trunk | |
Added grammar/grammar.gpp version [89005aac7c].
> > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#define flag -#1 #define exec x #define mode flag(#1)#2 #define user U #define meta M #define add +#1 #define del -#1 #define unix_lf z #define keepnl n #define tri #1#2#3 #define comment c #define string s #define quote q #define eval S #define evalquote Q #define stack bal_stack bal_unstack #define meta_grammar meta_start meta_end meta_arg_start meta_sep meta_arg_end stack #define user_grammar call_start call_end arg_start arg_sep arg_end stack arg_num_char quote_char |
Added grammar/makefile version [8c2d1af7ce].
> > |
1 2 |
${TMP}/%: %.gpp grammar.gpp ${gpp} $< | tr "\n" ' ' > $@ |
Added grammar/precomp.g.gpp version [d33952f39e].
> > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
#include grammar.gpp #mode comment "//" "\n" // this file defines the "precomp" grammar, the grammar // that's used to process C code templates // vim: ft=c #define call_start "[" #define call_end "]" #define arg_start " " #define arg_sep ",\\w" #define arg_end "]" #define bal_stack "\([" #define bal_unstack "\)]" #define arg_num_char "\\$" #define quote_char "|" #define meta_start "\\w[" #define meta_end "]\\w" #define meta_arg_start " " #define meta_sep "\\w:\\w" #define meta_arg_end "]\\W" add(unix_lf) add(comment "---" "\\n") add(comment "(*" "*)") flag(exec) mode(user, user_grammar) mode(meta, meta_grammar) |
Added kcore/__stack_chk_fail.fn.c version [7f5547f66a].
> > > |
1 2 3 |
#include <k/core.h> void __stack_chk_fail(void) { kstop(-1); } |
Modified kcore/boot.rt.x86.lin.64.s from [2671a43f32] to [22c891476d].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
; vim: ft=nasm
bits 64
%include "../arch/x86.lin.64.s"
global _start:function
extern _boot
extern entry;
_start:
mov rbp, rsp
mov rdi, [rbp + 0] ; argc
lea rsi, [rbp + 8] ; argv
call _boot
mov sys.reg.1, sys.reg.ret
mov sys.reg.0, sys.exit
sys.call
|
| |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
; vim: ft=nasm bits 64 %include "../arch/x86.lin.64.s" global _start:function extern _boot extern entry _start: mov rbp, rsp mov rdi, [rbp + 0] ; argc lea rsi, [rbp + 8] ; argv call _boot mov sys.reg.1, sys.reg.ret mov sys.reg.0, sys.exit sys.call |
Modified kcore/core.h from [cb5067b74b] to [ded1289884].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef KIcore
#define KIcore
#include <k/type.h>
#include <k/io.h>
#include <k/str.h>
static void* const null = (void*)0;
typedef struct kvar {
ksraw name;
ksraw val;
char* platform;
} kvar;
typedef struct kenv {
kiochan std;
kiochan err;
sz argc; char** argv;
kvar* vars;
} kenv;
#endif
|
< < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 127 128 129 130 |
#ifndef KIcore #define KIcore #include <k/type.h> #include <k/io.h> #include <k/str.h> typedef struct kvar { ksraw name; ksraw val; char* platform; } kvar; 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) bool /* enum bool { */ #endif { false = 0, no = 0, true = 1, yes = 1 } #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 # define KVvm_spec K_TEMP_M2QD52 # endif # if defined(__GNUC__) || defined(__clang__) # define KA(KVvm_spec) __attribute__((KVvm_args)) # else # define KA(KVvm_spec) # endif # define KAformat(KVvm_spec) KA(format(KVvm_args)) # define KAexport(KVvm_spec) KA(visibility(KVvm_args)) # define KAunused KA(unused) # define KAnoreturn KA(noreturn) # define KApure KA(const) # define KAinline KA(always_inline) # define KAflatten KA(flatten) # define KAexport_none KAexport("hidden") # define KAexport_force KAexport("default") /* now we define standard version flags, * to make it easy for the user to write * more portable code. */ # if (__STDC_VERSION__ >= 199901L) # define KFstd_c89 # define KFstd_c99 # define KVstd c99 # else # ifdef __STDC__ # define KFstd_c89 # define KVstd c89 # else # define KVstd K&R /* UH OH */ # endif # endif # if (__STDC_VERSION__ >= 201103L) # define KFstd_c11 # define KVstd c11 # endif # ifdef __cplusplus # define KFstd_cpp # define KVstd c++ # if (__cplusplus >= 201103L) # define KFstd_cpp11 # define KVstd c++11 # endif /* TODO: add more */ # endif #endif /* hooo boy. null. that one's got a storied * history across the versions and dialects. * below, we try to find the ideal way to * offer a "null" "keyword" depending on * dialect, version, and whether the user * has asked for macros to be suspended. * note that this may result in no "null" * being defined in C++ or K&R C. */ #if defined (__cplusplus) && ! defined(KFclean) # if __cplusplus >= 201103L # define null nullptr # else # define null ((void*)0) # endif #elif defined __STDC__ enum { null = 0 }; /* believe it or not, this is actually * completely legal. doesn't even raise * a single warning. i was surprised too. */ #elif ! defined(KFclean) # define null ((void*)0) #endif #ifdef __cplusplus # define noreturn [[ noreturn ]] #elif __STDC_VERSION__ >= 201103L # define noreturn _Noreturn #else # define noreturn #endif noreturn void kstop(longstat code); #ifdef KFclean # undef noreturn #endif #endif |
Deleted kcore/def.fbsd.i version [4373f0187e].
1 2 |
#define KVos fbsd typedef unsigned char stat; |
< < |
Deleted kcore/def.h version [5f84d85008].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <k/type.h> /* <k/def.h> * ~ lexi hale <lexi@hale.su> * define flags so we can reason about * our environment. */ #if (KVos == lin) ||\ (KVos == fbsd) ||\ (KVos == obsd) ||\ (KVos == nbsd) ||\ (KVos == dar) ||\ (KVos == and) # define KFenv_unix #endif #if defined(KFenv_unix) ||\ (KVos == hai) ||\ (KVos == mgw) # define KFenv_posix #endif |
< < < < < < < < < < < < < < < < < < < < < |
Added kcore/def.h.m version [9abe158651].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
--- kcore/def.h.m → <k/def.h> --- ~ lexi hale <lexi@hale.su> --- this file gathers information on the environment it's --- being compiled in, setting macros that other headers --- need. it will be emitted as <k/def.h>. --- vim: ft=c [ifdef atom_target_bits] [define target: [atom_target_arch].[atom_target_os].[atom_target_bits]] #define KVbits [atom_target_bits] [else] [define target: [atom_target_arch].[atom_target_os]] [endif] #define KVtarget [target] #define KVos [atom_target_os] #define KVarch [atom_target_arch] [if [target_unix] == yes] #define KFenv_unix #define KFenv_posix [else] [if [target_posix] == yes] #define KFenv_posix [endif] [endif] #define Kpragma(p) _Pragma(#p) #if defined(__GNUC__) || defined(__clang__) # define Kerror(msg) Kpragma(GCC error #msg) #else # define Kerror(msg) Kpragma(message #msg) #endif #define Knoimpl(fn) Kerror(no implementation of fn for platform [target]) |
Deleted kcore/def.lin.i version [0178d496a4].
1 2 |
#define KVos lin typedef unsigned char stat; |
< < |
Deleted kcore/def.win.i version [11ccc3c2e7].
1 2 |
#define KVos win typedef u32 stat; |
< < |
Added kcore/exit.fn.x86.lin.32.s version [4c4a17d7b6].
> > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 |
bits 32 %include "../arch/x86.lin.32.s" ; vim: ft=nasm global kio_posix_exit kio_posix_exit: mov sys.reg.0, sys.call.exit mov sys.reg.1, [esp + 4] ; first C int argument sys.call ; does not return |
Added kcore/exit.fn.x86.lin.64.s version [4c49f79d26].
> > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 |
bits 64 %include "../arch/x86.lin.64.s" %include "../arch/x86.cdecl.64.s" ; vim: ft=nasm global kio_posix_exit kio_posix_exit: mov sys.reg.1, ccall.reg.0 ;nop - rdi → rdi mov sys.reg.0, sys.exit sys.call ; no return |
Modified kcore/kcore.md from [d664110812] to [28cd81b166].
1
2
3
4
5
6
7
8
9
..
28
29
30
31
32
33
34
|
# 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.
## 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>). 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.
................................................................................
* `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
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
..
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
|
# 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>). 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. ................................................................................ * `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. |
Added kcore/magic.h version [1f7f63c3e2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
/* <k/magic.h> * ~ lexi hale <lexi@hale.su> * one of libk's biggest goals is standardization across * software. for this reason, we define here a variety * of "magical numbers" used to signal or describe * various states, messages, and errors. suggestions are * welcome. */ #include <k/type.h> typedef enum kbad { // values to be returned by an entry function kbad_ok = 0, /* the requested operation completed * successfully */ /* these are synchronized with freebsd's existing * sysexit.h conventions. */ kbad_usage = 64, /* # fbsd EX_USAGE * a usage screen was displayed to the user * on request or due to improperly formed call */ kbad_data = 65, /* # fbsd EX_DATAERR * data supplied by the user was incorrect in * some way */ kbad_no_input = 66, /* # fbsd EX_NOINPUT * input to the program is absent */ kbad_user = 67, /* # fbsd EX_NOUSER * these aren't the droids you're looking for */ kbad_host = 68, /* # fbsd EX_NOHOST * that host doesn't exist */ kbad_avail = 69, /* # fbsd EX_UNAVAILABLE * a necessary resource or support system isn't * available, or something else went wrong */ kbad_internal = 70, /* # fbsd EX_SOFTWARE * "my bad" */ kbad_os = 71, /* # fbsd EX_OSERR * the OS did a fucksy-wucksy */ kbad_osfile = 72, /* # fbsd EX_OSFILE * a system file is fucked up or gone */ kbad_creat = 73, /* # fbsd EX_CANTCREAT */ kbad_io = 74, /* # fbsd EX_IOERR */ kbad_try = 75, /* # fbsd EX_TEMPFAIL * something went wrong this time. try again * some other time */ kbad_proto = 76, /* # fbsd EX_PROTOCOL * failure to speak a protocol correctly */ kbad_perm = 77, /* # fbsd EX_NOPERM * you or the program do not have permissions * to do the thing requested */ kbad_conf = 78, /* # fbsd EX_CONFIG * your configuration is fucked */ } kbad; |
Modified kcore/makefile from [121a62ca71] to [c01fcd380e].
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 |
## kcore/makefile # kcore has to include, among other things, a replacement # for stddef.h, and that can't be written in portable C, # so we're generating it at build time. # # look, imma just be straight with you. the mechanism we're # using to generate these headers is unbelievably heinous. # it's inelegant, it's gross, and it's horrible. in the long # term this NEEDS to be replaced with a bespoke solution # instead of makefile gibberish. hopefully tho this will be # enough in the short term for libk to get going, enough that # someone more competent than me will someday be interested # in fixing this horrorshow. # # until them: i'm sorry. # very sincerely yours, lexi hale gen-headers = type.h include ../modmake ${OUT}/k/type.h: ${TMP}/type.${TARGET}.i cp $< $@ # generating C source in make… yaaay define arch = ${TMP}/type.$(1).%.$(2).i: type.$(1).$(2).i def.%.i ${TMP} echo '#ifndef KItype' > $$@ echo '#define KItype' >> $$@ cat $$< >> $$@ cat def.$$*.i >> $$@ echo '#endif' >> $$@ endef $(eval $(call arch,x86,32)) $(eval $(call arch,x86,64)) |
| > > > > > > > > > > < < < < < | | | | | | | | | | | | | | | | |
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 |
## kcore/makefile # kcore has to include, among other things, a replacement # for stddef.h, and that can't be written in portable C. # so we're generating it at build time. # gen-headers = type.h include ../modmake ## the below code predates the introduction of gpp ## to generate these headers from templates instead ## of trying to write one for everypossible arch ## tuple. it is left as a monument to a terrible ## and now blissfully forgotten past. # # look, imma just be straight with you. the mechanism we're # using to generate these headers is unbelievably heinous. # it's inelegant, it's gross, and it's horrible. in the long # term this NEEDS to be replaced with a bespoke solution # instead of makefile gibberish. hopefully tho this will be # enough in the short term for libk to get going, enough that # someone more competent than me will someday be interested # in fixing this horrorshow. # # until them: i'm sorry. # very sincerely yours, lexi hale # ${OUT}/k/type.h: ${TMP}/type.${TARGET}.i # cp $< $@ # # # generating C source in make… yaaay # define arch = # ${TMP}/type.$(1).%.$(2).i: type.$(1).$(2).i def.%.i ${TMP} # echo '#ifndef KItype' > $$@ # echo '#define KItype' >> $$@ # cat $$< >> $$@ # cat def.$$*.i >> $$@ # echo '#endif' >> $$@ # endef # # $(eval $(call arch,x86,32)) # $(eval $(call arch,x86,64)) # |
Added kcore/old/def.fbsd.i version [4373f0187e].
> > |
1 2 |
#define KVos fbsd typedef unsigned char stat; |
Added kcore/old/def.h version [074eb1cc6b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
#include <k/type.h> /* <k/def.h> * ~ lexi hale <lexi@hale.su> * define flags so we can reason about * our environment. */ #if (KVos == lin) ||\ (KVos == fbsd) ||\ (KVos == obsd) ||\ (KVos == nbsd) ||\ (KVos == dar) ||\ (KVos == and) # define KFenv_unix #endif #if defined(KFenv_unix) ||\ (KVos == hai) ||\ (KVos == mgw) # define KFenv_posix #endif #define Kpragma(p) _Pragma(#p) #if defined(__GNUC__) || defined(__clang__) # define Kerror(msg) Kpragma(GCC error #msg) #else # define Kerror(msg) Kpragma(message #msg) #endif #define Knoimpl(fn,p) Kerror(no implementation of fn for platform p) |
Added kcore/old/def.lin.i version [0178d496a4].
> > |
1 2 |
#define KVos lin typedef unsigned char stat; |
Added kcore/old/def.win.i version [11ccc3c2e7].
> > |
1 2 |
#define KVos win typedef u32 stat; |
Added kcore/old/type.x86.32.i version [fe891b76db].
> > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#define KVarch x86 #define KVbits 32 typedef unsigned long sz; typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned long u32; typedef signed long s32; typedef u32 word; typedef s32 sword; |
Added kcore/old/type.x86.64.i version [03a8b8f372].
> > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#define KVarch x86 #define KVbits 64 typedef unsigned long long sz; typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned long u32; typedef signed long s32; typedef unsigned long long u64; typedef signed long long s64; typedef __uint128_t u128; typedef __int128_t s128; typedef u64 word; typedef s64 sword; |
Added kcore/stop.fn.c version [c4373dead4].
> > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* kcore/stop.fn.c - kstop() * ~ lexi hale <lexi@hale.su> * this file defines a function that prematurely exits from * a running libk program with an appropriate exit status. */ #include <k/core.h> #include <k/def.h> // so we know what system this is #include <k/type.h> #ifdef KFenv_posix # define STOPFN kio_posix_exit extern void STOPFN(int); #else Knoimpl(kstop) #endif noreturn void kstop (longstat code) { STOPFN(code); } |
Added kcore/testbin.exe.c version [f1bdb07ea2].
> > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <k/core.h> #include <k/mem.h> #include <k/io.h> #include <k/magic.h> kbad entry(kenv e) { const char msg[] = "hello from libk\n"; ksraw ptr = { Kmsz(msg), msg }; bool maybe = true; maybe = no; if (kiosend(e.std, ptr, null) == kiocond_ok) { return kbad_ok; } else { return kbad_io; } } |
Added kcore/type.h.m version [8b1f2e0cb2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
--- kcore/type.h.m → <k/def.h> --- ~ lexi hale <lexi@hale.su> --- this file gathers information on the environment it's --- being compiled in, defining types that our code --- needs. it will be emitted as <k/type.h>. --- vim: ft=c // arch bit length [atom_target_bits] --- make some gigantic fucking assumptions [if [atom_target_bits] >= 8] typedef unsigned char u8; typedef signed char s8; [if [atom_target_bits] >= 16] typedef unsigned short u16; typedef signed short s16; [if [atom_target_bits] >= 32] typedef unsigned long u32; typedef signed long s32; [if [atom_target_bits] >= 64] typedef unsigned long long u64; typedef signed long long s64; [if [atom_target_arch] == x86] #if defined(__GNUC__) || defined(__clang__) typedef __uint128_t u128; typedef __int128_t s128; #endif [endif] [endif] [endif] [endif] [endif] typedef u[atom_target_bits] sz; typedef s[atom_target_bits] ssz; --- make sure something unlikely doesn't happen [define [maxtype name, n]: [if [n] > [atom_target_bits]] typedef u[atom_target_bits] [name] [else] typedef u[n] [name] [endif]] // exit status integer types - pls use kbad in <k/magic.h> instead [if [target_posix] == yes] /* by convention, posix return values are 8-bit, * but note that many modern UNIXes do technically * support higher-bit values. for this reason, * longstat is defined differently under posix. */ typedef u8 stat; [maxtype longstat, 32]; [else] [if ([atom_target_os] == win) || ([atom_target_os] == vms)] [maxtype stat, 32] [else] typedef u8 stat; /* we don't know a specific exit status type * for your arch so we're going with a sane * default. if this is wrong, help us fix it! */ [endif] typedef stat longstat; [endif] |
Deleted kcore/type.x86.32.i version [fe891b76db].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#define KVarch x86 #define KVbits 32 typedef unsigned long sz; typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned long u32; typedef signed long s32; typedef u32 word; typedef s32 sword; |
< < < < < < < < < < < < < < |
Deleted kcore/type.x86.64.i version [03a8b8f372].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#define KVarch x86 #define KVbits 64 typedef unsigned long long sz; typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned long u32; typedef signed long s32; typedef unsigned long long u64; typedef signed long long s64; typedef __uint128_t u128; typedef __int128_t s128; typedef u64 word; typedef s64 sword; |
< < < < < < < < < < < < < < < < < < |
Added kio/send.c version [d88d1642fe].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
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 |
#include <k/io.h> #include <k/core.h> #include <k/def.h> /* send.c - kiosend() * ~ lexi hale <lexi@hale.su> * kiosend() writes to a channel with an open out stream */ // we define all platform functions here, // whether or not they're for the correct // platform - only the ones actually called // by the generated code will be linked extern sz kio_posix_fd_write(int fd, const char* buf, sz len); kiocond kiosend(kiochan target, ksraw string, sz* len) { # ifdef KFenv_posix sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size); if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors # else # if KVos == win # error windows IO send function not yet defined # else Knoimpl(kiosend,KVos); # error missing implementation // boring error for plebs # endif # endif if (len != null) *len = size; return kiocond_ok; } |
Modified libk.md from [3c28c4d693] to [65938a7892].
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
5. **intrinsic reentrancy.** because *jesus christ,* libc. 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. 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. ## 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. however, a common problem with libraries is the proliferation of inordinately long and hard-to-type function names such as `SuperWidget_Widget_Label_Font_Size_Set()`. this may be tolerable in IDEs with robust auto-complete or when referencing a highly-specific, sparsely-used library; it is however completely intolerable in the case of a core library with heavily used functionality. |
> > > > > > > > > > > > > |
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 |
5. **intrinsic reentrancy.** because *jesus christ,* libc. 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. 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 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 [gpp], 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. [gpp]: http://en.nothingisreal.com/wiki/GPP [GNU make]: http://www.gnu.org/software/make while gpp is a very small program that builds quickly and has no major dependencies of its own, it is an obscure program not likely to be found in any repositories and with an uncertain future. for these reasons, adding m4 translations of the gpp headers should be a long-term priority. being able to be built with both a very small, easily built macro processor, and a very large but extremely well-supported processor, should make libk maximally buildable and future-proof. while this project will include gpp tooling and GNU makefiles designed to ease the task of writing and building libk code (as well as tools in many other languages, including native binaries that compile against libk), none of them are required for the task. ## 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. however, a common problem with libraries is the proliferation of inordinately long and hard-to-type function names such as `SuperWidget_Widget_Label_Font_Size_Set()`. this may be tolerable in IDEs with robust auto-complete or when referencing a highly-specific, sparsely-used library; it is however completely intolerable in the case of a core library with heavily used functionality. |
Modified makefile from [ac03aab83b] to [d63468c69f].
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
|
export OUT = $(PWD)/out export ARCH = x86 export OS = lin export BITS = 64 export TMP = $(PWD)/tmp export TARGET = $(ARCH).$(OS).$(BITS) export lin-headers = /usr/include/asm export fbsd-headers = /usr/include/sys 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),$(addprefix $(OUT)/$(dir).,$(notdir $(wildcard $(dir)/$1))))) cfnsources = $(call collect,*.fn.c) sfnsources = $(call collect,*.fn.${TARGET}.s) crtsources = $(call collect,*.rt.c) srtsources = $(call collect,*.rt.${TARGET}.s) fnsources = $(cfnsources) $(sfnsources) rtsources = $(crtsources) $(srtsources) sources = $(fnsources) $(rtsources) cfnobjects = $(cfnsources:%.c=%.o) sfnobjects = $(sfnsources:%.s=%.o) crtobjects = $(crtsources:%.c=%.o) srtobjects = $(srtsources:%.s=%.o) fnobjects = $(cfnobjects) $(sfnobjects) rtobjects = $(crtobjects) $(srtobjects) objects = $(fnobjects) $(rtobjects) header-dir = /usr/include lib-dir = /usr/lib posix-oses = lin fbsd dar and hai mgw ifeq ($(findstring $(OS),$(posix-oses)),$(OS)) export POSIX = yes else export POSIX = no 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)/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 cfnobjects sfnobjects crtobjects srtobjects rtobjects binaries binmods POSIX dbg: @echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))") %.obj: %/makefile ${TARGET}.calls $(OUT) cd $* && $(MAKE) obj %.tool: %/makefile $(OUT) cd $* && $(MAKE) tool %.dbg: %/makefile $(OUT) cd $* && $(MAKE) dbg %.def: %/makefile $(OUT) $(OUT)/k cd $* && $(MAKE) def %.calls: arch/makefile cd arch && $(MAKE) $(TMP)/calls.$*.s $(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) $(OUT)/k: mkdir -p $@ |
>
>
|
>
>
>
>
|
|
>
|
|
|
>
|
<
<
|
|
|
|
<
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
>
|
|
|
|
|
|
|
>
>
>
|
|
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
127
128
129
130
|
export OUT = $(PWD)/out # TODO: calculate these using $(MAKE_HOST) export ARCH = x86 export OS = lin export BITS = 64 export TMP = $(PWD)/tmp ifneq ($(BITS),) export TARGET = $(ARCH).$(OS).$(BITS) else export TARGET = $(ARCH).$(OS) endif export gpp = gpp export lin-headers = /usr/include/asm export fbsd-headers = /usr/include/sys 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)) 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) 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 $(TMP)/precomp.g $(TARGET).calls $(OUT) cd $* && $(MAKE) obj %.tool: %/makefile $(TMP)/precomp.g $(OUT) cd $* && $(MAKE) tool %.dbg: %/makefile $(OUT) cd $* && $(MAKE) dbg %.def: %/makefile $(TMP)/precomp.g $(OUT) $(OUT)/k cd $* && $(MAKE) def %.calls: arch/makefile cd arch && $(MAKE) $(TMP)/calls.$*.s $(TMP)/precomp.g: grammar/precomp.g.gpp $(TMP) cd grammar && $(MAKE) $@ $(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) $(OUT)/k $(TMP): mkdir -p $@ |
Modified modmake from [3c50b488d5] to [eb2aedd9b1].
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
..
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
|
#- 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) bare = $(mod:k%=%) headers = $(wildcard *.h) $(gen-headers) tools = $(filter %.exe.c, $(src)) nontools = $(filter-out %.exe.c, $(src)) cobjects = $(filter %.c, $(nontools)) sobjects = $(filter %.${TARGET}.s, $(nontools)) cflags = -isystem ${OUT} -fPIC -nostdlib ${COMPLIB} -L${OUT} -lk 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 tools = $(tools) @echo TARGET = ${TARGET} @echo cobjects = $(cobjects) @echo sobjects = $(sobjects) @echo headers = $(headers) @echo mod = $(mod) ${OUT}/$(mod).%.o: %.c $(CC) $(cflags) -c $< -o $@ ${OUT}/k/%.h: %.h cp $< $@ ${OUT}/$(mod).%: %.exe.c $(CC) $(cflags) $< -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 ................................................................................ # 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: %.$(1).s # invoke with $(call arch,tuple). do not # put spaces between either term though! ifeq ($(debug),yes) yasm-flags = -gdwarf2 endif #-- 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. #${OUT}/$(mod).%.x86.lin.32.o: %.x86.lin.32.s $(call arch,x86.lin.32) yasm $(yasm-flags) -felf32 -i${TMP} $< -o $@ #${OUT}/$(mod).%.x86.lin.64.o: %.x86.lin.64.s $(call arch,x86.lin.64) yasm $(yasm-flags) -felf64 -i${TMP} $< -o $@ #-- 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) yasm -felf32 $< -o $@ brandelf -t FreeBSD $@ $(call arch,x86.fbsd.64) yasm -felf64 $< -o $@ brandelf -t FreeBSD $@ |
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>
>
<
>
|
|
|
>
>
>
>
>
|
<
>
|
|
|
|
>
>
>
>
>
>
>
|
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
..
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
127
128
129
130
131
132
133
|
#- 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)) gpp = gpp cflags = -std=c11 -isystem ${OUT} -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-grammar = $(file < ${TMP}/precomp.g) m-comp = $(gpp) $(m-grammar) $(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/%) 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-grammar = $(m-grammar) @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 ................................................................................ # 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 $@ |