summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-07-30 22:53:58 +0200
committerAlejandro Sior <aho@sior.be>2022-07-30 22:53:58 +0200
commitab4e773dacc5411b7ede04950b07209dc606ad2f (patch)
tree6032329627c28565381c10cc47de146fc2c03b77
cook: add basic makefile generation
-rw-r--r--.build9
-rw-r--r--.gitignore1
-rwxr-xr-xcook.py192
-rw-r--r--test/.build5
-rw-r--r--test/main.c8
-rw-r--r--test/test.asm6
6 files changed, 221 insertions, 0 deletions
diff --git a/.build b/.build
new file mode 100644
index 0000000..281fc67
--- /dev/null
+++ b/.build
@@ -0,0 +1,9 @@
+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)
+)
+
+subdir("test") \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..95c245b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/makefile \ No newline at end of file
diff --git a/cook.py b/cook.py
new file mode 100755
index 0000000..9c6d3fe
--- /dev/null
+++ b/cook.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+
+import os
+from pathlib import Path
+
+ROOT = Path.cwd()
+BUILD = Path("bld").resolve().relative_to(ROOT)
+
+class FileMeta(type):
+ def __call__(cls, name, *rest):
+ # If already a file, return it
+ if issubclass(type(name), File):
+ return name
+
+ # 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)
+ else:
+ name = path
+
+ idx = str(name) + cls.__name__
+
+ if idx in cls.fdb:
+ return cls.fdb[idx]
+
+ obj = cls.__new__(cls, name, *rest)
+ cls.__init__(obj, name, *rest)
+ cls.fdb[idx] = obj
+ return obj
+
+class File(metaclass = FileMeta):
+ fdb = dict()
+
+ def __init__(self, name):
+ # The name corresponding to
+ # the target: this can be
+ # a path or an abstract name
+ self.name = name
+
+ def __str__(self):
+ return str(self.name)
+
+ def resolve_inner(tgt, arg):
+ if type(arg) == list or type(arg) == tuple:
+ for a in arg:
+ File.resolve_inner(tgt, a)
+ elif type(arg) == str:
+ tgt.append(File(arg))
+ elif issubclass(type(arg), File):
+ tgt.append(arg)
+
+ def resolve(*args):
+ tgt = []
+ for a in args:
+ File.resolve_inner(tgt, a)
+ return tgt
+
+class Process(File):
+ def __init__(self, name, machine, inputs, extra_args = None):
+ super().__init__(name)
+
+ # The generator that created this process
+ self.machine = machine
+
+ # The inputs
+ self.inputs = inputs
+
+ # The extra arguments taken
+ self.extra_args = extra_args
+
+ def gen_makefile(self):
+ inp = " ".join([str(x) for x in self.inputs])
+
+ ea = self.extra_args if self.extra_args else ""
+
+ ret = "%s: %s\n\t$(%s) %s\n" % (self.name, inp, self.machine.name, self.machine.args("$@", "$^", ea))
+ return ret
+
+class MachineMeta(type):
+ def __call__(cls, name, *rest):
+ # If already a file, return it
+ if issubclass(type(name), Machine):
+ return name
+
+ if name in cls.mdb:
+ return cls.mdb[name]
+
+ obj = cls.__new__(cls, name, *rest)
+ cls.__init__(obj, name, *rest)
+ cls.mdb[name] = obj
+ return obj
+
+class Machine(metaclass = MachineMeta):
+ mdb = dict()
+
+ def __init__(self, name, exe, args):
+ # The name of the machine
+ self.name = name
+
+ # Executable used in the process
+ self.exe = File(exe)
+
+ # The arguments that is used to launch the process
+ self.args = args
+
+ 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)
+
+ return Process(name, self, inputs, extra_args)
+
+ def gen_makefile(self):
+ return "%s = %s" % (self.name, self.exe)
+
+class Vec(Machine):
+ def __init__(self, name, output, exe, args):
+ super().__init__(name, exe, args)
+ self.output = output
+
+ def __call__(self, *args, extra_args=None):
+ return self.gen(*args, extra_args=extra_args)
+
+ def gen(self, *args, extra_args=None):
+ 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)
+
+ procs.append(Process(output, 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)
+)
+ld = Machine(
+ "ld",
+ "/usr/bin/cc",
+ lambda o, i, ea: "-o %s %s %s" % (o, i, ea)
+)
+
+def subdir(dir):
+ # Save the previous location
+ PWD = Path.cwd()
+
+ # Go into subdir
+ sub = PWD / dir
+ os.chdir(sub)
+
+ # Set helper path
+ CWD = Path.cwd().relative_to(ROOT)
+ exec(open('.build').read())
+
+ # Revert the current directory;
+ os.chdir(PWD)
+
+subdir(".")
+
+def gen_makefile():
+ ret = ""
+ for mach in Machine.mdb.values():
+ ret += "%s\n" % (mach.gen_makefile())
+
+ all = []
+ for proc in File.fdb.values():
+ if not issubclass(type(proc), Process):
+ continue
+ ret += "\n%s" % (proc.gen_makefile())
+ all.append(str(proc))
+ all = " ".join(all)
+
+ ret += "\n.PHONY: clean\nclean:\n\trm -f %s" % (all)
+ return ret
+
+open(ROOT / 'makefile', "w").write(gen_makefile())
+
+# Create a gitignore
+open(ROOT / BUILD / ".gitignore", "w").write("*") \ No newline at end of file
diff --git a/test/.build b/test/.build
new file mode 100644
index 0000000..8fdda48
--- /dev/null
+++ b/test/.build
@@ -0,0 +1,5 @@
+linker_sc = CWD / "linker.sc"
+
+as_obj = asm("test.asm")
+obj = cc("main.c", extra_args="-T" + str(linker_sc))
+aout = ld("a.out", obj, as_obj) \ No newline at end of file
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..ce0991a
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int test();
+
+int main() {
+ printf("test returned: %d\n", test());
+ return 0;
+} \ No newline at end of file
diff --git a/test/test.asm b/test/test.asm
new file mode 100644
index 0000000..bcd7d20
--- /dev/null
+++ b/test/test.asm
@@ -0,0 +1,6 @@
+[bits 64]
+
+global test
+test:
+ mov eax, 69
+ ret \ No newline at end of file