if(!Array.prototype.includes) { Array.prototype.includes = function(v) { for(var i = 0; i < this.length; i++) { if(this[i] == v) return true; } return false; }; } if(!Array.prototype.flat) { Array.prototype.flat = function() { const flat = function(acc, cur) { return acc.concat(cur); }; return this.reduce(flat, []); }; } const pmake = { VERSION : "0.0", compilers : {}, systems : {}, options : {}, options_category : {}, projects : [] }; pmake.inherit = function(base, call) { const func = (function() { base.apply(this, arguments); if(call) call.apply(this, arguments); }); Object.setPrototypeOf(func.prototype, base.prototype); return func; }; pmake.inherited = function(base, parent) { var proto = base.prototype; while(proto) { if(proto == parent.prototype) return true; proto = Object.getPrototypeOf(proto); } return false; }; pmake.register = function(target) { if(target instanceof pmake.Compiler) { pmake.compilers[target.target] = target; } else if(target instanceof pmake.System) { pmake.systems[target.target] = target; } else if(target instanceof pmake.Option) { if(!pmake.options_category[target.category]) pmake.options_category[target.category] = {}; pmake.options_category[target.category][target.target] = target; pmake.options[target.target] = target; } else if(target instanceof pmake.Project) { pmake.projects.push(target); } }; pmake.resolveProjects = function(arr, if_str) { var r = []; for(var i = 0; i < arr.length; i++) { var proj = arr[i]; function filter_project(x) { return x.target == proj; } if((typeof proj) == "string" && pmake.projects.filter(filter_project)[0]) { proj = pmake.projects.filter(filter_project)[0]; } if(proj instanceof pmake.Project) { r = r.concat(pmake.resolveProjects(proj.libraries, if_str)); r.push(proj); } else if((typeof proj) == "string" && if_str) { r.push(if_str(proj)); } } r = r.filter(function(item, pos) { return r.indexOf(item) == pos; }); return r; }; pmake.isCxx = function(src) { return src.endsWith(".cc") || src.endsWith(".cxx") || src.endsWith(".cpp"); }; pmake.pathTransform = function(target) { return function(x) { if(x.startsWith("/") || x.match(/^[A-Za-z]+:\//)) { return x; } else { return target.base + "/" + x; } }; }; pmake.includes = function(target) { function includes(x) { return x.includes.map(pmake.pathTransform(x)); } const targets = pmake.resolveProjects(target.libraries); return target.includes.concat(targets.map(includes).flat()); }; pmake.libdirs = function(target) { function libdirs(x) { if(x instanceof pmake.LibraryProject) { return x.libdirs.map(pmake.pathTransform(x)); } return []; } const targets = pmake.resolveProjects(target.libraries); return target.libdirs.concat(targets.map(libdirs).flat()); }; pmake.libs = function(target, if_str, nostr) { function libs(x) { if(x instanceof pmake.LibraryProject) { function recursion(x) { if(x instanceof pmake.LibraryProject) { return pmake.libs(x, if_str); } else if(!nostr && if_str) { return [ if_str(x) ]; } else if(!nostr) { return [ x ]; } return []; } const r = x.libraries.map(recursion).flat().concat([ x.base + "/" + pmake.compiler.output(x) ]); return r; } else if((typeof x) == "string" && !nostr) { return [ x ]; } return []; } const targets = pmake.resolveProjects(target.libraries, if_str).map(libs).flat(); targets = targets.filter(function(item, pos) { return targets.indexOf(item) == pos; }); return targets; }; pmake.setSystem = function(target) { pmake.system = pmake.systems[target]; if(pmake.system.init) pmake.system.init(); }; pmake.setCompiler = function(target) { pmake.compiler = pmake.compilers[target]; if(pmake.compiler.init) pmake.compiler.init(); }; (function() { const Compiler = function() { this.prefix = ""; }; Compiler.prototype.init = function() { }; Compiler.prototype.output = function(target) { if((typeof target) == "string") { if(target.endsWith(".c")) return target.replace(/\.c$/, ".o"); } else if(target instanceof pmake.LibraryProject) { return "lib" + target.output + ".a"; } else if(target instanceof pmake.ExecutableProject) { return target.output; } return target.output; }; const POSIXCompiler = pmake.inherit(Compiler, function(target) { this.ar = "ar"; this.cc = "cc"; this.cxx = "c++"; }); POSIXCompiler.prototype.compile = function(target, obj, src) { function add_i(x) { return "-I" + x; } const includes = pmake.includes(target).map(add_i).join(" "); const flags = includes + " -c -o " + obj + " " + src; if(src.endsWith(".c")) { return this.prefix + this.cc + " " + flags; } else if(is_cxx(src)) { return this.prefix + this.cxx + " " + flags; } return ""; }; POSIXCompiler.prototype.link = function(target, files) { if(target instanceof pmake.LibraryProject) { return this.prefix + this.ar + " rcs " + this.output(target) + " " + files.join(" "); } else if(target instanceof pmake.ExecutableProject) { var c = ""; var cxx = target.sources.filter(pmake.isCxx); if(!cxx || cxx.length == 0) { c = this.prefix + this.cc; } else { c = this.prefix + this.cxx; } function add_l(x) { return "-l" + x; } function add_L(x) { return "-L" + x; } return this.prefix + c + " " + pmake.libdirs(target).map(add_L).join(" ") + " -o " + this.output(target) + " " + files.join(" ") + " " + pmake.libs(target, add_l).join(" "); } return ""; } const System = function() {}; System.prototype.init = function() { }; const Option = function(cmd) { if(cmd) { const c = cmd.split("="); this.target = c[0]; this.option = c[1]; } }; const Project = function(target) { this.target = target; this.sources = []; this.includes = []; this.libdirs = []; this.libraries = []; this.output = target; this.base = fs.cwd(); if(this.base == fs.startedCwd) { this.base = "."; } else { this.base = this.base.substr(fs.startedCwd.length + 1); } }; Project.prototype.generate = function() { }; const LibraryProject = pmake.inherit(Project, function(target) { }); const ExecutableProject = pmake.inherit(Project, function(target) { }); const InterfaceProject = pmake.inherit(Project, function(target) { }); 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.System = System; pmake.Option = Option; pmake.Project = Project; pmake.LibraryProject = LibraryProject; pmake.ExecutableProject = ExecutableProject; pmake.InterfaceProject = InterfaceProject; pmake.File = File; })(); /*** Option ***/ (function() { const Compiler = new pmake.Option("compiler=VALUE"); Compiler.category = "General"; Compiler.description = "Choose a compiler set; one of:"; Compiler.options = function() { return Object.keys(pmake.compilers); }; Compiler.action = function(value) { pmake.setCompiler(value); }; const System = new pmake.Option("system=VALUE"); System.category = "General"; System.description = "Generate files for a different system; one of:"; System.options = function() { return Object.keys(pmake.systems); }; System.action = function(value) { pmake.setSystem(value); }; pmake.register(Compiler); pmake.register(System); })();