This commit is contained in:
Nishi 2026-05-09 16:20:44 +09:00
commit ae7ff555d9
Signed by: nishi
GPG key ID: 27EF69B208EB9343
5 changed files with 250 additions and 31 deletions

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
/pmake*
*.o
*.a
/Makefile
/*.make
/src/compiler/*.c

View file

@ -4,5 +4,8 @@ const GCC = new pmake.POSIXCompiler();
GCC.target = "GCC";
GCC.description = "GCC/Clang";
GCC.cc = "gcc";
GCC.cxx = "g++";
pmake.register(GCC);
})();

View file

@ -34,13 +34,13 @@ int js_init(int argc, char** argv) {
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));
printf("JS error: js/core.js: %s\n", duk_safe_to_string(js_ctx, -1));
return 1;
}
#define X(name, prefix) \
if(duk_peval_lstring(js_ctx, prefix##_##name, prefix##_##name##_len) != 0) { \
printf("error: %s: %s\n", #prefix "/" #name ".js", duk_safe_to_string(js_ctx, -1)); \
printf("JS error: %s: %s\n", #prefix "/" #name ".js", duk_safe_to_string(js_ctx, -1)); \
return 1; \
}
JS;
@ -49,7 +49,7 @@ int js_init(int argc, char** argv) {
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));
printf("JS error: js/cmdline.js: %s\n", duk_safe_to_string(js_ctx, -1));
return 1;
}
@ -74,7 +74,7 @@ int js_run(const char* file) {
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));
printf("JS error: %s: %s\n", file, duk_safe_to_string(js_ctx, -1));
free(buffer);
fclose(f);

View file

@ -1,5 +1,7 @@
const PADDING = 24;
pmake.compiler = pmake.compilers["GCC"];
for(var i = 1; i < ARGV.length; i++) {
if(ARGV[i] == "--help") {
var keys;
@ -48,35 +50,104 @@ for(var i = 1; i < ARGV.length; i++) {
}
process.exit(0);
} else if(ARGV[i].startsWith("--")) {
console.log("Error: invalid option '" + ARGV[i].substr(2) + "'");
process.exit(1);
var args = ARGV[i].split("=");
args[0] = args[0].substr(2);
if(pmake.options[args[0]]) {
var opts = pmake.options[args[0]].options;
if(opts) {
if((typeof opts) == "function") opts = opts();
}
if(opts && !args[1]) {
console.log("Error: no value specified for option '" + args[0] + "'");
process.exit(1);
} else if(opts && !opts.includes(args[1])) {
console.log("Error: invalid value '" + args[1] + "' for option '" + args[0] + "'");
process.exit(1);
} else if(opts) {
pmake.options[args[0]].action(args[1]);
} else {
pmake.options[args[0]].action();
}
} else {
console.log("Error: invalid option '" + args[0] + "'");
process.exit(1);
}
}
}
(function() {
function make(output) {
const targets = pmake.resolveProjects(pmake.projects);
function target_map(x) {
return x.target;
}
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("RM = rm -f\n");
mk.write("\n");
mk.write(".PHONY: all clean\n");
if(output == "Makefile") {
var targets = pmake.resolveProjects(pmake.projects);
mk.write(".PHONY: " + targets.map(target_map).join(" ") + "\n");
mk.write("\n");
mk.write("MAKEARGS$(.TARGET) = --no-print-directory");
mk.write("\n");
mk.write("all: " + pmake.projects.map(target_map).join(" ") + "\n");
mk.write("\n");
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(targets[i].target + ": " + pmake.resolveProjects(targets[i].libraries).map(target_map).join(" ") + "\n");
mk.write(" @$(MAKE) $(MAKEARGS) -f " + targets[i].target + ".make\n");
mk.write("\n");
}
mk.write("clean:\n");
for(var i = 0; i < targets.length; i++) {
mk.write(" @$(MAKE) $(MAKEARGS) -f " + targets[i].target + ".make clean\n");
}
} else {
function target_filter(x) {
return x.target == output.replace(/\.make$/, "");
}
const self = targets.filter(target_filter)[0];
const objs = self.sources.map(pmake.compiler.output);
mk.write("\n");
mk.write("all: " + pmake.compiler.output(self) + "\n");
mk.write("\n");
mk.write(pmake.compiler.output(self) + ": " + objs.join(" ") + "\n");
mk.write(" " + pmake.compiler.link(self, objs) + "\n");
mk.write("\n");
for(var i = 0; i < objs.length; i++) {
mk.write(objs[i] + ": " + self.sources[i] + "\n");
mk.write(" " + pmake.compiler.compile(self, objs[i], self.sources[i]) + "\n");
mk.write("\n");
}
mk.write("clean: \n");
mk.write(" $(SILENT)$(RM) " + pmake.compiler.output(self) + " *.o *.exe *.a *.lib *.so *.dll\n");
}
mk.close();
}
make("Makefile");
var targets = pmake.resolveProjects(pmake.projects);
const targets = pmake.resolveProjects(pmake.projects);
for(var i = 0; i < targets.length; i++) {
make(targets[i].target + ".make");
}

View file

@ -1,12 +1,37 @@
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 : {},
options : {},
options_category : {},
projects : []
};
pmake.inherit = function(base, call) {
const func = (function() {});
const func = (function() {
base.apply(this, arguments);
if(call) call.apply(this, arguments);
});
Object.setPrototypeOf(func.prototype, base.prototype);
@ -25,47 +50,159 @@ pmake.inherited = function(base, parent) {
return false;
};
pmake.register = function(base) {
if(base instanceof pmake.Compiler) {
pmake.compilers[base.target] = base;
} else if(base instanceof pmake.Option) {
if(!pmake.options[base.category]) pmake.options[base.category] = {};
pmake.register = function(target) {
if(target instanceof pmake.Compiler) {
pmake.compilers[target.target] = target;
} else if(target instanceof pmake.Option) {
if(!pmake.options_category[target.category]) pmake.options_category[target.category] = {};
pmake.options[base.category][base.target] = base;
} else if(base instanceof pmake.Project) {
pmake.projects.push(base);
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) {
pmake.resolveProjects = function(arr, if_str) {
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]);
var proj = arr[i];
if((typeof proj) == "string" && pmake.projects[proj]) {
proj = pmake.projects[proj];
}
if(proj instanceof pmake.Project) {
r = r.concat(pmake.resolveProjects(proj.libraries));
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;
};
(function() {
const Compiler = function() {};
pmake.isCxx = function(src) {
return src.endsWith(".cc") || src.endsWith(".cxx") || src.endsWith(".cpp");
};
const POSIXCompiler = pmake.inherit(Compiler);
pmake.includes = function(target) {
function includes(x) {
return x.includes;
}
const targets = pmake.resolveProjects(target.libraries);
return targets.map(includes).flat();
};
pmake.libs = function(target, if_str) {
function libs(x) {
if(x instanceof pmake.LibraryProject) {
return x.libraries.concat([ pmake.compiler.output(x) ]);
} else if((typeof x) == "string") {
return [ x ];
}
return [];
}
const targets = pmake.resolveProjects(target.libraries, if_str);
return targets.map(libs).flat();
};
(function() {
const Compiler = function() {
this.prefix = "";
};
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)
if(includes.length > 0) includes = " " + includes.join(" ");
if(src.endsWith(".c")) {
return this.prefix + this.cc + includes + " -c -o " + obj + " " + src;
} else if(is_cxx(src)) {
return this.prefix + this.cxx + includes + " -c -o " + obj + " " + src;
}
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;
}
return this.prefix + c + " -o " + this.output(target) + " " + files.join(" ") + " " + pmake.libs(target, add_l).join(" ");
}
return "";
}
const Option = function() {};
const Project = function(target) {
this.target = target;
this.files = [];
this.sources = [];
this.includes = [];
this.libraries = [];
this.output = target;
};
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);
};
@ -78,11 +215,14 @@ File.prototype.close = function() {
fs.close(this.fp);
};
pmake.Compiler = Compiler;
pmake.POSIXCompiler = POSIXCompiler;
pmake.Option = Option;
pmake.Project = Project;
pmake.File = File;
pmake.Compiler = Compiler;
pmake.POSIXCompiler = POSIXCompiler;
pmake.Option = Option;
pmake.Project = Project;
pmake.LibraryProject = LibraryProject;
pmake.ExecutableProject = ExecutableProject;
pmake.InterfaceProject = InterfaceProject;
pmake.File = File;
})();
/*** Option ***/
@ -98,5 +238,9 @@ Compiler.options = function() {
return Object.keys(pmake.compilers);
};
Compiler.action = function(value) {
pmake.compiler = pmake.compilers[value];
};
pmake.register(Compiler);
})();