diff options
| author | Alejandro Sior <aho@sior.be> | 2022-07-30 22:53:58 +0200 |
|---|---|---|
| committer | Alejandro Sior <aho@sior.be> | 2022-07-30 22:53:58 +0200 |
| commit | ab4e773dacc5411b7ede04950b07209dc606ad2f (patch) | |
| tree | 6032329627c28565381c10cc47de146fc2c03b77 | |
cook: add basic makefile generation
| -rw-r--r-- | .build | 9 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rwxr-xr-x | cook.py | 192 | ||||
| -rw-r--r-- | test/.build | 5 | ||||
| -rw-r--r-- | test/main.c | 8 | ||||
| -rw-r--r-- | test/test.asm | 6 |
6 files changed, 221 insertions, 0 deletions
@@ -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 @@ -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 |
