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,237 @@
|
||||
import os
|
||||
import shutil
|
||||
from command import Command
|
||||
from config import Config
|
||||
from cache import Cache
|
||||
from seed import Seed
|
||||
from target import Target
|
||||
from env import Environment
|
||||
from platform import Platform
|
||||
from colorama import Fore, Style
|
||||
|
||||
|
||||
class SetCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='set',
|
||||
description='Set a configuration key value.')
|
||||
|
||||
|
||||
def run(self, args):
|
||||
key = args.get_positional(0)
|
||||
value = args.get_positional(1)
|
||||
|
||||
if key is None or value is None:
|
||||
print('usage: meadow set <key> <value>')
|
||||
return -1
|
||||
|
||||
try:
|
||||
value_i = int(value)
|
||||
Config.set(key, value_i)
|
||||
except:
|
||||
Config.set(key, value)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class SeedsCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='seeds',
|
||||
description='List all available seeds.')
|
||||
|
||||
|
||||
def write_dot(self, path):
|
||||
f = open(path, mode='w')
|
||||
f.write('digraph seeds {\n')
|
||||
f.write(' node [shape=Mrecord];\n')
|
||||
nodes = {}
|
||||
|
||||
seeds = Seed.all_seeds()
|
||||
targets = Target.all_targets()
|
||||
for s in seeds.values():
|
||||
if s.name() in nodes:
|
||||
continue
|
||||
|
||||
sname = s.name().replace('-', '_')
|
||||
nodes[s.name()] = s
|
||||
f.write(' {} [label="{}"];\n'.format(sname, s.name()))
|
||||
|
||||
for d in s.dependencies().values():
|
||||
continue
|
||||
|
||||
|
||||
for t in targets.values():
|
||||
if t.name() in nodes:
|
||||
continue
|
||||
|
||||
t.resolve()
|
||||
tname = t.name().replace('-', '_')
|
||||
nodes[t.name()] = t
|
||||
f.write(' {} [label="{}",shape=hexagon];\n'.format(tname, t.name()))
|
||||
|
||||
for s in seeds.values():
|
||||
for k, d in s.dependencies().items():
|
||||
if d.name() not in nodes:
|
||||
nodes[d.name()] = d
|
||||
dname = d.name().replace('-', '_')
|
||||
f.write(' {} [label="{}",shape=diamond];\n'.format(dname, d.name()))
|
||||
|
||||
sname = s.name().replace('-', '_')
|
||||
dname = d.name().replace('-', '_')
|
||||
|
||||
if d.is_resolved():
|
||||
f.write(' {} -> {};\n'.format(dname, sname))
|
||||
else:
|
||||
f.write(' {} -> {}[style=dotted];\n'.format(dname, sname))
|
||||
|
||||
for t in targets.values():
|
||||
for k, d in t.dependencies().items():
|
||||
tname = t.name().replace('-', '_')
|
||||
dname = d.name().replace('-', '_')
|
||||
|
||||
if d.is_resolved():
|
||||
f.write(' {} -> {};\n'.format(dname, tname))
|
||||
else:
|
||||
f.write(' {} -> {}[style=dotted];\n'.format(dname, tname))
|
||||
|
||||
f.write('}\n')
|
||||
f.close()
|
||||
|
||||
|
||||
def run(self, args):
|
||||
seeds = Seed.all_seeds()
|
||||
|
||||
dot_path = args.get_named('to-dot-file', 0, 1)
|
||||
if dot_path is not None:
|
||||
self.write_dot(dot_path)
|
||||
return 0
|
||||
|
||||
for s in seeds.values():
|
||||
print('{}'.format(s.name()))
|
||||
|
||||
|
||||
class PlatformsCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='platforms',
|
||||
description='List all available platforms')
|
||||
|
||||
|
||||
def run(self, args):
|
||||
print('Supported platforms:')
|
||||
|
||||
platforms = Platform.all_platforms()
|
||||
current_platform = Platform.current_platform()
|
||||
|
||||
for p in platforms.values():
|
||||
if current_platform is not None and p.name() == current_platform.name():
|
||||
print(f'* {Fore.GREEN}{p.name()}{Style.RESET_ALL}')
|
||||
else:
|
||||
print(f' {p.name()}')
|
||||
|
||||
|
||||
class HelpCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='help',
|
||||
description='List all available commands.')
|
||||
|
||||
|
||||
def run(self, args):
|
||||
print('Available commands:')
|
||||
|
||||
commands = Command.all_commands()
|
||||
max_len = 0
|
||||
|
||||
for c in commands.values():
|
||||
if len(c.name()) > max_len:
|
||||
max_len = len(c.name())
|
||||
|
||||
max_len += 5
|
||||
for c in commands.values():
|
||||
print(' ', end='')
|
||||
print(c.name(), end='')
|
||||
|
||||
for i in range(len(c.name()), max_len):
|
||||
print(' ', end='')
|
||||
|
||||
print(c.description())
|
||||
|
||||
|
||||
class BuildCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='build',
|
||||
description='Build the currently selected target.')
|
||||
|
||||
|
||||
def run(self, args):
|
||||
verbose = args.get_named('verbose', 0, 0)
|
||||
|
||||
current_target = Target.current_target()
|
||||
if current_target is None:
|
||||
print(f'{Fore.RED}Err:{Style.RESET_ALL} no build target has been set. Use `meadow set target.name <...>` to specify which target to build')
|
||||
return -1
|
||||
|
||||
current_platform = Platform.current_platform()
|
||||
if current_platform is None:
|
||||
print(f'{Fore.RED}Err:{Style.RESET_ALL} no target platform has been set. Use `meadow set target.platform <...>` to specify which platform to target')
|
||||
return -1
|
||||
|
||||
components = current_target.resolve()
|
||||
|
||||
for c in components:
|
||||
build_system = None
|
||||
if isinstance(c, Seed):
|
||||
build_system = c.build_system()
|
||||
build_system.check_out_of_date()
|
||||
|
||||
for c in components:
|
||||
build_system = None
|
||||
if isinstance(c, Seed):
|
||||
build_system = c.build_system()
|
||||
|
||||
if build_system is not None:
|
||||
out_of_date = \
|
||||
build_system.is_configuration_out_of_date() \
|
||||
or build_system.is_build_out_of_date()
|
||||
|
||||
if out_of_date:
|
||||
print(f'{Fore.GREEN}>>>{Style.RESET_ALL} Building {c.name()}')
|
||||
|
||||
if build_system.is_configuration_out_of_date():
|
||||
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Configuring build...')
|
||||
build_system.configure(verbose=verbose)
|
||||
|
||||
if out_of_date:
|
||||
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Building...')
|
||||
build_system.build(verbose=verbose)
|
||||
print(f'{Fore.CYAN} >>{Style.RESET_ALL} Installing...')
|
||||
build_system.install(verbose=verbose)
|
||||
|
||||
print(f'{Style.BRIGHT}{Fore.GREEN}>>> Build Complete!{Style.RESET_ALL}')
|
||||
|
||||
|
||||
class CleanCommand(Command):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name='clean',
|
||||
description='Delete all build-related files.')
|
||||
|
||||
|
||||
def run(self, args):
|
||||
build_dir = Environment.build_root()
|
||||
|
||||
for i in os.listdir(build_dir):
|
||||
if i.startswith('meadow') and ('cache' not in i):
|
||||
continue
|
||||
|
||||
ipath = os.path.join(build_dir, i)
|
||||
if os.path.isdir(ipath):
|
||||
shutil.rmtree(ipath)
|
||||
else:
|
||||
os.remove(ipath)
|
||||
|
||||
Cache.reset()
|
||||
return 0
|
||||
Reference in New Issue
Block a user