mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Overall, I believe TOML to be a superior configuration format than YAML in many situations, but it gets ugly quickly when nesting data structures. The build configs were fine in TOML, but the manifest (and my future plans for it) got unwieldy. I also did not want different formats for each kind of configuration on top of also having a custom DSL for interface definitions, so I've switched all the TOML to YAML. Also of note is that this change actually adds structure to the manifest file, which was little more than a CSV previously.
189 lines
6.6 KiB
Python
189 lines
6.6 KiB
Python
from . import BonnibelError
|
|
|
|
class Project:
|
|
def __init__(self, root):
|
|
from .version import git_version
|
|
|
|
self.root = root
|
|
self.version = git_version(root)
|
|
|
|
def __str__(self):
|
|
return f"{self.name} {self.version.major}.{self.version.minor}.{self.version.patch}-{self.version.sha}"
|
|
|
|
def generate(self, root, output, modules, config, manifest_file):
|
|
import sys
|
|
import bonnibel
|
|
from os.path import join
|
|
from ninja.ninja_syntax import Writer
|
|
from . import load_config
|
|
from .target import Target
|
|
|
|
targets = set()
|
|
for mod in modules.values():
|
|
targets.update({Target.load(root, t, config) for t in mod.targets})
|
|
|
|
with open(output / "build.ninja", "w") as buildfile:
|
|
build = Writer(buildfile)
|
|
|
|
build.comment("This file is automatically generated by bonnibel")
|
|
build.variable("ninja_required_version", "1.3")
|
|
build.variable("build_root", output)
|
|
build.variable("source_root", root)
|
|
build.newline()
|
|
|
|
build.include(root / "configs" / "rules.ninja")
|
|
build.newline()
|
|
|
|
build.variable("version_major", self.version.major)
|
|
build.variable("version_minor", self.version.minor)
|
|
build.variable("version_patch", self.version.patch)
|
|
build.variable("version_sha", self.version.sha)
|
|
build.newline()
|
|
|
|
for target in targets:
|
|
build.subninja(output / target.name / "target.ninja")
|
|
build.newline()
|
|
|
|
fatroot = output / "fatroot"
|
|
fatroot.mkdir(exist_ok=True)
|
|
|
|
fatroot_content = []
|
|
def add_fatroot(name, target):
|
|
if not name in modules:
|
|
raise BonnibelError(f"Manifest item '{name}' is not a known module")
|
|
|
|
mod = modules[name]
|
|
fatroot_output = f"${{build_root}}/fatroot/{mod.output}"
|
|
|
|
build.build(
|
|
rule = "strip",
|
|
outputs = [fatroot_output],
|
|
inputs = [f"${{build_root}}/{target}/{mod.output}"],
|
|
variables = {
|
|
"name": f"Installing {name}",
|
|
"debug": f"${{build_root}}/{mod.output}.debug",
|
|
})
|
|
|
|
fatroot_content.append(fatroot_output)
|
|
build.newline()
|
|
|
|
manifest = load_config(manifest_file)
|
|
programs = manifest.get("programs", tuple())
|
|
|
|
kernel = manifest.get("kernel", dict())
|
|
add_fatroot(
|
|
kernel.get("name", "kernel"),
|
|
kernel.get("target", "kernel"))
|
|
|
|
for program in programs:
|
|
name = program["name"]
|
|
target = program.get("target", "user")
|
|
add_fatroot(name, target)
|
|
|
|
symbol_table = "${build_root}/fatroot/symbol_table.dat"
|
|
build.build(
|
|
rule = "makest",
|
|
outputs = [symbol_table],
|
|
inputs = ["${build_root}/fatroot/jsix.elf"],
|
|
)
|
|
fatroot_content.append(symbol_table)
|
|
build.newline()
|
|
|
|
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [bootloader],
|
|
inputs = ["${build_root}/boot/boot.efi"],
|
|
variables = {
|
|
"name": "Installing bootloader",
|
|
})
|
|
fatroot_content.append(bootloader)
|
|
build.newline()
|
|
|
|
build.build(
|
|
rule = "makefat",
|
|
outputs = ["${build_root}/jsix.img"],
|
|
inputs = ["${source_root}/assets/diskbase.img"],
|
|
implicit = fatroot_content,
|
|
variables = {"name": "jsix.img"},
|
|
)
|
|
build.newline()
|
|
|
|
default_assets = {
|
|
"ovmf/x64/ovmf_vars.fd": "UEFI Variables",
|
|
"debugging/jsix.elf-gdb.py": "GDB Debug Helpers",
|
|
}
|
|
|
|
for asset, name in default_assets.items():
|
|
p = root / "assets" / asset
|
|
out = f"${{build_root}}/{p.name}"
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [out],
|
|
inputs = [str(p)],
|
|
variables = {"name": name},
|
|
)
|
|
build.default([out])
|
|
build.newline()
|
|
|
|
build.rule("regen",
|
|
command = " ".join([str(root / 'configure')] + sys.argv[1:]),
|
|
description = "Regenerate build files",
|
|
generator = True,
|
|
)
|
|
build.newline()
|
|
|
|
regen_implicits = \
|
|
[f"{self.root}/configure", str(manifest_file)] + \
|
|
[str(mod.modfile) for mod in modules.values()]
|
|
|
|
for target in targets:
|
|
regen_implicits += target.depfiles
|
|
|
|
build.build(
|
|
rule = "regen",
|
|
outputs = ['build.ninja'],
|
|
implicit = regen_implicits,
|
|
implicit_outputs =
|
|
[f"{mod.name}.ninja" for mod in modules.values()] +
|
|
[f"{target.name}/target.ninja" for target in targets],
|
|
)
|
|
|
|
build.newline()
|
|
build.default(["${build_root}/jsix.img"])
|
|
|
|
for target in targets:
|
|
mods = [m.name for m in modules.values() if target.name in m.targets]
|
|
|
|
targetdir = output / target.name
|
|
targetdir.mkdir(exist_ok=True)
|
|
|
|
buildfilename = str(targetdir / "target.ninja")
|
|
with open(buildfilename, "w") as buildfile:
|
|
build = Writer(buildfile)
|
|
build.comment("This file is automatically generated by bonnibel")
|
|
build.newline()
|
|
|
|
build.variable("target", target.name)
|
|
build.variable("target_dir", output / target.name)
|
|
build.newline()
|
|
|
|
for name, value in target.items():
|
|
build.variable(name, value)
|
|
|
|
build.newline()
|
|
for kind in ('defs', 'run'):
|
|
for lang in ('c', 'cpp'):
|
|
deffile = str(output / target.name / f"{lang}.{kind}")
|
|
|
|
build.build(
|
|
rule = f"dump_{lang}_{kind}",
|
|
outputs = [deffile],
|
|
implicit = [buildfilename],
|
|
)
|
|
build.default(deffile)
|
|
build.newline()
|
|
|
|
for mod in mods:
|
|
build.subninja(f"{mod}.ninja")
|