meta: replace cmake mono-build system with a custom build co-ordinator
every system component now has its own self-contained build system, and a seed file describing the component and its build system and dependencies. a new tool, meadow, collects and uses these seed files to build the components into a full system. meadow also manages the target system root and a host prefix where toolchain tools are installed to. the build system has also been updated to use a new $ARCH-rosetta-gcc compiler, and the patches files necessary to build it have been added to toolchain/cross-compiler.
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
import os
|
||||
import sys
|
||||
import tomli
|
||||
from dependency import *
|
||||
from cmake import CMakeBuildSystem
|
||||
from publish import Publish
|
||||
from build import UnknownBuildSystemError
|
||||
from env import Environment
|
||||
from source_only import SourceOnlyBuildSystem
|
||||
from generic import GenericBuildSystem
|
||||
|
||||
|
||||
all_seeds = {}
|
||||
|
||||
|
||||
class SeedParseError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Seed(DependencyItem):
|
||||
def all_seeds():
|
||||
return all_seeds
|
||||
|
||||
|
||||
def get(name):
|
||||
if name in all_seeds:
|
||||
return all_seeds[name]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def load_file(self, path):
|
||||
with open(path, mode='rb') as f:
|
||||
self.__data = tomli.load(f)
|
||||
|
||||
|
||||
def __init_dependencies(self):
|
||||
self.__dependencies = {}
|
||||
|
||||
if 'dependency' not in self.__data:
|
||||
return
|
||||
|
||||
dependency = self.__data['dependency']
|
||||
if 'seeds' in dependency:
|
||||
seeds = dependency['seeds']
|
||||
self.__dependencies = {}
|
||||
for s in seeds:
|
||||
self.__dependencies[s] = SeedDependency(parent=self.name(), name=s)
|
||||
|
||||
|
||||
def __init_build_system(self):
|
||||
self.__build_system = None
|
||||
if 'build' not in self.__data:
|
||||
return
|
||||
|
||||
build = self.__data['build']
|
||||
if 'build_system' not in build:
|
||||
return
|
||||
|
||||
source_dir = os.path.dirname(self.__seed_path)
|
||||
bin_dir = os.path.join(Environment.build_root(), self.name())
|
||||
install = self.__data.get('install', None)
|
||||
|
||||
if 'source_dir' in build:
|
||||
source_dir = build['source_dir']
|
||||
|
||||
match build['build_system']:
|
||||
case 'none':
|
||||
self.__build_system = None
|
||||
case 'cmake':
|
||||
self.__build_system = CMakeBuildSystem(
|
||||
parent=self,
|
||||
name=self.name(),
|
||||
source_dir=source_dir,
|
||||
bin_dir=bin_dir,
|
||||
install=install,
|
||||
data=build)
|
||||
case 'source-only':
|
||||
self.__build_system = SourceOnlyBuildSystem(
|
||||
parent=self,
|
||||
name=self.name(),
|
||||
source_dir=source_dir,
|
||||
bin_dir=bin_dir,
|
||||
install=install,
|
||||
data=build)
|
||||
case 'generic':
|
||||
self.__build_system = GenericBuildSystem(
|
||||
parent=self,
|
||||
name=self.name(),
|
||||
source_dir=source_dir,
|
||||
bin_dir=bin_dir,
|
||||
install=install,
|
||||
data=build)
|
||||
case _:
|
||||
raise UnknownBuildSystemError(
|
||||
'Seed {} has unrecognised build system "{}"'.format(self.name(), build['build_system']))
|
||||
|
||||
|
||||
def __init_publish(self):
|
||||
install_path = Environment.system_root()
|
||||
if 'build' in self.__data and 'build_for' in self.__data['build']:
|
||||
build_for = self.__data['build']['build_for']
|
||||
if build_for == 'host':
|
||||
install_path = Environment.native_root()
|
||||
|
||||
self.__publish = None
|
||||
if 'publish' not in self.__data:
|
||||
return
|
||||
|
||||
self.__publish = Publish(install_path=install_path, data=self.__data['publish'])
|
||||
|
||||
|
||||
def add_dependency(self, name, dep):
|
||||
self.__dependencies[name] = dep
|
||||
|
||||
|
||||
def collect_dependencies(self, **kwargs):
|
||||
ctx = None
|
||||
if 'ctx' in kwargs:
|
||||
ctx = kwargs['ctx']
|
||||
else:
|
||||
ctx = {}
|
||||
|
||||
for k, d in self.__dependencies.items():
|
||||
if k in ctx:
|
||||
continue
|
||||
|
||||
ctx[d.name()] = d.target()
|
||||
if isinstance(d.target(), Seed):
|
||||
d.target().collect_dependencies(ctx=ctx)
|
||||
|
||||
return list(ctx.values())
|
||||
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__()
|
||||
|
||||
if not 'path' in kwargs:
|
||||
return
|
||||
|
||||
self.__seed_path = kwargs['path']
|
||||
self.load_file(kwargs['path'])
|
||||
self.__init_dependencies()
|
||||
self.__init_build_system()
|
||||
self.__init_publish()
|
||||
|
||||
|
||||
def seed_path(self):
|
||||
return self.__seed_path
|
||||
|
||||
|
||||
def name(self):
|
||||
if not 'seed' in self.__data:
|
||||
return None
|
||||
|
||||
s = self.__data['seed']
|
||||
if 'name' in s:
|
||||
return s['name']
|
||||
return None
|
||||
|
||||
|
||||
def type(self):
|
||||
if not 'seed' in self.__data:
|
||||
return None
|
||||
|
||||
s = self.__data['seed']
|
||||
if 'type' in s:
|
||||
return s['type']
|
||||
return 'component'
|
||||
|
||||
|
||||
def dependencies(self):
|
||||
return self.__dependencies
|
||||
|
||||
|
||||
def publish(self):
|
||||
return self.__publish
|
||||
|
||||
|
||||
def install(self):
|
||||
return self.__data.get('install', None)
|
||||
|
||||
|
||||
def should_include_standard_dependencies(self):
|
||||
if 'dependency' not in self.__data:
|
||||
return True
|
||||
|
||||
s = self.__data['dependency']
|
||||
if 'no_standard_dependencies' in s:
|
||||
return not s['no_standard_dependencies']
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def build_system(self):
|
||||
return self.__build_system
|
||||
|
||||
|
||||
def scan_directory(paths):
|
||||
for p in paths:
|
||||
for root, dirs, files in os.walk(p):
|
||||
for f in files:
|
||||
if not f.endswith('.seed'):
|
||||
continue
|
||||
seed_path = os.path.join(root, f)
|
||||
seed = None
|
||||
try:
|
||||
seed = Seed(path=seed_path)
|
||||
except tomli.TOMLDecodeError as e:
|
||||
raise SeedParseError('Err: Failed to parse seed file {}: {}'.format(seed_path, e))
|
||||
|
||||
all_seeds[seed.name()] = seed
|
||||
|
||||
|
||||
def resolve_all():
|
||||
for s in all_seeds.values():
|
||||
deps = s.dependencies()
|
||||
for k, v in deps.items():
|
||||
v.resolve()
|
||||
Reference in New Issue
Block a user