diff options
| author | nodist <kevin.comas.git@gmail.com> | 2026-10-06 17:13:01 -0400 |
|---|---|---|
| committer | nodist <kevin.comas.git@gmail.com> | 2026-10-06 17:13:01 -0400 |
| commit | 7bd050ccf74222e1b659f2fd6826a86e6afbcc94 (patch) | |
| tree | 30bae9ca5dd110f32cd4abb10d42ea4d872b4d82 | |
| parent | de65adbc1b2d1b3efdbe6a023bb7435f84b2f3a7 (diff) | |
basic tests
| -rw-r--r-- | README | 8 | ||||
| -rw-r--r-- | include/README | 12 | ||||
| -rw-r--r-- | include/kpl.h | 9 | ||||
| -rw-r--r-- | include/kpl/base.h | 33 | ||||
| -rw-r--r-- | include/kpl/class.h | 34 | ||||
| -rw-r--r-- | include/kpl/color.h | 120 | ||||
| -rw-r--r-- | include/kpl/object.h | 33 | ||||
| -rw-r--r-- | include/kpl/runtime.h | 52 | ||||
| -rw-r--r-- | include/kpl/tree.h | 61 | ||||
| -rw-r--r-- | include/kpl_test.h | 69 | ||||
| -rw-r--r-- | source/README | 9 | ||||
| -rw-r--r-- | source/kpl.c | 11 | ||||
| -rw-r--r-- | source/tree.c | 37 | ||||
| -rw-r--r-- | test/README | 31 | ||||
| -rw-r--r-- | test/test.c | 77 | ||||
| -rwxr-xr-x | vm.sh | 2 |
16 files changed, 597 insertions, 1 deletions
@@ -26,6 +26,14 @@ Running: Testing: +./kpl_test # Run all tests + +./kpl_test NAME1... # Run test by test name + +--- + +Cross Architecture Testing: + See TESTING --- diff --git a/include/README b/include/README new file mode 100644 index 0000000..6800f87 --- /dev/null +++ b/include/README @@ -0,0 +1,12 @@ +Header Files + +--- + +Includes: + +Only include one of these files in the source + +kpl.h # For the main kpl application +kpl_test.h # For Testing + +--- diff --git a/include/kpl.h b/include/kpl.h new file mode 100644 index 0000000..913edb7 --- /dev/null +++ b/include/kpl.h @@ -0,0 +1,9 @@ +/* + * This is the only header included in any c source file + */ + +#pragma once + +#include "kpl/runtime.h" + +#define KPL_VERSION "0.0.0" diff --git a/include/kpl/base.h b/include/kpl/base.h new file mode 100644 index 0000000..144fd51 --- /dev/null +++ b/include/kpl/base.h @@ -0,0 +1,33 @@ +/* + * The header for headers included in kpl.h + */ + +#pragma once + +// System includes +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <ctype.h> +#include <pthread.h> +#include <semaphore.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/uio.h> +#include <linux/fs.h> +#include <linux/io_uring.h> +// KPL includes +#include "color.h" +#include "class.h" +#include "object.h" +#include "tree.h" + +typedef enum : int32_t { + KPL_EXIT_CODE_SUCCESS = 0, + KPL_EXIT_CODE_ERROR = 1 +} kpl_exit_code; diff --git a/include/kpl/class.h b/include/kpl/class.h new file mode 100644 index 0000000..b1b7054 --- /dev/null +++ b/include/kpl/class.h @@ -0,0 +1,34 @@ +/* + * The kpl class a 64bit value with an table of functions + */ + +typedef uint8_t kpl_utf8[4]; + +typedef union { + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + kpl_utf8 utf8; + float f32; + double f64; + void *ptr; +} kpl_value; + +typedef struct { + kpl_value value; + int64_t tag; +} kpl_result; + +typedef struct { +// TODO KPL INTERFACE +} kpl_interface; + +typedef struct { + kpl_value value; + kpl_interface *interface; +} kpl_class; diff --git a/include/kpl/color.h b/include/kpl/color.h new file mode 100644 index 0000000..dc7fe20 --- /dev/null +++ b/include/kpl/color.h @@ -0,0 +1,120 @@ +/* + * Colors for pretty printing + */ + +#pragma once + +#define KPL_COLOR_CONCAT(COLOR) KPL_COLOR_ ## COLOR + +#ifndef KPL_COLOR_OFF + +#define KPL_COLOR(A) "\e[" KPL_COLOR_CONCAT(A) "m" +#define KPL_COLOR2(A, B) "\e[" KPL_COLOR_CONCAT(A) ";" KPL_COLOR_CONCAT(B) "m" +#define KPL_COLOR3(A, B, C) "\e[" KPL_COLOR_CONCAT(A) ";" KPL_COLOR_CONCAT(B) ";" KPL_COLOR_CONCAT(C) "m" + +#define KPL_COLOR_RESET "0" +#define KPL_COLOR_BOLD "1" +#define KPL_COLOR_FAINT "2" +#define KPL_COLOR_ITALIC "3" +#define KPL_COLOR_UNDERLINE "4" +#define KPL_COLOR_BLINK "5" +#define KPL_COLOR_REVERSE "7" +#define KPL_COLOR_HIDDEN "8" +#define KPL_COLOR_RESET_BOLD "21" +#define KPL_COLOR_RESET_FAINT "22" +#define KPL_COLOR_RESET_ITALIC "23" +#define KPL_COLOR_RESET_UNDERLINE "24" +#define KPL_COLOR_RESET_BLINK "25" +#define KPL_COLOR_RESET_REVERSE "27" +#define KPL_COLOR_RESET_HIDDEN "28" +#define KPL_COLOR_BLACK "30" +#define KPL_COLOR_RED "31" +#define KPL_COLOR_GREEN "32" +#define KPL_COLOR_YELLOW "33" +#define KPL_COLOR_BLUE "34" +#define KPL_COLOR_MAGENTA "35" +#define KPL_COLOR_CYAN "36" +#define KPL_COLOR_GREY "37" +#define KPL_COLOR_DEFAULT "39" +#define KPL_COLOR_BG_BLACK "30" +#define KPL_COLOR_BG_RED "41" +#define KPL_COLOR_BG_GREEN "42" +#define KPL_COLOR_BG_YELLOW "43" +#define KPL_COLOR_BG_BLUE "44" +#define KPL_COLOR_BG_MAGENTA "45" +#define KPL_COLOR_BG_CYAN "46" +#define KPL_COLOR_BG_GREY "47" +#define KPL_COLOR_DARK_GREY "90" +#define KPL_COLOR_LIGHT_RED "91" +#define KPL_COLOR_LIGHT_GREEN "92" +#define KPL_COLOR_LIGHT_YELLOW "93" +#define KPL_COLOR_LIGHT_BLUE "94" +#define KPL_COLOR_LIGHT_MAGENTA "95" +#define KPL_COLOR_LIGHT_CYAN "96" +#define KPL_COLOR_WHITE "97" +#define KPL_COLOR_BG_DARK_GREY "100" +#define KPL_COLOR_BG_LIGHT_RED "101" +#define KPL_COLOR_BG_LIGHT_GREEN "102" +#define KPL_COLOR_BG_LIGHT_YELLOW "103" +#define KPL_COLOR_BG_LIGHT_BLUE "104" +#define KPL_COLOR_BG_LIGHT_MAGENTA "105" +#define KPL_COLOR_BG_LIGHT_CYAN "106" +#define KPL_COLOR_BG_WHITE "107" + +#else + +#define KPL_COLOR(A) KPL_COLOR_CONCAT(A) +#define KPL_COLOR2(A, B) KPL_COLOR_CONCAT(A) KPL_COLOR_CONCAT(B) +#define KPL_COLOR3(A, B, C) KPL_COLOR_CONCAT(A) KPL_COLOR_CONCAT(B) KPL_COLOR_CONCAT(C) + + +#define KPL_COLOR_RESET "" +#define KPL_COLOR_BOLD "" +#define KPL_COLOR_FAINT "" +#define KPL_COLOR_ITALIC "" +#define KPL_COLOR_UNDERLINE "" +#define KPL_COLOR_BLINK "" +#define KPL_COLOR_REVERSE "" +#define KPL_COLOR_HIDDEN "" +#define KPL_COLOR_RESET_BOLD "" +#define KPL_COLOR_RESET_FAINT "" +#define KPL_COLOR_RESET_ITALIC "" +#define KPL_COLOR_RESET_UNDERLINE "" +#define KPL_COLOR_RESET_BLINK "" +#define KPL_COLOR_RESET_REVERSE "" +#define KPL_COLOR_RESET_HIDDEN "" +#define KPL_COLOR_BLACK "" +#define KPL_COLOR_RED "" +#define KPL_COLOR_GREEN "" +#define KPL_COLOR_YELLOW "" +#define KPL_COLOR_BLUE "" +#define KPL_COLOR_MAGENTA "" +#define KPL_COLOR_CYAN "" +#define KPL_COLOR_GREY "" +#define KPL_COLOR_DEFAULT "" +#define KPL_COLOR_BG_BLACK "" +#define KPL_COLOR_BG_RED "" +#define KPL_COLOR_BG_GREEN "" +#define KPL_COLOR_BG_YELLOW "" +#define KPL_COLOR_BG_BLUE "" +#define KPL_COLOR_BG_MAGENTA "" +#define KPL_COLOR_BG_CYAN "" +#define KPL_COLOR_BG_GREY "" +#define KPL_COLOR_DARK_GREY "" +#define KPL_COLOR_LIGHT_RED "" +#define KPL_COLOR_LIGHT_GREEN "" +#define KPL_COLOR_LIGHT_YELLOW "" +#define KPL_COLOR_LIGHT_BLUE "" +#define KPL_COLOR_LIGHT_MAGENTA "" +#define KPL_COLOR_LIGHT_CYAN "" +#define KPL_COLOR_WHITE "" +#define KPL_COLOR_BG_DARK_GREY "" +#define KPL_COLOR_BG_LIGHT_RED "" +#define KPL_COLOR_BG_LIGHT_GREEN "" +#define KPL_COLOR_BG_LIGHT_YELLOW "" +#define KPL_COLOR_BG_LIGHT_BLUE "" +#define KPL_COLOR_BG_LIGHT_MAGENTA "" +#define KPL_COLOR_BG_LIGHT_CYAN "" +#define KPL_COLOR_BG_WHITE "" + +#endif diff --git a/include/kpl/object.h b/include/kpl/object.h new file mode 100644 index 0000000..0f54a5e --- /dev/null +++ b/include/kpl/object.h @@ -0,0 +1,33 @@ +/* + * KPL specific objects + */ + +#pragma once + +// for atomic linked list queue +// size in bytes, index on the kpl_threads array +#define KPL_OBJECT_HEADER(STRUCT_NAME) \ + struct STRUCT_NAME *_Atomic queue_next; \ + int32_t obj_size, thread_id + +typedef struct _kpl_object { + KPL_OBJECT_HEADER(_kpl_object); +} kpl_object; // all kpl objects allocated by the kpl allocator extend this header + +typedef struct { + kpl_object *_Atomic head, *tail; // head is modified with atomic exchange + struct { + kpl_object *_Atomic queue_next; + } dummy; // head and tail are never null will always point to this +} kpl_object_queue; // atomic linked list queue any thread can add, only owner thread can remove + +typedef struct _kpl_task kpl_task; + +typedef struct _kpl_env kpl_env; + +typedef void kpl_task_fn(kpl_task *task, kpl_env *env); + +typedef struct _kpl_task { + KPL_OBJECT_HEADER(_kpl_task); + // TODO +} kpl_task; diff --git a/include/kpl/runtime.h b/include/kpl/runtime.h new file mode 100644 index 0000000..2adf402 --- /dev/null +++ b/include/kpl/runtime.h @@ -0,0 +1,52 @@ +/* + * KPL allocators, io and threading + */ + +#pragma once + +#include "base.h" + +typedef enum : uint8_t { + KPL_MEMORY_ALLOCATOR_MIN_POW2 = 7, + KPL_MEMORY_ALLOCATOR_MAX_POW2 = 30 +} kpl_memory_allocator_enum; + +/* + * All allocations are rounded to the next power of two at lest to a min or error if over max + * Each power of two has a bucket in the memory pool for reuse + */ +typedef struct { +// TODO MEMORY ALLOCATOR +} kpl_memory_allocator; + +typedef enum : uint8_t { + KPL_MEMORY_POOL_COUNT = 31 +} kpl_memory_pool_enum; + +// TODO IO URING + +// TODO JIT ALLOCATOR + +typedef struct { + kpl_memory_allocator allocator; + kpl_object_queue memory_pools[KPL_MEMORY_POOL_COUNT]; // each index represents 2 ** INDEX size in bytes + // TODO io_uring + // TODO jit allocator + _Atomic ssize_t priority; // running + the total number of tasks in threads queue, lower is higher priority + kpl_object_queue task_queue; + pthread_t pthread; // not used for main thread + sem_t sem; // wait when no task queue and io queue is empty +} kpl_thread; + +typedef enum : int32_t { + KPL_THREAD_DETERIMINE_COUNT = -1, + KPL_THREAD_MAIN_ID = 0 +} kpl_thread_enum; + +typedef struct _kpl_env { + int32_t thread_count; // -1 updates this value to max possible, 0 invalid, >= 1 for specific number + _Atomic ssize_t total_priority; // the sum of the threads priority fields, application stops on zero + kpl_thread *thread_array; // 0 is main thread, >= 1 are spawned pthreads + kpl_tree *namespace_tree, *module_tree; // *namespace_tree lookups are thread safe, *module_tree needs mutex + pthread_mutex_t module_tree_mutex; +} kpl_env; // kpl state, no globals diff --git a/include/kpl/tree.h b/include/kpl/tree.h new file mode 100644 index 0000000..8e52524 --- /dev/null +++ b/include/kpl/tree.h @@ -0,0 +1,61 @@ +/* + * KPL tree + */ + +#pragma once + +// tree_duplicate is a linked stack +#define KPL_TREE_HEADER(STRUCT_NAME) \ + struct STRUCT_NAME *tree_left, *tree_right, *tree_duplicate; \ + int32_t tree_height + +/* + * Recursive AVL saves 8 bytes per object (no need for parent pointer) and keeps the insertion and finding simple + */ +typedef struct _kpl_tree_node { + KPL_TREE_HEADER(_kpl_tree_node); +} kpl_tree_node; + +typedef enum : int32_t { + KPL_TREE_TREE_HEIGHT_INIT = 1 +} kpl_tree_enum; + +/* + * -1 search left, 1 search right, 0 found + */ +typedef int32_t kpl_tree_node_compare_fn(const void *node_a, const void *node_b); + +typedef void kpl_tree_node_free_fn(void *node); + +/* + * KPL needs tree with insertion and find operations, deletion is not needed, all nodes are freed on tree free + */ +typedef struct { + kpl_tree_node *root_node; + kpl_tree_node_compare_fn *node_compare_fn; + kpl_tree_node_free_fn *node_free_fn; +} kpl_tree; + +#define KPL_TREE_INIT_STATIC(COMPARE_FN, FREE_FN) \ + (kpl_tree) { .root_node = NULL, .node_compare_fn = COMPARE_FN, .node_free_fn = FREE_FN } + +inline void kpl_tree_init(kpl_tree *tree, kpl_tree_node_compare_fn node_compare_fn, + kpl_tree_node_free_fn node_free_fn) { + tree->root_node = NULL; + tree->node_compare_fn = node_compare_fn; + tree->node_free_fn = node_free_fn; +} + +void kpl_tree_free(kpl_tree *tree); + +/* + * *find is stack allocated + * NULL for not found + */ +void *kpl_tree_find(kpl_tree *tree, const void *find_node); + +/* + * *insert is heap allocated + * All inserts succeed, duplicates are added to *tree_duplicate + */ +void kpl_tree_insert(kpl_tree *tree, void *insert_node); diff --git a/include/kpl_test.h b/include/kpl_test.h new file mode 100644 index 0000000..a656761 --- /dev/null +++ b/include/kpl_test.h @@ -0,0 +1,69 @@ +/* + * This is the only header included in any c test file + */ + +#pragma once + +#include "kpl.h" + +typedef enum : int32_t { + KPL_TEST_ERROR_LINE_NUMBER_INIT = -1, +} kpl_test_enum; + +typedef struct _kpl_test kpl_test; + +typedef void kpl_test_fn(__attribute__((unused)) kpl_test *_test); + +/* + * The kpl_test object is used to build a static singly linked list and a static tree + * The list is for running all tests and moving failed tests to an error linked list + * The tree is used for running tests by name + */ +typedef struct _kpl_test { + KPL_TREE_HEADER(_kpl_test); + int32_t error_line_number; // -1 line number for no error + struct _kpl_test *list_next; + const char *source_file, *name, *error_message; // static c strings only + kpl_test_fn *test_fn; +} kpl_test; // Per test object, lists and trees are globals + +void _kpl_test_add(kpl_test *_test); // do not call outside KPL_TEST macro + +#define _KPL_TEST_FN_DEFINITION(NAME) static void NAME(__attribute__((unused)) kpl_test *_test) + +/* + * Each test is a static function added to the test list and tree by a static gnu constructor function + * The NAME becomes the function name _NAME becomes the constructor name, only one name can be used per file + */ +#define KPL_TEST(NAME) _KPL_TEST_FN_DEFINITION(NAME); \ +static void __attribute__((constructor)) _ ## NAME(void) { \ + static kpl_test _test = { \ + .tree_left = NULL, .tree_right = NULL, .tree_duplicate = NULL, \ + .tree_height = KPL_TREE_TREE_HEIGHT_INIT, \ + .error_line_number = KPL_TEST_ERROR_LINE_NUMBER_INIT, \ + .list_next = NULL, \ + .source_file = __FILE__, .name = #NAME, .error_message = NULL, \ + .test_fn = NAME \ + }; \ + _kpl_test_add(&_test); \ +} \ +_KPL_TEST_FN_DEFINITION(NAME) + +/* + * MESSAGE is a static c string, sets the error fields in a test once, aborting the rest of test + * Can only be called within a KPL_TEST + */ +#define KPL_FAIL(MESSAGE) do { \ + _test->error_line_number = __LINE__; \ + _test->error_message = MESSAGE; \ + return; \ +} while (0) + +/* + * CONDITION is statement evaluating to true or false, MESSAGE is a static c string, false invokes KPL_FAIL + * Can only be called within KPL_TEST + */ +#define KPL_ASSERT(CONDITION, MESSAGE) do { \ + if (!(CONDITION)) \ + KPL_FAIL(#CONDITION "; " MESSAGE); \ +} while (0) diff --git a/source/README b/source/README new file mode 100644 index 0000000..016daa8 --- /dev/null +++ b/source/README @@ -0,0 +1,9 @@ +Source Files + +--- + +Compiler Flags + +KPL_COLOR_OFF # Turn off internal pretty printing, does not effect source file pretty printing + +--- diff --git a/source/kpl.c b/source/kpl.c new file mode 100644 index 0000000..55ca994 --- /dev/null +++ b/source/kpl.c @@ -0,0 +1,11 @@ +/* + * Core kpl functions and entry point + */ + +#include "kpl.h" + +#ifdef KPL_MAIN +int32_t main(void) { + return 0; +} +#endif diff --git a/source/tree.c b/source/tree.c new file mode 100644 index 0000000..dcae485 --- /dev/null +++ b/source/tree.c @@ -0,0 +1,37 @@ + +#include "kpl.h" + +extern inline void kpl_tree_init(kpl_tree *tree, kpl_tree_node_compare_fn node_compare_fn, + kpl_tree_node_free_fn node_free_fn); + +static void kpl_tree_free_helper(kpl_tree_node *node, kpl_tree_node_free_fn node_free_fn) { + if (node->tree_left) + kpl_tree_free_helper(node->tree_left, node_free_fn); + if (node->tree_right) + kpl_tree_free_helper(node->tree_right, node_free_fn); + node_free_fn(node); +} + +void kpl_tree_free(kpl_tree *tree) { + kpl_tree_free_helper(tree->root_node, tree->node_free_fn); +} + +static void *kpl_tree_find_helper(kpl_tree_node *root_node, const void *find_node, + kpl_tree_node_compare_fn compare_fn) { + if (!root_node) + return NULL; + int32_t compare = compare_fn(root_node, find_node); + if (compare < 0) + return kpl_tree_find_helper(root_node->tree_left, find_node, compare_fn); + if (compare > 0) + return kpl_tree_find_helper(root_node->tree_right, find_node, compare_fn); + return root_node; +} + +void *kpl_tree_find(kpl_tree *tree, const void *find_node) { + return kpl_tree_find_helper(tree->root_node, find_node, tree->node_compare_fn); +} + +void kpl_tree_insert(kpl_tree *tree, void *insert_node) { + // TODO +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..4ef67e0 --- /dev/null +++ b/test/README @@ -0,0 +1,31 @@ +Test Files + +--- + +Testing: + +Each test is a function wrapped in a macro + +KPL_TEST(my_test) { + // code here +} + +Each test passes by default + +--- + +Testing Macros: + +The testing framework provides two macros KPL_ASSERT and KPL_FAIL + +Both macros can only be used inside a KPL_TEST function + +Asserting: + +KPL_ASSSERT(condition, "Fail Message"); + +--- + +Failing: + +KPL_FAIL("The test failed"); diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..6cede92 --- /dev/null +++ b/test/test.c @@ -0,0 +1,77 @@ + +#include "kpl_test.h" + +static int32_t kpl_test_tree_compare(const void *node_a, const void *node_b) { + const kpl_test *test_a = node_a, *test_b = node_b; + return strcmp(test_a->name, test_b->name); +} + +static kpl_tree test_tree = KPL_TREE_INIT_STATIC(kpl_test_tree_compare, NULL); + +static kpl_test *test_head = NULL, *test_tail = NULL, *error_head = NULL, *error_tail = NULL; + +void _kpl_test_add(kpl_test *_test) { + if (!test_head) + test_head = test_tail = _test; + else + test_tail = test_tail->list_next = _test; + kpl_tree_insert(&test_tree, _test); +} + +static void kpl_test_report(const kpl_test *_test) { + printf(KPL_COLOR(BOLD) "%s" KPL_COLOR(RESET) ":" KPL_COLOR(LIGHT_CYAN) "%s" KPL_COLOR(RESET), + _test->source_file, _test->name); + if (_test->error_line_number == KPL_TEST_ERROR_LINE_NUMBER_INIT) { + printf(KPL_COLOR(LIGHT_GREEN) " PASS\n" KPL_COLOR(RESET)); + return; + } + printf("::" KPL_COLOR(LIGHT_MAGENTA) "%d" KPL_COLOR(RESET) KPL_COLOR(LIGHT_RED) " %s\n" KPL_COLOR(RESET), + _test->error_line_number, _test->error_message); +} + +static int32_t kpl_test_report_error(void) { + if (!error_head) { + printf(KPL_COLOR2(BOLD, GREEN) "PASSED\n" KPL_COLOR(RESET)); + return KPL_EXIT_CODE_SUCCESS; + } + printf(KPL_COLOR2(BOLD, RED) "FAILED\n" KPL_COLOR(RESET)); + while (error_head) { + kpl_test *_test = error_head; + error_head = error_head->list_next; + kpl_test_report(_test); + } + return KPL_EXIT_CODE_ERROR; +} + +static void kpl_test_run_one(kpl_test *_test) { + _test->list_next = NULL; + _test->test_fn(_test); + kpl_test_report(_test); + if (_test->error_line_number == KPL_TEST_ERROR_LINE_NUMBER_INIT) + return; + if (!error_head) + error_head = error_tail = _test; + else + error_tail = error_tail->list_next = _test; +} + +static int32_t kpl_test_run_all(void) { + while (test_head) { + kpl_test *_test = test_head; + test_head = test_head->list_next; + kpl_test_run_one(_test); + } + return kpl_test_report_error(); +} + +int32_t main(int32_t argc, char *argv[]) { + if (argc < 2) + return kpl_test_run_all(); + // TODO run by name + return kpl_test_report_error(); +} + +KPL_TEST(pass_by_default) { + // pass, uncomment below to fail + // KPL_FAIL("example fail"); +} @@ -12,7 +12,7 @@ CORES="2" MEMORY="2G" DEVICE="virtio-net-pci,netdev=net0" HDA_URL="https://cloud.debian.org/images/cloud/trixie/latest" -TEST_COMMAND="make kpl_test && arch && ./kpl_test -a" +TEST_COMMAND="make kpl_test && arch && ./kpl_test" CLEAN_COMMAND="make clean; find -type f -regex '^.*\.[ch]' -exec rm -v {} \;" X64="X64" A64="A64" |
