diff --git a/.gitignore b/.gitignore index 16aac0a..5324768 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ /pmake* *.o +/Makefile +/*.make /src/compiler/*.c /src/action/*.c /src/js/*.c diff --git a/GNUmakefile b/GNUmakefile index cf7fef6..ac01a47 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -13,6 +13,11 @@ ifeq ($(TARGET),NetBSD) UNIX = 1 endif +ifeq ($(TARGET),Windows) + MINGW = 1 + WINDOWS = 1 +endif + ### Stuff ifeq ($(UNIX),1) CC = gcc @@ -23,11 +28,22 @@ ifeq ($(UNIX),1) EXE = endif +ifeq ($(WINDOWS),1) + EXE = .exe +endif + +ifeq ($(MINGW),1) + CC = gcc + CFLAGS = -c + LDFLAGS = + LIBS = +endif + ### Common flags CFLAGS += -Iexternal/duktape -Iexternal/stb ### Rules -OBJS = src/main.o src/js.o +OBJS = src/main.o src/js.o src/js_console.o src/js_process.o src/js_fs.o OBJS += external/duktape/duktape.o external/stb/stb_ds.o NAME = rev | cut -d/ -f1 | rev | cut -d. -f1 @@ -85,5 +101,6 @@ pmake$(EXE): $(OBJS) $(CC) $(CFLAGS) -o $@ $< clean: + rm -f pmake pmake.exe find . -name "*.o" >/dev/null && rm -f $(shell find . -name "*.o") - rm -f src/compiler/*.c + rm -f src/compiler/*.c src/action/*.c src/js/*.c diff --git a/mk/js.mk b/mk/js.mk index 14dea5f..85d3ed2 100644 --- a/mk/js.mk +++ b/mk/js.mk @@ -6,10 +6,6 @@ OBJS += src/js/cmdline.o src/js/cmdline.c: src/js/cmdline.js xxd -njs_cmdline -i src/js/cmdline.js > src/js/cmdline.c -OBJS += src/action/gmake.o -src/action/gmake.c: src/action/gmake.js - xxd -naction_gmake -i src/action/gmake.js > src/action/gmake.c - OBJS += src/compiler/watcom.o src/compiler/watcom.c: src/compiler/watcom.js xxd -ncompiler_watcom -i src/compiler/watcom.js > src/compiler/watcom.c diff --git a/src/action/gmake.js b/src/action/gmake.js deleted file mode 100644 index 555b12b..0000000 --- a/src/action/gmake.js +++ /dev/null @@ -1,6 +0,0 @@ -const gmake = pmake.inherit(pmake.Action); - -gmake.target = "gmake"; -gmake.description = "GNU Make"; - -pmake.register(gmake); diff --git a/src/compiler/gcc.js b/src/compiler/gcc.js index 0ffa542..3cfbf8e 100644 --- a/src/compiler/gcc.js +++ b/src/compiler/gcc.js @@ -1,6 +1,8 @@ -const GCC = pmake.inherit(pmake.Compiler); +(function() { +const GCC = new pmake.POSIXCompiler(); GCC.target = "GCC"; GCC.description = "GCC/Clang"; pmake.register(GCC); +})(); diff --git a/src/compiler/watcom.js b/src/compiler/watcom.js index 3a987f9..dc90c11 100644 --- a/src/compiler/watcom.js +++ b/src/compiler/watcom.js @@ -1,6 +1,8 @@ -const Watcom = pmake.inherit(pmake.Compiler); +(function() { +const Watcom = new pmake.Compiler(); Watcom.target = "Watcom"; Watcom.description = "Open Watcom"; pmake.register(Watcom); +})(); diff --git a/src/config.h b/src/config.h index b41cac3..ead5407 100644 --- a/src/config.h +++ b/src/config.h @@ -5,8 +5,7 @@ X(watcom, compiler) \ X(gcc, compiler) -#define ACTIONS \ - X(gmake, action) +#define ACTIONS #define JS \ COMPILERS \ diff --git a/src/js.c b/src/js.c index 308fb7a..7aea3f6 100644 --- a/src/js.c +++ b/src/js.c @@ -4,12 +4,7 @@ duk_context* js_ctx; LOAD(js_core); LOAD(js_cmdline); - -static duk_ret_t js_console_log(duk_context* self) { - printf("%s\n", duk_to_string(self, 0)); - - return 0; -} +LOAD(js_end); static void js_argv_init(int argc, char** argv) { int arr; @@ -28,57 +23,15 @@ static void js_argv_init(int argc, char** argv) { duk_pop(js_ctx); } -static void js_console_init(void) { - int obj; - - duk_push_global_object(js_ctx); - obj = duk_push_object(js_ctx); - - duk_push_c_function(js_ctx, js_console_log, 1); - duk_put_prop_string(js_ctx, obj, "log"); - - duk_put_prop_string(js_ctx, 0, "console"); - - duk_pop(js_ctx); -} - -static duk_ret_t js_process_exit(duk_context* self) { - duk_idx_t argc = duk_get_top(self); - int ex; - - if(argc > 1) { - return duk_error(self, DUK_ERR_TYPE_ERROR, "needs 0 or 1 argument(s)"); - } - - if(argc == 1) { - ex = duk_to_number(self, 0); - } else { - ex = 0; - } - - exit(ex); -} - -static void js_process_init(void) { - int obj; - - duk_push_global_object(js_ctx); - obj = duk_push_object(js_ctx); - - duk_push_c_function(js_ctx, js_process_exit, DUK_VARARGS); - duk_put_prop_string(js_ctx, obj, "exit"); - - duk_put_prop_string(js_ctx, 0, "process"); - - duk_pop(js_ctx); -} - int js_init(int argc, char** argv) { + int st; + js_ctx = duk_create_heap_default(); js_argv_init(argc, argv); js_console_init(); js_process_init(); + js_fs_init(); if(duk_peval_lstring(js_ctx, js_core, js_core_len) != 0) { printf("error: js/core.js: %s\n", duk_safe_to_string(js_ctx, -1)); @@ -93,6 +46,8 @@ int js_init(int argc, char** argv) { JS; #undef X + if((st = js_run("pmake.js")) != 0) return st; + if(duk_peval_lstring(js_ctx, js_cmdline, js_cmdline_len) != 0) { printf("error: js/cmdline.js: %s\n", duk_safe_to_string(js_ctx, -1)); return 1; @@ -101,6 +56,38 @@ int js_init(int argc, char** argv) { return 0; } +int js_run(const char* file) { + FILE* f; + char* buffer; + int len; + + if((f = fopen(file, "rb")) == NULL) { + printf("No PMake script (pmake.js) found!\n"); + return 1; + } + + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + + buffer = malloc(len); + fread(buffer, 1, len, f); + + if(duk_peval_lstring(js_ctx, buffer, len) != 0) { + printf("error: %s: %s\n", file, duk_safe_to_string(js_ctx, -1)); + + free(buffer); + fclose(f); + + return 1; + } + + free(buffer); + fclose(f); + + return 0; +} + void js_uninit(void) { duk_destroy_heap(js_ctx); } diff --git a/src/js/cmdline.js b/src/js/cmdline.js index daee9a4..e74b5cd 100644 --- a/src/js/cmdline.js +++ b/src/js/cmdline.js @@ -1,5 +1,4 @@ -const PADDING = 16; -var action; +const PADDING = 24; for(var i = 1; i < ARGV.length; i++) { if(ARGV[i] == "--help") { @@ -7,10 +6,42 @@ for(var i = 1; i < ARGV.length; i++) { console.log("PMake " + pmake.VERSION + " - Pyrite's build script generator"); console.log(""); - console.log("Usage: " + ARGV[0] + " [options] action [arguments]"); + console.log("Usage: " + ARGV[0] + " [options]"); + + keys = Object.keys(pmake.options); + for(var i = 0; i < keys.length; i++) { + console.log(""); + console.log("OPTIONS - " + keys[i]); + + var keys2 = Object.keys(pmake.options[keys[i]]); + for(var j = 0; j < keys2.length; j++) { + const opt = pmake.options[keys[i]][keys2[j]]; + var arg = ""; + var opts = []; + + if(opt.option) { + arg = "=" + opt.option; + } + + console.log(" --" + keys2[j] + arg + " ".repeat(PADDING - keys2[j].length - 2 - arg.length) + opt.description); + if(!opt.options) { + } else if((typeof opt.options) == "function") { + opts = opt.options(); + } else { + opts = opt.options; + } + + if(opts.length > 0) { + for(var k = 0; k < opts.length; k++) { + console.log(" " + opts[k]); + } + console.log(""); + } + } + } + console.log(""); console.log("ACTIONS"); - keys = Object.keys(pmake.actions); for(var i = 0; i < keys.length; i++) { console.log(" " + keys[i] + " ".repeat(PADDING - keys[i].length) + pmake.actions[keys[i]].description); @@ -19,16 +50,34 @@ for(var i = 1; i < ARGV.length; i++) { } else if(ARGV[i].startsWith("--")) { console.log("Error: invalid option '" + ARGV[i].substr(2) + "'"); process.exit(1); - } else if(pmake.actions[ARGV[i]]) { - action = ARGV[i]; - break; - } else { - console.log("Error: no such action '" + ARGV[i] + "'"); - process.exit(1); } } -if(!action) { - console.log("Type '" + ARGV[0] + " --help' for help"); - process.exit(1); +(function(){ +function make(output){ + var mk = new pmake.File(output, "w"); + + mk.write("# This file was auto-generated. Do not edit manually!\n"); + mk.write("\n"); + mk.write("SILENT = @\n"); + mk.write("\n"); + + if(output == "Makefile"){ + var targets = pmake.resolveProjects(pmake.projects); + for(var i = 0; i < targets.length; i++){ + mk.write(targets[i].target + ":\n"); + mk.write(" @$(MAKE) -f " + targets[i].target + ".make\n"); + mk.write("\n"); + } + }else{ + } + + mk.close(); } + +make("Makefile"); +var targets = pmake.resolveProjects(pmake.projects); +for(var i = 0; i < targets.length; i++){ + make(targets[i].target + ".make"); +} +})(); diff --git a/src/js/core.js b/src/js/core.js index 60ea0c4..fe9c70d 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -1,11 +1,12 @@ const pmake = { VERSION : "0.0", - actions : {}, - compilers : {} + compilers : {}, + options : {}, + projects : [] }; -pmake.inherit = function(base) { - const func = function() {}; +pmake.inherit = function(base, call) { + const func = (function() {}); Object.setPrototypeOf(func.prototype, base.prototype); @@ -25,15 +26,77 @@ pmake.inherited = function(base, parent) { }; pmake.register = function(base) { - if(pmake.inherited(base, pmake.Compiler)) { + if(base instanceof pmake.Compiler) { pmake.compilers[base.target] = base; - } else if(pmake.inherited(base, pmake.Action)) { - pmake.actions[base.target] = base; + } else if(base instanceof pmake.Option) { + if(!pmake.options[base.category]) pmake.options[base.category] = {}; + + pmake.options[base.category][base.target] = base; + } else if(base instanceof pmake.Project) { + pmake.projects.push(base); } }; -pmake.Compiler = function() { +pmake.resolveProjects = function(arr){ + var r = []; + + for(var i = 0; i < arr.length; i++){ + if(arr[i] instanceof pmake.Project){ + r = r.concat(pmake.resolveProjects(arr[i].libraries)); + r.push(arr[i]); + } + } + + return r; }; -pmake.Action = function() { +(function() { +const Compiler = function() {}; + +const POSIXCompiler = pmake.inherit(Compiler); + +const Option = function() {}; + +const Project = function(target) { + this.target = target; + this.files = []; + this.libraries = []; }; + +Project.prototype.generate = function() { +}; + +const File = function(filename, mode) { + this.fp = fs.open(filename, mode); +}; + +File.prototype.write = function(string) { + fs.write(this.fp, string); +}; + +File.prototype.close = function() { + fs.close(this.fp); +}; + +pmake.Compiler = Compiler; +pmake.POSIXCompiler = POSIXCompiler; +pmake.Option = Option; +pmake.Project = Project; +pmake.File = File; +})(); + +/*** Option ***/ +(function() { +const Compiler = new pmake.Option(); + +Compiler.category = "General"; +Compiler.target = "compiler"; +Compiler.description = "Choose a compiler set; one of:"; +Compiler.option = "VALUE"; + +Compiler.options = function() { + return Object.keys(pmake.compilers); +}; + +pmake.register(Compiler); +})(); diff --git a/src/js_console.c b/src/js_console.c new file mode 100644 index 0000000..e24f8f4 --- /dev/null +++ b/src/js_console.c @@ -0,0 +1,21 @@ +#include "pmake.h" + +static duk_ret_t js_console_log(duk_context* self) { + printf("%s\n", duk_to_string(self, 0)); + + return 0; +} + +void js_console_init(void) { + int obj; + + duk_push_global_object(js_ctx); + obj = duk_push_object(js_ctx); + + duk_push_c_function(js_ctx, js_console_log, 1); + duk_put_prop_string(js_ctx, obj, "log"); + + duk_put_prop_string(js_ctx, 0, "console"); + + duk_pop(js_ctx); +} diff --git a/src/js_fs.c b/src/js_fs.c new file mode 100644 index 0000000..c1c4126 --- /dev/null +++ b/src/js_fs.c @@ -0,0 +1,119 @@ +#include "pmake.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +static duk_ret_t js_fs_glob(duk_context* self) { + int top = duk_get_top(self); + int i; + int arr = duk_push_array(self); + int c = 0; + + for(i = 0; i < top; i++) { +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + HANDLE h; + const char* p = duk_to_string(self, i); + + if((h = FindFirstFile(p, &ffd)) != INVALID_HANDLE_VALUE) { + do { + char* s = malloc(strlen(p) + 1 + strlen(ffd.cFileName) + 1); + char* l; + + strcpy(s, p); + + if((l = strchr(s, '*')) != NULL) { + l[0] = 0; + } + + if(s[strlen(s) - 1] == '/' || s[strlen(s) - 1] == '\\') { + } else if(strchr(p, '/') != NULL) { + strcat(s, "/"); + } else { + strcat(s, "\\"); + } + strcat(s, ffd.cFileName); + + duk_push_string(self, s); + duk_put_prop_index(self, arr, c); + c++; + + free(s); + } while(FindNextFile(h, &ffd) != 0); + + FindClose(h); + } +#else + glob_t g; + + if(glob(duk_to_string(self, i), 0, NULL, &g) == 0) { + int j; + + for(j = 0; j < g.gl_matchc; j++) { + duk_push_string(self, g.gl_pathv[j]); + duk_put_prop_index(self, arr, c); + c++; + } + + globfree(&g); + } +#endif + } + + return 1; +} + +static duk_ret_t js_fs_open(duk_context* self) { + const char* path = duk_to_string(self, 0); + const char* mode = duk_to_string(self, 1); + FILE* f = fopen(path, mode); + + if(f == NULL) return 0; + + duk_push_pointer(self, f); + + return 1; +} + +static duk_ret_t js_fs_write(duk_context* self) { + FILE* f = duk_to_pointer(self, 0); + const char* str = duk_to_string(self, 1); + + fwrite(str, 1, strlen(str), f); + + return 0; +} + +static duk_ret_t js_fs_close(duk_context* self) { + FILE* f = duk_to_pointer(self, 0); + + fclose(f); + + return 0; +} + +void js_fs_init(void) { + int obj; + + duk_push_global_object(js_ctx); + obj = duk_push_object(js_ctx); + + duk_push_c_function(js_ctx, js_fs_glob, DUK_VARARGS); + duk_put_prop_string(js_ctx, obj, "glob"); + + duk_push_c_function(js_ctx, js_fs_open, 2); + duk_put_prop_string(js_ctx, obj, "open"); + + duk_push_c_function(js_ctx, js_fs_write, 2); + duk_put_prop_string(js_ctx, obj, "write"); + + duk_push_c_function(js_ctx, js_fs_close, 1); + duk_put_prop_string(js_ctx, obj, "close"); + + duk_put_prop_string(js_ctx, 0, "fs"); + + duk_pop(js_ctx); +} diff --git a/src/js_process.c b/src/js_process.c new file mode 100644 index 0000000..0427d32 --- /dev/null +++ b/src/js_process.c @@ -0,0 +1,32 @@ +#include "pmake.h" + +static duk_ret_t js_process_exit(duk_context* self) { + duk_idx_t argc = duk_get_top(self); + int ex; + + if(argc > 1) { + return duk_error(self, DUK_ERR_TYPE_ERROR, "needs 0 or 1 argument(s)"); + } + + if(argc == 1) { + ex = duk_to_number(self, 0); + } else { + ex = 0; + } + + exit(ex); +} + +void js_process_init(void) { + int obj; + + duk_push_global_object(js_ctx); + obj = duk_push_object(js_ctx); + + duk_push_c_function(js_ctx, js_process_exit, DUK_VARARGS); + duk_put_prop_string(js_ctx, obj, "exit"); + + duk_put_prop_string(js_ctx, 0, "process"); + + duk_pop(js_ctx); +} diff --git a/src/main.c b/src/main.c index dc8e50a..c6a8f01 100644 --- a/src/main.c +++ b/src/main.c @@ -5,5 +5,7 @@ int main(int argc, char** argv) { if((st = js_init(argc, argv)) != 0) return st; + js_uninit(); + return 0; } diff --git a/src/pmake.h b/src/pmake.h index e23ad85..5659416 100644 --- a/src/pmake.h +++ b/src/pmake.h @@ -19,8 +19,14 @@ JS; #undef X /* js.c */ -extern duk_context* js_context; +extern duk_context* js_ctx; int js_init(int argc, char** argv); +int js_run(const char* file); void js_uninit(void); +/* js_*.c */ +void js_console_init(void); +void js_process_init(void); +void js_fs_init(void); + #endif