Working on ninja file generation.
This commit is contained in:
parent
a3ae84fde9
commit
e7b93db95f
5 changed files with 100 additions and 24 deletions
|
@ -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:
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 []
|
||||||
|
|
Loading…
Add table
Reference in a new issue