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.logger import Logger
from osdk.context import Context, contextFor
from osdk import shell
from osdk import shell, rules
logger = Logger("builder")
@ -18,14 +18,45 @@ def gen(out: TextIO, context: Context):
writer.newline()
writer.separator("Tools")
for key in target.tools:
tool = target.tools[key]
writer.variable(key, tool.cmd)
for i in target.tools:
tool = target.tools[i]
writer.variable(i, tool.cmd)
writer.variable(
key + "flags", " ".join(tool.args))
i + "flags", " ".join(tool.args))
writer.newline()
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:

View file

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

View file

@ -141,10 +141,17 @@ class ComponentManifest(Manifest):
def isEnabled(self, target: TargetManifest):
for k, v in self.enableIf.items():
if k in target.props and target.props[k] in v:
return True
if not k in target.props:
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):

View file

@ -1,7 +1,37 @@
rules = {
"cc": "-c -o $out $in -MD -MF $out.d $flags",
"cxx": "-c -o $out $in -MD -MF $out.d $flags",
"as": "-o $out $in $flags",
"ar": "$flags $out $in",
"ld": "-o $out $in $flags",
class Rule:
id: str
fileIn: list[str]
fileOut: list[str]
rule: str
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 hashlib
T = TypeVar('T')
def uniq(l: list[str]) -> list[str]:
result: list[str] = []
@ -48,9 +50,6 @@ def key(obj: Any, keys: list[str] = []) -> str:
return "-".join(k)
T = TypeVar('T')
def asList(i: T | list[T] | None) -> list[T]:
if i is None:
return []