mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
Bonnibel will now build dynamic libraries when they're dependencies for non-statically linked modules. It will also copy those shared libraries into the initrd image for programs being copied into the image.
294 lines
10 KiB
Python
294 lines
10 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
|
|
from os.path import join
|
|
from ninja.ninja_syntax import Writer
|
|
|
|
targets = set()
|
|
kinds = set()
|
|
for mod in modules.values():
|
|
targets.update(mod.targets)
|
|
kinds.add(mod.kind)
|
|
|
|
from .config import generate_configs
|
|
config_deps = generate_configs(root, output, config, targets, kinds)
|
|
|
|
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.variable("build_config", config)
|
|
build.newline()
|
|
|
|
build.include(root / "assets/build/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()
|
|
|
|
build.variable("cogflags", [
|
|
"-I", "${source_root}/scripts",
|
|
"-D", "definitions_path=${source_root}/definitions",
|
|
])
|
|
build.newline()
|
|
|
|
for target in targets:
|
|
build.subninja(output / target / "target.ninja")
|
|
build.newline()
|
|
|
|
build.build(
|
|
rule = "touch",
|
|
outputs = "${build_root}/.all_headers",
|
|
implicit = [f"${{build_root}}/include/{m.name}/.headers.phony"
|
|
for m in modules.values() if m.public_headers],
|
|
)
|
|
build.build(
|
|
rule = "phony",
|
|
outputs = ["all-headers"],
|
|
inputs = ["${build_root}/.all_headers"])
|
|
|
|
from .manifest import Manifest
|
|
manifest = Manifest(manifest_file, modules)
|
|
|
|
debugroot = output / ".debug"
|
|
debugroot.mkdir(exist_ok=True)
|
|
|
|
fatroot = output / "fatroot"
|
|
fatroot.mkdir(exist_ok=True)
|
|
|
|
(fatroot / manifest.location).mkdir(exist_ok=True)
|
|
|
|
initrdroot = output / "initrd_root"
|
|
initrdroot.mkdir(exist_ok=True)
|
|
|
|
fatroot_content = []
|
|
initrd_content = []
|
|
|
|
def add_fatroot(source, name):
|
|
output = join(manifest.location, name)
|
|
fatroot_output = f"${{build_root}}/fatroot/{output}"
|
|
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [fatroot_output],
|
|
inputs = [source],
|
|
variables = {
|
|
"description": f"Installing {output}",
|
|
})
|
|
|
|
fatroot_content.append(fatroot_output)
|
|
build.newline()
|
|
|
|
def add_fatroot_exe(entry):
|
|
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
|
|
intermediary = f"${{build_root}}/{entry.output}"
|
|
|
|
build.build(
|
|
rule = "strip",
|
|
outputs = [intermediary],
|
|
inputs = [input_path],
|
|
implicit = [f"{input_path}.dump"],
|
|
variables = {
|
|
"name": f"Stripping {entry.module}",
|
|
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
|
|
})
|
|
|
|
add_fatroot(intermediary, entry.output)
|
|
|
|
def add_initrd_content(root, name):
|
|
output = join(root, name)
|
|
initrd_output = f"${{build_root}}/initrd_root/{output}"
|
|
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [initrd_output],
|
|
inputs = [f"${{build_root}}/{name}"],
|
|
variables = {
|
|
"description": f"Installing {name}",
|
|
})
|
|
|
|
initrd_content.append(initrd_output)
|
|
build.newline()
|
|
|
|
def add_initrd_stripped(root, entry):
|
|
input_path = f"${{build_root}}/{entry.target}/{entry.output}"
|
|
intermediary = f"${{build_root}}/{entry.output}"
|
|
|
|
build.build(
|
|
rule = "strip",
|
|
outputs = [intermediary],
|
|
inputs = [input_path],
|
|
implicit = [f"{input_path}.dump"],
|
|
variables = {
|
|
"name": f"Stripping {entry.module}",
|
|
"debug": f"${{build_root}}/.debug/{entry.output}.debug",
|
|
})
|
|
|
|
add_initrd_content(root, entry.output)
|
|
|
|
add_fatroot_exe(manifest.kernel)
|
|
add_fatroot_exe(manifest.init)
|
|
for program in manifest.panics:
|
|
add_fatroot_exe(program)
|
|
|
|
for program in manifest.services:
|
|
add_initrd_stripped("jsix/services", program)
|
|
|
|
for program in manifest.drivers:
|
|
add_initrd_stripped("jsix/drivers", program)
|
|
|
|
for program in manifest.libs:
|
|
add_initrd_stripped("jsix/lib", program)
|
|
|
|
syms = manifest.add_data("symbol_table.dat",
|
|
"Symbol table", ("symbols",))
|
|
|
|
syms_file = "jsix.symbols"
|
|
syms_path = join(manifest.location, syms_file );
|
|
syms_out = join(fatroot, syms_path)
|
|
build.build(
|
|
rule = "makest",
|
|
outputs = [syms_out],
|
|
inputs = [f"${{build_root}}/kernel/{modules['kernel'].get_output(static=True)}"],
|
|
)
|
|
fatroot_content.append(syms_out)
|
|
manifest.symbols = syms_file
|
|
|
|
bootloader = "${build_root}/fatroot/efi/boot/bootx64.efi"
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [bootloader],
|
|
inputs = ["${build_root}/boot/boot.efi"],
|
|
variables = {
|
|
"description": "Installing bootloader",
|
|
})
|
|
build.newline()
|
|
|
|
boot_config = join(fatroot, "jsix", "boot.conf")
|
|
manifest.write_boot_config(boot_config)
|
|
|
|
initrd = str(fatroot / manifest.location / manifest.initrd["name"])
|
|
build.build(
|
|
rule = "makeinitrd",
|
|
outputs = [initrd],
|
|
inputs = [str(initrdroot)],
|
|
implicit = initrd_content + ["${source_root}/scripts/mkj6romfs.py"],
|
|
variables = {"format": manifest.initrd["format"]},
|
|
)
|
|
build.newline()
|
|
|
|
fatroot_content.append(initrd)
|
|
|
|
build.build(
|
|
rule = "makefat",
|
|
outputs = ["${build_root}/jsix.img"],
|
|
inputs = ["${source_root}/assets/diskbase.img"],
|
|
implicit = fatroot_content + [bootloader],
|
|
variables = {"name": "jsix.img"},
|
|
)
|
|
build.newline()
|
|
|
|
default_assets = {
|
|
"UEFI Variables": ("ovmf/x64/ovmf_vars.fd", "ovmf_vars.fd"),
|
|
"GDB Debug Helpers": ("debugging/jsix.elf-gdb.py", "jsix.elf-gdb.py"),
|
|
}
|
|
|
|
for name, assets in default_assets.items():
|
|
p = root / "assets" / assets[0]
|
|
out = f"${{build_root}}/{assets[1]}"
|
|
build.build(
|
|
rule = "cp",
|
|
outputs = [out],
|
|
inputs = [str(p)],
|
|
variables = {"name": name},
|
|
)
|
|
build.default([out])
|
|
build.newline()
|
|
|
|
compdb = "${source_root}/compile_commands.json"
|
|
|
|
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()]
|
|
|
|
regen_implicits += list(map(str, config_deps))
|
|
|
|
build.build(
|
|
rule = "compdb",
|
|
outputs = [compdb],
|
|
implicit = regen_implicits,
|
|
)
|
|
build.default([compdb])
|
|
build.newline()
|
|
|
|
build.build(
|
|
rule = "regen",
|
|
outputs = ['build.ninja'],
|
|
implicit = regen_implicits,
|
|
implicit_outputs =
|
|
[f"module.{mod.name}.ninja" for mod in modules.values()] +
|
|
[f"{target}/target.ninja" for target in targets] +
|
|
[boot_config],
|
|
)
|
|
|
|
build.newline()
|
|
build.default(["${build_root}/jsix.img"])
|
|
|
|
for target in targets:
|
|
mods = [m.name for m in modules.values() if target in m.targets]
|
|
|
|
targetdir = output / target
|
|
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)
|
|
build.variable("target_dir", output / target)
|
|
build.newline()
|
|
|
|
build.include(f"{target}/config.ninja")
|
|
|
|
build.newline()
|
|
for kind in ('defs', 'run'):
|
|
for lang in ('c', 'cpp'):
|
|
deffile = str(output / target / 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"module.{mod}.ninja")
|