Files
jsix_import/scripts/bonnibel/module.py
Justin C. Miller c1d9b35e7c [bootproto] Create new bootproto lib
This is a rather large commit that is widely focused on cleaning things
out of the 'junk drawer' that is src/include. Most notably, several
things that were put in there because they needed somewhere where both
the kernel, boot, and init could read them have been moved to a new lib,
'bootproto'.

- Moved kernel_args.h and init_args.h to bootproto as kernel.h and
  init.h, respectively.

- Moved counted.h and pointer_manipulation.h into util, renaming the
  latter to util/pointers.h.

- Created a new src/include/arch for very arch-dependent definitions,
  and moved some kernel_memory.h constants like frame size, page table
  entry count, etc to arch/amd64/memory.h. Also created arch/memory.h
  which detects platform and includes the former.

- Got rid of kernel_memory.h entirely in favor of a new, cog-based
  approach. The new definitions/memory_layout.csv lists memory regions
  in descending order from the top of memory, their sizes, and whether
  they are shared outside the kernel (ie, boot needs to know them). The
  new header bootproto/memory.h exposes the addresses of the shared
  regions, while the kernel's memory.h gains the start and size of all
  the regions. Also renamed the badly-named page-offset area the linear
  area.

- The python build scripts got a few new features: the ability to parse
  the csv mentioned above in a new memory.py module; the ability to add
  dependencies to existing source files (The list of files that I had to
  pull out of the main list just to add them with the dependency on
  memory.h was getting too large. So I put them back into the sources
  list, and added the dependency post-hoc.); and the ability to
  reference 'source_root', 'build_root', and 'module_root' variables in
  .module files.

- Some utility functions that were in the kernel's memory.h got moved to
  util/pointers.h and util/misc.h, and misc.h's byteswap was renamed
  byteswap32 to be more specific.
2022-01-03 17:44:13 -08:00

195 lines
6.1 KiB
Python

def resolve(path):
if path.startswith('/') or path.startswith('$'):
return path
from pathlib import Path
return str(Path(path).resolve())
class Module:
__fields = {
# name: (type, default)
"kind": (str, "exe"),
"output": (str, None),
"targets": (set, ()),
"deps": (set, ()),
"includes": (tuple, ()),
"sources": (tuple, ()),
"variables": (dict, ()),
"default": (bool, False),
}
def __init__(self, name, modfile, root, **kwargs):
from .source import Source
# Required fields
self.root = root
self.name = name
self.modfile = modfile
for name, data in self.__fields.items():
ctor, default = data
value = kwargs.get(name, default)
if value is not None:
value = ctor(value)
setattr(self, name, value)
for name in kwargs:
if not name in self.__fields:
raise AttributeError(f"No attribute named {name} on Module")
# Turn strings into real Source objects
self.sources = [Source(root, f) for f in self.sources]
# Filled by Module.update
self.depmods = set()
def __str__(self):
return "Module {} {}\n\t{}".format(self.kind, self.name, "\n\t".join(map(str, self.sources)))
@property
def output(self):
if self.__output is not None:
return self.__output
if self.kind == "lib":
return f"lib{self.name}.a"
else:
return f"{self.name}.elf"
@output.setter
def output(self, value):
self.__output = value
@classmethod
def update(cls, mods):
from . import BonnibelError
for mod in mods.values():
for dep in mod.deps:
if not dep in mods:
raise BonnibelError(f"module '{mod.name}' references unknown module '{dep}'")
depmod = mods[dep]
mod.depmods.add(depmod)
target_mods = [mod for mod in mods.values() if mod.targets]
for mod in target_mods:
closed = set()
children = set(mod.depmods)
while children:
child = children.pop()
closed.add(child)
child.targets |= mod.targets
children |= {m for m in child.depmods if not m in closed}
def generate(self, output):
filename = str(output / f"{self.name}.ninja")
with open(filename, "w") as buildfile:
from pathlib import Path
from ninja.ninja_syntax import Writer
build = Writer(buildfile)
build.comment("This file is automatically generated by bonnibel")
build.newline()
build.variable("module_dir", f"${{target_dir}}/{self.name}.dir")
for key, value in self.variables.items():
build.variable(key, value)
build.newline()
includes = [self.root, "${module_dir}"]
for include in self.includes:
p = Path(include)
if p.is_absolute():
if not p in includes:
includes.append(str(p.resolve()))
elif include != ".":
includes.append(str(self.root / p))
includes.append(f"${{module_dir}}/{p}")
libs = []
order_only = []
closed = set()
children = set(self.depmods)
while children:
child = children.pop()
closed.add(child)
includes += [f"${{target_dir}}/{child.name}.dir/{i}" for i in child.includes]
includes += [f"{child.root}/{i}" for i in child.includes]
if child.kind == "lib":
libs.append(f"${{target_dir}}/{child.output}")
else:
order_only.append(f"${{target_dir}}/{child.output}")
children |= {m for m in child.depmods if not m in closed}
if includes:
build.variable("ccflags", ["${ccflags}"] + [f"-I{i}" for i in includes])
build.variable("asflags", ["${asflags}"] + [f"-I{i}" for i in includes])
if libs:
build.variable("libs", ["${libs}"] + libs)
inputs = []
implicits = []
for start in self.sources:
source = start
while source and source.action:
output = source.output
if source.action.rule:
build.build(
rule = source.action.rule,
outputs = output.input,
inputs = source.input,
implicit = list(map(resolve, source.deps)),
variables = {"name": source.name},
)
elif source.action.implicit:
implicits.append(source.input)
else:
inputs.append(source.input)
source = output
build.newline()
output = f"${{target_dir}}/{self.output}"
dump = f"${{target_dir}}/{self.output}.dump"
build.build(
rule = self.kind,
outputs = output,
inputs = inputs,
implicit = implicits + libs,
order_only = order_only,
)
build.newline()
build.build(
rule = "dump",
outputs = dump,
inputs = output,
variables = {"name": self.name},
)
if self.default:
build.newline()
build.default(output)
build.default(dump)
def add_input(self, path, **kwargs):
from .source import Source
s = Source(self.root, path, **kwargs)
self.sources.append(s)
return str(s.output)
def add_depends(self, paths, deps):
for source in self.sources:
if source.name in paths:
source.add_deps(deps)