pmake/src/js/core.js
2026-05-12 08:36:20 +09:00

341 lines
7.3 KiB
JavaScript

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) {
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);
})();