summaryrefslogtreecommitdiff
path: root/cook.py
diff options
context:
space:
mode:
Diffstat (limited to 'cook.py')
-rwxr-xr-xcook.py159
1 files changed, 110 insertions, 49 deletions
diff --git a/cook.py b/cook.py
index 9c6d3fe..87183c5 100755
--- a/cook.py
+++ b/cook.py
@@ -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