[build] Move headers out of target dirs
The great header shift: It didn't make sense to regenerate headers for the same module for every target (boot/kernel/user) it appeared in. And now that core headers are out of src/include, this was going to cause problems for the new libc changes I've been working on. So I went back to re-design how module headers work. Pre-requisites: - A module's public headers should all be available in one location, not tied to target. - No accidental includes. Another module should not be able to include anything (creating an implicit dependency) from a module without declaring an explicit dependency. - Exception to the previous: libc's headers should be available to all, at least for the freestanding headers. New system: - A new "public_headers" property of module declares all public headers that should be available to dependant modules - All public headers (after possible processing) are installed relative to build/include/<module> with the same path as their source - This also means no "include" dir in modules is necessary. If a header should be included as <j6/types.h> then its source should be src/libraries/j6/j6/types.h - this caused the most churn as all public header sources moved one directory up. - The "includes" property of a module is local only to that module now, it does not create any implicit public interface Other changes: - The bonnibel concept of sources changed: instead of sources having actions, they themselves are an instance of a (sub)class of Source, which provides all the necessary information itself. - Along with the above, rule names were standardized into <type>.<ext>, eg "compile.cpp" or "parse.cog" - cog and cogflags variables moved from per-target scope to global scope in the build files. - libc gained a more dynamic .module file
This commit is contained in:
@@ -1,87 +1,119 @@
|
||||
class Action:
|
||||
name = property(lambda self: self.__name)
|
||||
implicit = property(lambda self: False)
|
||||
rule = property(lambda self: None)
|
||||
deps = property(lambda self: tuple())
|
||||
parse_deps = property(lambda self: False)
|
||||
from os.path import join, splitext
|
||||
from . import mod_rel
|
||||
|
||||
def __init__(self, name):
|
||||
self.__name = name
|
||||
|
||||
def output_of(self, path):
|
||||
return None
|
||||
|
||||
|
||||
class Compile(Action):
|
||||
rule = property(lambda self: f'compile_{self.name}')
|
||||
deps = property(lambda self: ("${module_dir}/.parse_dep.phony",))
|
||||
parse_deps = property(lambda self: True)
|
||||
|
||||
def __init__(self, name, suffix = ".o"):
|
||||
super().__init__(name)
|
||||
self.__suffix = suffix
|
||||
|
||||
def output_of(self, path):
|
||||
return str(path) + self.__suffix
|
||||
|
||||
|
||||
class Parse(Action):
|
||||
rule = property(lambda self: f'parse_{self.name}')
|
||||
|
||||
def output_of(self, path):
|
||||
suffix = "." + self.name
|
||||
if path.suffix == suffix:
|
||||
return path.with_suffix('')
|
||||
def _resolve(path):
|
||||
if path.startswith('/') or path.startswith('$'):
|
||||
return path
|
||||
from pathlib import Path
|
||||
return str(Path(path).resolve())
|
||||
|
||||
|
||||
class Link(Action): pass
|
||||
|
||||
|
||||
class Header(Action):
|
||||
implicit = property(lambda self: True)
|
||||
def _dynamic_action(name):
|
||||
def prop(self):
|
||||
root, suffix = splitext(self.path)
|
||||
return f"{name}{suffix}"
|
||||
return prop
|
||||
|
||||
|
||||
class Source:
|
||||
Actions = {
|
||||
'.c': Compile('c'),
|
||||
'.cpp': Compile('cxx'),
|
||||
'.s': Compile('asm'),
|
||||
'.cog': Parse('cog'),
|
||||
'.o': Link('o'),
|
||||
'.h': Header('h'),
|
||||
'.inc': Header('inc'),
|
||||
}
|
||||
next = tuple()
|
||||
action = None
|
||||
args = dict()
|
||||
gather = False
|
||||
outputs = tuple()
|
||||
input = False
|
||||
|
||||
def __init__(self, root, path, output=None, deps=tuple()):
|
||||
from pathlib import Path
|
||||
self.__root = Path(root)
|
||||
self.__path = Path(path)
|
||||
self.__output = output
|
||||
self.__deps = tuple(deps)
|
||||
|
||||
def __str__(self):
|
||||
return self.input
|
||||
def __init__(self, path, root = "${module_dir}", deps=tuple()):
|
||||
self.path = path
|
||||
self.root = root
|
||||
self.deps = deps
|
||||
|
||||
def add_deps(self, deps):
|
||||
self.__deps += tuple(deps)
|
||||
self.deps += tuple(deps)
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
suffix = self.__path.suffix
|
||||
return self.Actions.get(suffix)
|
||||
def fullpath(self):
|
||||
return join(self.root, self.path)
|
||||
|
||||
class ParseSource(Source):
|
||||
action = property(_dynamic_action("parse"))
|
||||
|
||||
@property
|
||||
def output(self):
|
||||
if not self.action:
|
||||
return None
|
||||
root, _ = splitext(self.path)
|
||||
return root
|
||||
|
||||
path = self.__output
|
||||
if path is None:
|
||||
path = self.action.output_of(self.__path)
|
||||
@property
|
||||
def outputs(self):
|
||||
return (self.output,)
|
||||
|
||||
return path and Source("${module_dir}", path)
|
||||
@property
|
||||
def gather(self):
|
||||
_, suffix = splitext(self.output)
|
||||
return suffix in (".h", ".inc")
|
||||
|
||||
deps = property(lambda self: self.__deps)
|
||||
name = property(lambda self: str(self.__path))
|
||||
input = property(lambda self: str(self.__root / self.__path))
|
||||
@property
|
||||
def next(self):
|
||||
_, suffix = splitext(self.output)
|
||||
nextType = {
|
||||
".s": CompileSource,
|
||||
".cpp": CompileSource,
|
||||
}.get(suffix)
|
||||
|
||||
if nextType:
|
||||
return (nextType(self.output),)
|
||||
return tuple()
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
return dict(
|
||||
outputs = list(map(mod_rel, self.outputs)),
|
||||
inputs = [self.fullpath],
|
||||
implicit = list(map(_resolve, self.deps)),
|
||||
variables = dict(name=self.path),
|
||||
)
|
||||
|
||||
class HeaderSource(Source):
|
||||
action = "cp"
|
||||
gather = True
|
||||
|
||||
@property
|
||||
def outputs(self):
|
||||
return (self.path,)
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
return dict(
|
||||
outputs = [mod_rel(self.path)],
|
||||
inputs = [join(self.root, self.path)],
|
||||
implicit = list(map(_resolve, self.deps)),
|
||||
variables = dict(name=self.path),
|
||||
)
|
||||
|
||||
class CompileSource(Source):
|
||||
action = property(_dynamic_action("compile"))
|
||||
input = True
|
||||
|
||||
@property
|
||||
def outputs(self):
|
||||
return (self.path + ".o",)
|
||||
|
||||
@property
|
||||
def args(self):
|
||||
return dict(
|
||||
outputs = list(map(mod_rel, self.outputs)),
|
||||
inputs = [join(self.root, self.path)],
|
||||
implicit = list(map(_resolve, self.deps)) + [mod_rel(".headers.phony")],
|
||||
variables = dict(name=self.path),
|
||||
)
|
||||
|
||||
def make_source(root, path):
|
||||
_, suffix = splitext(path)
|
||||
|
||||
if suffix in (".s", ".c", ".cpp"):
|
||||
return CompileSource(path, root)
|
||||
elif suffix in (".cog",):
|
||||
return ParseSource(path, root)
|
||||
elif suffix in (".h", ".inc"):
|
||||
return HeaderSource(path, root)
|
||||
else:
|
||||
raise RuntimeError(f"{path} has no Source type")
|
||||
|
||||
Reference in New Issue
Block a user