Working on ninja file generation.

This commit is contained in:
Nicolas Van Bossuyt 2023-01-31 21:09:28 +01:00
parent a3ae84fde9
commit e7b93db95f
5 changed files with 100 additions and 24 deletions

View file

@ -4,7 +4,7 @@ from osdk.model import ComponentManifest, TargetManifest, Props
from osdk.ninja import Writer from osdk.ninja import Writer
from osdk.logger import Logger from osdk.logger import Logger
from osdk.context import Context, contextFor from osdk.context import Context, contextFor
from osdk import shell from osdk import shell, rules
logger = Logger("builder") logger = Logger("builder")
@ -18,14 +18,45 @@ def gen(out: TextIO, context: Context):
writer.newline() writer.newline()
writer.separator("Tools") writer.separator("Tools")
for key in target.tools: for i in target.tools:
tool = target.tools[key] tool = target.tools[i]
writer.variable(key, tool.cmd) writer.variable(i, tool.cmd)
writer.variable( writer.variable(
key + "flags", " ".join(tool.args)) i + "flags", " ".join(tool.args))
writer.newline() writer.newline()
writer.separator("Rules") writer.separator("Rules")
for i in rules.rules:
tool = target.tools[i]
rule = rules.rules[i]
writer.rule(
i, f"{tool.cmd} {rule.rule.replace('$flags',f'${i}flags')}")
writer.newline()
writer.separator("Components")
for instance in context.instances:
objects = instance.objsfiles()
writer.comment(f"Component: {instance.manifest.id}")
writer.newline()
for obj in objects:
r = rules.byFileIn(obj[0])
if r is None:
raise Exception(f"Unknown rule for file {obj[0]}")
writer.build(obj[1], r.id, obj[0])
writer.newline()
if instance.isLib():
writer.build(instance.libfile(), "ar",
list(map(lambda o: o[1], objects)))
else:
writer.build(instance.binfile(), "ld",
list(map(lambda o: o[1], objects)))
writer.newline()
def build(componentSpec: str, targetSpec: str = "default", props: Props = {}) -> str: def build(componentSpec: str, targetSpec: str = "default", props: Props = {}) -> str:

View file

@ -1,3 +1,5 @@
from typing import cast
from osdk.model import TargetManifest, ComponentManifest, Props from osdk.model import TargetManifest, ComponentManifest, Props
from osdk.logger import Logger from osdk.logger import Logger
from osdk import const, shell, jexpr from osdk import const, shell, jexpr
@ -22,17 +24,21 @@ class ComponentInstance:
self.sources = sources self.sources = sources
self.resolved = resolved self.resolved = resolved
def isLib(self):
return self.manifest.type == "lib"
def binfile(self) -> str: def binfile(self) -> str:
return f"{self.target.builddir()}/bin/{self.manifest.id}.out" return f"{self.target.builddir()}/bin/{self.manifest.id}.out"
def objdir(self) -> str: def objdir(self) -> str:
return f"{self.target.builddir()}/obj/{self.manifest.id}" return f"{self.target.builddir()}/obj/{self.manifest.id}"
def objsfiles(self) -> list[str]: def objsfiles(self) -> list[tuple[str, str]]:
return list( return list(
map( map(
lambda s: f"{self.objdir()}/{s}.o", lambda s: (
self.sources.remplace(self.manifest.dirname(), ""))) s, f"{self.objdir()}/{s.replace(self.manifest.dirname() + '/', '')}.o"),
self.sources))
def libfile(self) -> str: def libfile(self) -> str:
return f"{self.target.builddir()}/lib/{self.manifest.id}.a" return f"{self.target.builddir()}/lib/{self.manifest.id}.a"
@ -124,12 +130,15 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target:
return enabled, resolved[1:] return enabled, resolved[1:]
def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> ComponentInstance: def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> ComponentInstance | None:
manifest = next(filter(lambda c: c.id == componentSpec, components)) manifest = next(filter(lambda c: c.id == componentSpec, components))
sources = shell.find( sources = shell.find(
manifest.path, ["*.c", "*.cpp", "*.s", "*.asm"]) manifest.dirname(), ["*.c", "*.cpp", "*.s", "*.asm"])
enabled, resolved = resolveDeps(componentSpec, components, target) enabled, resolved = resolveDeps(componentSpec, components, target)
if not enabled:
return None
return ComponentInstance(target, manifest, sources, resolved) return ComponentInstance(target, manifest, sources, resolved)
@ -140,8 +149,8 @@ def contextFor(targetSpec: str, props: Props) -> Context:
components = loadAllComponents() components = loadAllComponents()
components = filterDisabled(components, target) components = filterDisabled(components, target)
instances = list(map(lambda c: instanciate( instances = cast(list[ComponentInstance], list(filter(lambda e: e != None, map(lambda c: instanciate(
c.id, components, target), components)) c.id, components, target), components))))
return Context( return Context(
target, target,

View file

@ -141,10 +141,17 @@ class ComponentManifest(Manifest):
def isEnabled(self, target: TargetManifest): def isEnabled(self, target: TargetManifest):
for k, v in self.enableIf.items(): for k, v in self.enableIf.items():
if k in target.props and target.props[k] in v: if not k in target.props:
return True logger.log(
f"Component {self.id} disabled by missing {k} in target")
return False
return False if not target.props[k] in v:
logger.log(
f"Component {self.id} disabled by {k}={target.props[k]} not in {v}")
return False
return True
class ModelEncoder(JSONEncoder): class ModelEncoder(JSONEncoder):

View file

@ -1,7 +1,37 @@
rules = { class Rule:
"cc": "-c -o $out $in -MD -MF $out.d $flags", id: str
"cxx": "-c -o $out $in -MD -MF $out.d $flags", fileIn: list[str]
"as": "-o $out $in $flags", fileOut: list[str]
"ar": "$flags $out $in", rule: str
"ld": "-o $out $in $flags",
def __init__(self, id: str, fileIn: list[str], fileOut: list[str], rule: str):
self.id = id
self.fileIn = fileIn
self.fileOut = fileOut
self.rule = rule
rules: dict[str, Rule] = {
"cc": Rule("cc", ["c"], ["o"], "-c -o $out $in -MD -MF $out.d $flags"),
"cxx": Rule("cxx", ["cpp", "cc", "cxx"], ["o"], "-c -o $out $in -MD -MF $out.d $flags"),
"as": Rule("as", ["s", "asm", "S"], ["o"], "-o $out $in $flags"),
"ar": Rule("ar", ["o"], ["a"], "$flags $out $in"),
"ld": Rule("ld", ["o", "a"], ["out"], "$flags $out $in"),
} }
def append(rule: Rule):
rules[rule.id] = rule
def byFileIn(fileIn: str) -> Rule | None:
for key in rules:
rule = rules[key]
for ext in rule.fileIn:
if fileIn.endswith("." + ext):
return rule
return None
def byId(id: str) -> Rule | None:
return rules.get(id, None)

View file

@ -2,6 +2,8 @@ from typing import Any, TypeVar, cast
import json import json
import hashlib import hashlib
T = TypeVar('T')
def uniq(l: list[str]) -> list[str]: def uniq(l: list[str]) -> list[str]:
result: list[str] = [] result: list[str] = []
@ -48,9 +50,6 @@ def key(obj: Any, keys: list[str] = []) -> str:
return "-".join(k) return "-".join(k)
T = TypeVar('T')
def asList(i: T | list[T] | None) -> list[T]: def asList(i: T | list[T] | None) -> list[T]:
if i is None: if i is None:
return [] return []