diff options
| author | Alejandro Sior <aho@sior.be> | 2022-07-31 13:16:45 +0200 |
|---|---|---|
| committer | Alejandro Sior <aho@sior.be> | 2022-07-31 13:16:45 +0200 |
| commit | 11c116cc2c440b6dea801d250266b92bc5b6b85a (patch) | |
| tree | f57f3a92ba464e221521d4d6fe778610acf79e32 | |
| parent | ab4e773dacc5411b7ede04950b07209dc606ad2f (diff) | |
cook: ninja files generation
| -rw-r--r-- | .build | 5 | ||||
| -rw-r--r-- | .gitignore | 3 | ||||
| -rwxr-xr-x | cook.py | 159 | ||||
| -rw-r--r-- | test/main.c | 1 |
4 files changed, 116 insertions, 52 deletions
@@ -1,9 +1,10 @@ global asm asm = Vec( "asm", - lambda i: "%s.o" % (i), "/usr/bin/nasm", - lambda o, i, ea: "-f elf64 %s -o %s %s" % (i, o, ea) + lambda o, i, ea: "-f elf64 %s -o %s %s" % (i, o, ea), + lambda i: (i.name + ".o"), + desc=lambda o, i, ea: "ASM %s" % (o) ) subdir("test")
\ No newline at end of file @@ -1 +1,2 @@ -/makefile
\ No newline at end of file +/makefile +*.ninja*
\ No newline at end of file @@ -2,45 +2,59 @@ import os from pathlib import Path +from threading import local +import shutil + + +def find_program(prog, required=True): + path = shutil.which(prog) + if path == None and required: + raise Exception("Required program '%s' not found on the system" % (prog)) + return File(path) ROOT = Path.cwd() BUILD = Path("bld").resolve().relative_to(ROOT) +DEFDESC = lambda o, i, cmd: "%s" % (cmd) class FileMeta(type): - def __call__(cls, name, *rest): + def __call__(cls, path, *rest, **krest): + # If none, return none + if path == None: + return None + # If already a file, return it - if issubclass(type(name), File): - return name + if issubclass(type(path), File): + return path # Adjust name to be a path - if type(name) == str: - path = Path(name).resolve() - if path.is_relative_to(ROOT): - name = path.relative_to(ROOT) + if type(path) == str: + p = Path(path).resolve() + if p.is_relative_to(ROOT): + path = p.relative_to(ROOT) else: - name = path + path = p - idx = str(name) + cls.__name__ + idx = str(path) + cls.__name__ if idx in cls.fdb: return cls.fdb[idx] - obj = cls.__new__(cls, name, *rest) - cls.__init__(obj, name, *rest) + obj = cls.__new__(cls, path, *rest, **krest) + cls.__init__(obj, path, *rest, **krest) cls.fdb[idx] = obj return obj class File(metaclass = FileMeta): fdb = dict() - def __init__(self, name): + def __init__(self, path): # The name corresponding to # the target: this can be # a path or an abstract name - self.name = name + self.path = path def __str__(self): - return str(self.name) + return str(self.path) def resolve_inner(tgt, arg): if type(arg) == list or type(arg) == tuple: @@ -58,8 +72,8 @@ class File(metaclass = FileMeta): return tgt class Process(File): - def __init__(self, name, machine, inputs, extra_args = None): - super().__init__(name) + def __init__(self, path, machine, inputs, extra_args = None): + super().__init__(path) # The generator that created this process self.machine = machine @@ -71,15 +85,27 @@ class Process(File): self.extra_args = extra_args def gen_makefile(self): - inp = " ".join([str(x) for x in self.inputs]) + inputs = " ".join([str(x) for x in self.inputs]) + + extra_args = self.extra_args if self.extra_args else "" - ea = self.extra_args if self.extra_args else "" + out = "%s: %s\n" % (self.path, inputs) + out += "\t@$(%s) %s\n" % (self.machine.name, self.machine.mkargs("$@", "$^", extra_args)) + out += "\t@echo '%s'" % (self.machine.desc(self, inputs, extra_args)) + + return out + + def gen_ninja(self): + inputs = " ".join([str(x) for x in self.inputs]) + + out = "build %s: %s %s" % (self.path, self.machine.name, inputs) + if self.extra_args != None: + out += "\n extra = %s" % (self.extra_args) - ret = "%s: %s\n\t$(%s) %s\n" % (self.name, inp, self.machine.name, self.machine.args("$@", "$^", ea)) - return ret + return out class MachineMeta(type): - def __call__(cls, name, *rest): + def __call__(cls, name, *rest, **krest): # If already a file, return it if issubclass(type(name), Machine): return name @@ -87,15 +113,15 @@ class MachineMeta(type): if name in cls.mdb: return cls.mdb[name] - obj = cls.__new__(cls, name, *rest) - cls.__init__(obj, name, *rest) + obj = cls.__new__(cls, name, *rest, **krest) + cls.__init__(obj, name, *rest, **krest) cls.mdb[name] = obj return obj class Machine(metaclass = MachineMeta): mdb = dict() - def __init__(self, name, exe, args): + def __init__(self, name, exe, mkargs, desc=DEFDESC): # The name of the machine self.name = name @@ -103,27 +129,36 @@ class Machine(metaclass = MachineMeta): self.exe = File(exe) # The arguments that is used to launch the process - self.args = args + self.mkargs = mkargs + + # The description + self.desc = desc def __call__(self, name, *args, extra_args=None): return self.gen(name, *args, extra_args=extra_args) def gen(self, name, *args, extra_args=None): inputs = File.resolve(args) - name = BUILD / Path.cwd().relative_to(ROOT) / name - - # Create the parent directory - (ROOT / name).parent.mkdir(parents=True, exist_ok=True) + path = BUILD / Path.cwd().relative_to(ROOT) / name - return Process(name, self, inputs, extra_args) + return Process(path, self, inputs, extra_args) def gen_makefile(self): return "%s = %s" % (self.name, self.exe) + def gen_ninja(self): + out = "rule %s\n" % (self.name) + + cmd = "%s %s" % (self.exe, self.mkargs("$out", "$in", "$extra")) + + out += " command = %s\n" % (cmd) + out += " description = %s" % (self.desc("$out", "$in", cmd)) + return out + class Vec(Machine): - def __init__(self, name, output, exe, args): - super().__init__(name, exe, args) - self.output = output + def __init__(self, name, exe, args, mkout, desc=DEFDESC): + super().__init__(name, exe, args, desc=desc) + self.mkout = mkout def __call__(self, *args, extra_args=None): return self.gen(*args, extra_args=extra_args) @@ -132,25 +167,24 @@ class Vec(Machine): procs = [] inputs = File.resolve(args) for i in inputs: - output = BUILD / i.name.parent / self.output(i.name.name) - - # Create the parent directory - (ROOT / output).parent.mkdir(parents=True, exist_ok=True) + path = BUILD / i.path.parent / self.mkout(i.path) - procs.append(Process(output, self, [i], extra_args)) + procs.append(Process(path, self, [i], extra_args)) return procs cc = Vec( "cc", - lambda i: "%s.o" % (i), "/usr/bin/cc", - lambda o, i, ea: "-o %s -c %s %s" % (o, i, ea) + lambda o, i, ea: "-o %s -c %s %s" % (o, i, ea), + lambda i: i.name + ".o", + desc=lambda o, i, ea: "CC %s" % (o), ) ld = Machine( "ld", "/usr/bin/cc", - lambda o, i, ea: "-o %s %s %s" % (o, i, ea) + lambda o, i, ea: "-o %s %s %s" % (o, i, ea), + desc=lambda o, i, ea: "LD %s" % (o) ) def subdir(dir): @@ -170,23 +204,50 @@ def subdir(dir): subdir(".") +def gen_bld(): + for proc in File.fdb.values(): + if not issubclass(type(proc), Process): + continue + proc.path.parent.mkdir(parents=True, exist_ok=True) + def gen_makefile(): - ret = "" + out = "" for mach in Machine.mdb.values(): - ret += "%s\n" % (mach.gen_makefile()) + out += mach.gen_makefile() + out += "\n" all = [] for proc in File.fdb.values(): if not issubclass(type(proc), Process): continue - ret += "\n%s" % (proc.gen_makefile()) + + out += "\n" + out += proc.gen_makefile() + out += "\n" all.append(str(proc)) all = " ".join(all) - ret += "\n.PHONY: clean\nclean:\n\trm -f %s" % (all) - return ret + out += "\n.PHONY: clean\nclean:\n\trm -f %s" % (all) + return out + +def gen_ninja(): + out = "" + for mach in Machine.mdb.values(): + out += mach.gen_ninja() + out += "\n" -open(ROOT / 'makefile', "w").write(gen_makefile()) + out += "\n" -# Create a gitignore -open(ROOT / BUILD / ".gitignore", "w").write("*")
\ No newline at end of file + for proc in File.fdb.values(): + if not issubclass(type(proc), Process): + continue + + out += proc.gen_ninja() + out += "\n" + + return out + +# Generate everything +gen_bld() +open(ROOT / BUILD / ".gitignore", "w").write("*") +open(ROOT / 'build.ninja', 'w').write(gen_ninja())
\ No newline at end of file diff --git a/test/main.c b/test/main.c index ce0991a..9298b76 100644 --- a/test/main.c +++ b/test/main.c @@ -3,6 +3,7 @@ int test(); int main() { + printf("test returned: %d\n", test()); return 0; }
\ No newline at end of file |
