forked from pyrite-dev/pmake
352 lines
7.6 KiB
JavaScript
352 lines
7.6 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 && 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.reverse();
|
|
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");
|
|
if(target.endsWith(".rc")) return target.replace(/\.rc$/, ".res");
|
|
} else if(target instanceof pmake.LibraryProject) {
|
|
return "lib" + target.output + ".a";
|
|
} else if(target instanceof pmake.ExecutableProject) {
|
|
if(pmake.system.target == "Windows") {
|
|
return target.output + ".exe";
|
|
} else {
|
|
return target.output;
|
|
}
|
|
}
|
|
|
|
return target.output;
|
|
};
|
|
|
|
const POSIXCompiler = pmake.inherit(Compiler, function(target) {
|
|
this.ar = "ar";
|
|
this.cc = "cc";
|
|
this.cxx = "c++";
|
|
this.rc = "windres";
|
|
});
|
|
|
|
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(".rc")) {
|
|
return this.prefix + this.rc + " -O coff " + src + " " + obj;
|
|
} else 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.cc;
|
|
} else {
|
|
c = 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);
|
|
})();
|