import os from typing import TextIO from osdk.model import ComponentManifest, TargetManifest, Props from osdk.ninja import Writer from osdk.logger import Logger from osdk.context import Context, contextFor from osdk import shell, rules logger = Logger("builder") def gen(out: TextIO, context: Context): writer = Writer(out) target = context.target writer.comment("File generated by the build system, do not edit") writer.newline() writer.variable("builddir", context.builddir()) writer.separator("Tools") writer.variable("cincs", " ".join( map(lambda i: f"-I{i}", context.cincls()))) writer.variable("cdefs", " ".join(context.cdefs())) writer.newline() for i in target.tools: tool = target.tools[i] rule = rules.rules[i] writer.variable(i, tool.cmd) writer.variable( i + "flags", " ".join(rule.args + tool.args)) writer.rule( i, f"{tool.cmd} {rule.rule.replace('$flags',f'${i}flags')}", depfile=rule.deps) writer.newline() writer.separator("Components") all: list[str] = [] for instance in context.enabledInstances(): objects = instance.objsfiles(context) writer.comment(f"Component: {instance.manifest.id}") writer.comment(f"Resolved: {', '.join(instance.resolved)}") for obj in objects: r = rules.byFileIn(obj[0]) if r is None: raise Exception(f"Unknown rule for file {obj[0]}") t = target.tools[r.id] writer.build(obj[1], r.id, obj[0], order_only=t.files) writer.newline() if instance.isLib(): writer.build(instance.libfile(context), "ar", list(map(lambda o: o[1], objects))) else: libraries: list[str] = [] for req in instance.resolved: reqInstance = context.componentByName(req) if reqInstance is None: raise Exception(f"Component {req} not found") if not reqInstance.isLib(): raise Exception(f"Component {req} is not a library") libraries.append(reqInstance.outfile(context)) writer.build(instance.binfile(context), "ld", list(map(lambda o: o[1], objects)) + libraries) all.append(instance.binfile(context)) writer.newline() writer.separator("Phony targets") writer.build("all", "phony", all) writer.default("all") def build(componentSpec: str, targetSpec: str, props: Props = {}) -> str: context = contextFor(targetSpec, props) shell.mkdir(context.builddir()) ninjaPath = os.path.join(context.builddir(), "build.ninja") with open(ninjaPath, "w") as f: gen(f, context) instance = context.componentByName(componentSpec) if instance is None: raise Exception(f"Component {componentSpec} not found") if not instance.enabled: raise Exception( f"Component {componentSpec} is disabled: {instance.disableReason}") shell.exec(f"ninja", "-v", "-f", ninjaPath, instance.outfile(context)) return instance.outfile(context) class Paths: bin: str lib: str obj: str def __init__(self, bin: str, lib: str, obj: str): self.bin = bin self.lib = lib self.obj = obj def buildAll(targetSpec: str) -> Paths: context = contextFor(targetSpec) target = context.target shell.mkdir(context.builddir()) ninjaPath = os.path.join(context.builddir(), "build.ninja") with open(ninjaPath, "w") as f: gen(f, context) shell.exec(f"ninja", "-v", "-f", ninjaPath) return Paths( os.path.join(context.builddir(), "bin"), os.path.join(context.builddir(), "lib"), os.path.join(context.builddir(), "obj") )