diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..29bcbd1 --- /dev/null +++ b/TODO.md @@ -0,0 +1,78 @@ +## cbuild logic description ++ verify cbuild version ++ foreach dep in import + + if dep starts with "./" + + import local file + + else + + if find(dep in ./cbuild) + + else if find (dep in global_config_dir/**) + + else error: "import target 'dep' not found, try 'fluzm find dep'" ++ apply proj settings ++ apply platform settings ++ apply configuration settings + + apply platform settings ++ foreach task in tasks + + apply platform settings + + foreach tool in tool_order + + apply task settings + + foreach src in find(dir, langs) + + if platform, settings, src or src_deps (included headers) were changed + + src -> src_to_process + + if parallel + + foreach src in src_to_process + + run tool on src + + else + + run tool on src_to_process ++ copy files to general_out_dir + +## Example of project.dtsod: +```yml +cbuild_version: 0; +import: [ "c", "c++", "gcc", "./some_local_file.dtsod" ]; + +gcc: { + src_languages: [ "c" ], + src_dirs: [ "src" ], +}; + +configurations: { + release: { + preprocess_sources: { + src_languages: [ "c", "c++" ], + src_dirs: [ "src" ], + }, + gcc: { + pre_args: [ "-O2" ], + post_args: [ "-Wl,--gc-sections" ], + }; + }; +} + +tasks: { + exe: { + pre_tasks: [ ], + tool_order: [ "preprocess_sources", "gcc", "g++", "g++-link" ], + g++: [ ... ], + }; +}; + +languages: [ + { + aliases: [ "c" ], + file_extensions: [ "c" ], + }, + { + aliases: [ "c-header" ], + file_extensions: [ "h" ], + } +]; + +tools: [ + { + aliases: [ "gcc" ], + exe_file: [ "gcc" ], + supported_languages: [ "c" ]; # set to "any" to use with any lang + parallel: true, + } +]; +``` diff --git a/build.sh b/build.sh index cead1a7..acf2352 100644 --- a/build.sh +++ b/build.sh @@ -1,6 +1,7 @@ #!/bin/bash set -eo pipefail +CONFIG_DIR="/etc/cbuild" CMP="gcc" WARN="-Wall -Wextra -Wno-discarded-qualifiers -Wno-unused-parameter" ARGS="-O2 -flto -fdata-sections -ffunction-sections -Wl,--gc-sections" @@ -10,7 +11,7 @@ OS="$(./detect_os.sh)" ARCH="$(./detect_arch.sh)" LINK="-Lkerep/bin -lkerep-$OS-$ARCH" -if [[ OS -eq "windows" ]]; then +if [ "$OS" = "windows" ]; then OUT_FILE="cbuild.exe" else OUT_FILE="cbuild" @@ -18,7 +19,7 @@ fi command="$CMP $ARGS $WARN - -DOS=\"$OS\" -DARCH=\"$ARCH\" + -DOS=\"$OS\" -DARCH=\"$ARCH\" -DCONFIG_DIR=\"$CONFIG_DIR\" $SRC $LINK -o bin/$OUT_FILE" diff --git a/src/CompilationScenario.c b/src/CompilationScenario.c index df00b44..2360afa 100644 --- a/src/CompilationScenario.c +++ b/src/CompilationScenario.c @@ -1,47 +1,95 @@ +#include #include "CompilationScenario.h" -#include "unistd.h" + +kt_define(Language, NULL, NULL); +Autoarr_define(Language, false); +kt_define(Tool, NULL, NULL); +kt_define(CompilationScenario, (freeMembers_t)CompilationScenario_destruct, NULL); void CompilationScenario_construct(CompilationScenario* ptr){ - ptr->compiler = "UNDEFINED_COMPILER"; - ptr->obj_dir = "obj"; - ptr->out_file = "bin/out"; - ptr->args = Autoarr_create(Pointer, 32, 32); - ptr->sources = Autoarr_create(Pointer, 32, 32); + ptr->languages = Hashtable_create(); + ptr->tools = Hashtable_create(); + ptr->tool_order = Autoarr_create(Pointer, 32, 32); } void CompilationScenario_destruct(CompilationScenario* ptr){ - Autoarr_freeWithoutMembers(ptr->args, true); - Autoarr_freeWithoutMembers(ptr->sources, true); + // TODO } -#define Dtsod_setStrField(FIELD) \ +void Tool_construct(Tool* ptr, Autoarr(Pointer)* aliases, const char* exe_file, bool parallel, Autoarr(Language)* supported_languages){ + ptr->aliases = aliases; + ptr->exe_file = exe_file; + ptr->parallel = parallel; + ptr->supported_languages = Hashtable_create(); + Autoarr_foreach(supported_languages, l, + Language* l_copy = malloc(sizeof(Language)); + *l_copy = l; + Autoarr_foreach(l.aliases, l_name, + Hashtable_add(ptr->supported_languages, l_name, UniHeapPtr(Language, l_copy))); + ) + ptr->src_languages = Hashtable_create(); + ptr->src_dirs = Autoarr_create(Pointer, 32, 32); + ptr->pre_args = Autoarr_create(Pointer, 32, 32); + ptr->post_args = Autoarr_create(Pointer, 32, 32); +} + +void Tool_destruct(Tool* ptr){ + // TODO +} + +#define Dtsod_getStrField(FIELD, OBJ) \ if(Hashtable_tryGet(dtsod, #FIELD, &val)){ \ if(val.typeId != ktid_char_Ptr) \ safethrow(#FIELD " value expected to be string",;);\ - sc->FIELD = val.VoidPtr; \ + OBJ->FIELD = val.VoidPtr; \ } - -#define Dtsod_addArrField(FIELD, ELEM_TYPE) \ + +#define Dtsod_addToStrAr(FIELD, OBJ) \ if(Hashtable_tryGet(dtsod, #FIELD, &val)){ \ if(val.typeId != ktid_Autoarr_Unitype_Ptr) \ - safethrow(#FIELD " value expected to be array", ;); \ + safethrow(#FIELD " value expected to be a string array", ;); \ Autoarr(Unitype)* ar = val.VoidPtr; \ Autoarr_foreach(ar, el, \ - if(el.typeId != ktid_ptrName(ELEM_TYPE)) \ - safethrow(#FIELD " array values expected to be " #ELEM_TYPE, ;); \ - Autoarr_add(sc->FIELD, el.VoidPtr); \ + if(el.typeId != ktid_char_Ptr) \ + safethrow(#FIELD " array values expected to be string", ;); \ + Autoarr_add(OBJ->FIELD, el.VoidPtr); \ ) \ } -Maybe CompilationScenario_tryApplyOptions(CompilationScenario* sc, Hashtable* dtsod){ +Maybe Tool_tryApplyOptions(Tool* t, Hashtable* dtsod){ + Unitype val = UniNull; + Dtsod_addToStrAr(src_dirs, t); + Dtsod_addToStrAr(pre_args, t); + Dtsod_addToStrAr(post_args, t); + if(Hashtable_tryGet(dtsod, "src_languages", &val)){ \ + if(val.typeId != ktid_Autoarr_Unitype_Ptr) \ + safethrow("src_languages value expected to be a string array", ;); \ + Autoarr(Unitype)* ar = val.VoidPtr; + Autoarr_foreach(ar, el, + if(el.typeId != ktid_char_Ptr) + safethrow("src_languages array values expected to be string", ;); + const char* l_name = el.VoidPtr; + if(!Hashtable_tryGet(t->supported_languages, l_name, &val)) + safethrow(cptr_concat("language '", l_name, "' isn't supported by tool '", Autoarr_get(t->aliases, 0), "'"), ;); + Hashtable_add(t->src_languages, l_name, val); + ) + } + return MaybeNull; +} + +Maybe CompilationScenario_tryApplyToolsOptions(CompilationScenario* sc, Hashtable* dtsod){ Unitype val = UniNull; - Dtsod_setStrField(compiler); - Dtsod_setStrField(obj_dir); - Dtsod_setStrField(out_file); - Dtsod_addArrField(args, char); - Dtsod_addArrField(sources, char); try(CompilationScenario_tryApplyPlatformSpecificOptions(sc, dtsod), _m0, ;); + Hashtable_foreach(sc->tools, _tool, + Tool* tool = _tool.value.VoidPtr; + if(Hashtable_tryGet(dtsod, _tool.key, &val)){ + if(val.typeId != ktid_ptrName(Hashtable)) + safethrow(ERR_WRONGTYPE, ;); + Hashtable* tool_dtsod = val.VoidPtr; + try(Tool_tryApplyOptions(tool, tool_dtsod), _m1, ;); + } + ) return SUCCESS(UniBool(Unitype_isUniNull(val) || _m0.value.Bool)); } @@ -52,7 +100,7 @@ Maybe CompilationScenario_tryApplyConditionalOptions(CompilationScenario* sc, Ha if(val.typeId != ktid_Hashtable_Ptr) safethrow(cptr_concat(condition_name, " expected to be key-value map"), ;); Hashtable* conditional_options = val.VoidPtr; - try(CompilationScenario_tryApplyOptions(sc, conditional_options), _m0, ;); + try(CompilationScenario_tryApplyToolsOptions(sc, conditional_options), _m0, ;); return SUCCESS(UniTrue); } else return SUCCESS(UniFalse); @@ -77,6 +125,7 @@ Maybe CompilationScenario_applyConfigurationOptions(CompilationScenario* sc, Has try(CompilationScenario_tryApplyConditionalOptions(sc, dtsod, configuration), _m0, ;); if(!_m0.value.Bool) safethrow(cptr_concat("configuration '", configuration, "' not found"), ;); + return MaybeNull; } @@ -84,12 +133,17 @@ Maybe CompilationScenario_applyTaskOptions(CompilationScenario* sc, Hashtable* d try(CompilationScenario_tryApplyConditionalOptions(sc, dtsod, task), _m0, ;); if(!_m0.value.Bool) safethrow(cptr_concat("task '", task, "' not found"), ;); + return MaybeNull; } Maybe CompilationScenario_applyProjectOptions(CompilationScenario* sc, Hashtable* dtsod, const char* configuration, const char* task){ - // general options - try(CompilationScenario_tryApplyOptions(sc, dtsod), _m0, ;); + // TODO version check + // TODO import + // TODO register tools + // TODO register languagess + // project-wide options + try(CompilationScenario_tryApplyToolsOptions(sc, dtsod), _m0, ;); // configuration options try(CompilationScenario_applyConfigurationOptions(sc, dtsod, configuration), _m1, ;); // task options @@ -97,25 +151,6 @@ Maybe CompilationScenario_applyProjectOptions(CompilationScenario* sc, Hashtable return MaybeNull; } - -/* -universal compilation: - pre-compilation tools - parallel foreach src - apply proj settings - apply lang settings - apply dir settings - if platform, settings or src were changed - compile object to onj/lang - concurrent add obj to obj_ar - post-compilation tools - example: if linkage enabled - apply proj linker settings - link - post-link tools - move files to general_out_dir -*/ - Maybe CompilationScenario_exec(CompilationScenario* sc){ /*const char ** compiler_args; Autoarr_foreach(sc->sources, arg, diff --git a/src/CompilationScenario.h b/src/CompilationScenario.h index d4b7beb..a1a3ee9 100644 --- a/src/CompilationScenario.h +++ b/src/CompilationScenario.h @@ -3,14 +3,28 @@ extern const char* os; extern const char* arch; -typedef struct { - const char* language; - const char* compiler; - const char* obj_dir; - const char* out_file; - Autoarr(Pointer)* args; - Autoarr(Pointer)* sources; -} CompilationScenario; +STRUCT(Language, + Autoarr(Pointer)* aliases; + Autoarr(Pointer)* file_extensions; +) +Autoarr_declare(Language) + +STRUCT(Tool, + Autoarr(Pointer)* aliases; + const char* exe_file; + bool parallel; + Hashtable* supported_languages; + Hashtable* src_languages; + Autoarr(Pointer)* src_dirs; + Autoarr(Pointer)* pre_args; + Autoarr(Pointer)* post_args; +) + +STRUCT(CompilationScenario, + Hashtable* tools; /* Hashtable */ + Hashtable* languages; /* Hashtable */ + Autoarr(Pointer)* tool_order; +) /* Public Functions */ @@ -29,13 +43,15 @@ Maybe CompilationScenario_exec(CompilationScenario* sc); /* Internal Functions */ +/// tries to set options for tools registered in the project ///@return Maybe -Maybe CompilationScenario_tryApplyOptions(CompilationScenario* sc, Hashtable* dtsod); +Maybe CompilationScenario_tryApplyToolsOptions(CompilationScenario* sc, Hashtable* dtsod); +/// tries to get any options from field ///@return Maybe Maybe CompilationScenario_tryApplyConditionalOptions(CompilationScenario* sc, Hashtable* dtsod, const char* condition_name); -/// tries to get options from dtsod fields named "windows", "linux", "android", "x64", "android-arm32", "windows_x86", etc. +/// tries to get options from dtsod fields named "windowss", "linux", "android", "x64", "android-arm32", "windows_x86", etc. ///@return Maybe Maybe CompilationScenario_tryApplyPlatformSpecificOptions(CompilationScenario* sc, Hashtable* dtsod); diff --git a/src/cbuilld.c b/src/cbuilld.c index 8410add..99d044b 100644 --- a/src/cbuilld.c +++ b/src/cbuilld.c @@ -4,16 +4,21 @@ #include "CompilationScenario.h" #ifndef OS +#error undefined OS #define OS "UNDEFINED" #endif #ifndef ARCH +#error undefined ARCH #define ARCH "UNDEFINED" #endif - +#ifndef CONFIG_DIR +#error undefined CONFIG_DIR +#define CONFIG_DIR "UNDEFINED" +#endif const char* os=OS; const char* arch=ARCH; +const char* global_config_dir=CONFIG_DIR; -const char* global_out_dir="bin"; const char* configuration="release"; const char* project_dir_or_file="./"; Autoarr(Pointer)* tasks; @@ -39,9 +44,11 @@ int main(const int argc, const char** argv){ tasks = Autoarr_create(Pointer, 16, 32); if(cptr_equals(os, "UNDEFINED")) - throw("Operation system undefined. Recompile cbuild with flag -DOS=\\\"$(./detect_os.sh)\\\""); + throw("Undefined operation system. Recompile cbuild with flag -DOS=\\\"$(./detect_os.sh)\\\""); if(cptr_equals(arch, "UNDEFINED")) - throw("CPU architecture undefined. Recompile cbuild with flag -DARCH=\\\"$(./detect_arch.sh)\\\""); + throw("Undefined CPU architecture. Recompile cbuild with flag -DARCH=\\\"$(./detect_arch.sh)\\\""); + if(cptr_equals(global_config_dir, "UNDEFINED")) + throw("Undefined global config directory. Recompile cbuild with flag -DCONFIG_DIR=\\\"/etc/cbuild\\\""); for(int argi = 1; argi < argc; argi++){ const char* arg = argv[argi]; @@ -50,13 +57,10 @@ int main(const int argc, const char** argv){ kprintf("Usage: cbuild [options] [tasks0 task1...]\n" " Options:\n" " -h, --help, /? Display this message.\n" - " -o, --out-dir Set global output directory (default=bin).\n" " -c, --configuration Select project configuration (default=release).\n" " -p, --project Set project directory/file (default=./).\n"); return 0; } - else if(argIs("-o") || argIs("--out-dir")) - global_out_dir = argNext(); else if(argIs("-c") || argIs("--configuration")) configuration = argNext(); else if(argIs("-p") || argIs("--project"))