import os import logging from typing import TextIO from osdk.model import Props from osdk.ninja import Writer from osdk.context import ComponentInstance, Context, contextFor from osdk import shell, rules logger = logging.getLogger(__name__) 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() writer.rule("cp", "cp $in $out") 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() assets = instance.resfiles() 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) for asset in assets: writer.build(asset[1], "cp", asset[0]) writer.newline() if instance.isLib(): writer.build(instance.outfile(), "ar", list(map(lambda o: o[1], objects)), implicit=list(map(lambda o: o[1], assets))) 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()) writer.build(instance.outfile(), "ld", list( map(lambda o: o[1], objects)) + libraries, implicit=list(map(lambda o: o[1], assets))) all.append(instance.outfile()) writer.newline() writer.separator("Phony targets") writer.build("all", "phony", all) writer.default("all") def build(componentSpec: str, targetSpec: str, props: Props = {}) -> ComponentInstance: 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()) return instance 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) -> Context: context = contextFor(targetSpec) 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 context def testAll(targetSpec: str): context = contextFor(targetSpec) 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, "all") for instance in context.enabledInstances(): if instance.isLib(): continue if instance.id().endswith("-tests"): print(f"Running {instance.id()}") shell.exec(instance.outfile())