shuriken: Refactor merged target configs
This commit is contained in:
parent
d5d480d854
commit
acd53e17d1
1 changed files with 47 additions and 17 deletions
|
|
@ -10,7 +10,6 @@
|
|||
############################################
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import json
|
||||
import shlex
|
||||
import subprocess
|
||||
|
|
@ -18,7 +17,7 @@ import sys
|
|||
from collections import namedtuple
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Any, Self
|
||||
|
||||
import yaml
|
||||
|
||||
|
|
@ -60,6 +59,38 @@ class TargetConfig:
|
|||
return f"{self.linker_args or ''} {self.linker_args_extra or ''}".strip()
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class MergedTargetConfig(TargetConfig):
|
||||
cpp_compiler: str = ''
|
||||
cpp_standard: str = ''
|
||||
cpp_flags: str = ''
|
||||
cpp_flags_extra: str = ''
|
||||
|
||||
linker_flags: str = ''
|
||||
linker_flags_extra: str = ''
|
||||
linker_args: str = ''
|
||||
linker_args_extra: str = ''
|
||||
|
||||
output_file: str = ''
|
||||
run_command: str = ''
|
||||
|
||||
@classmethod
|
||||
def create_from(cls, target_defaults: TargetConfig, target_config: TargetConfig) -> Self:
|
||||
merged_config = cls()
|
||||
merged_config.update(asdict(target_defaults))
|
||||
merged_config.update(asdict(target_config))
|
||||
return merged_config
|
||||
|
||||
def validate(self) -> None:
|
||||
# Validate that all required fields are set
|
||||
if not self.cpp_compiler:
|
||||
raise ConfigValidationException('cpp_compiler must be set')
|
||||
if not self.cpp_standard:
|
||||
raise ConfigValidationException('cpp_standard must be set')
|
||||
if not self.output_file:
|
||||
raise ConfigValidationException('output_file must be set')
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class ShurikenConfig:
|
||||
__path_fields = ['source_dir', 'build_dir']
|
||||
|
|
@ -72,9 +103,6 @@ class ShurikenConfig:
|
|||
defaults: TargetConfig = field(default_factory=lambda: TargetConfig(
|
||||
cpp_compiler='clang++',
|
||||
cpp_standard='c++20',
|
||||
cpp_flags='',
|
||||
linker_flags='',
|
||||
linker_args='',
|
||||
))
|
||||
|
||||
enable_import_std: bool = False
|
||||
|
|
@ -82,6 +110,9 @@ class ShurikenConfig:
|
|||
default_target: str = ''
|
||||
targets: dict[str, TargetConfig] = field(default_factory=dict)
|
||||
|
||||
# Merged target configs, generated from defaults and targets
|
||||
_merged_target_configs = {}
|
||||
|
||||
def update(self, data: dict) -> None:
|
||||
for key, value in data.items():
|
||||
# Ignore unknown config keys
|
||||
|
|
@ -116,6 +147,10 @@ class ShurikenConfig:
|
|||
else:
|
||||
setattr(self, key, str(value))
|
||||
|
||||
# Generate merged target configs (we generate all of them so that we can validate the full config)
|
||||
for target_name, target_config in self.targets.items():
|
||||
self._merged_target_configs[target_name] = MergedTargetConfig.create_from(self.defaults, target_config)
|
||||
|
||||
def update_from_yaml(self, file_path: Path) -> None:
|
||||
with file_path.open('r') as file:
|
||||
self.update(yaml.safe_load(file))
|
||||
|
|
@ -137,23 +172,18 @@ class ShurikenConfig:
|
|||
raise ConfigValidationException('default_target is not defined in targets')
|
||||
|
||||
# Validate individual build targets
|
||||
for target_name, target_config in self.targets.items():
|
||||
if not target_config.cpp_compiler and not self.defaults.cpp_compiler:
|
||||
raise ConfigValidationException(f'Target "{target_name}": cpp_compiler must be set')
|
||||
if not target_config.cpp_standard and not self.defaults.cpp_standard:
|
||||
raise ConfigValidationException(f'Target "{target_name}": cpp_standard must be set')
|
||||
if not target_config.output_file and not self.defaults.output_file:
|
||||
raise ConfigValidationException(f'Target "{target_name}": output_file must be set')
|
||||
for target_name, merged_target_config in self._merged_target_configs.items():
|
||||
try:
|
||||
merged_target_config.validate()
|
||||
except ConfigValidationException as exc:
|
||||
raise ConfigValidationException(f'Target "{target_name}": {str(exc)}')
|
||||
|
||||
def get_ninja_file_path(self, target: str) -> Path:
|
||||
return self.build_dir / f'build.{target}.ninja'
|
||||
|
||||
def get_merged_target_config(self, target: str) -> TargetConfig:
|
||||
def get_merged_target_config(self, target: str) -> MergedTargetConfig:
|
||||
assert target in self.targets, f'Target "{target}" not defined!'
|
||||
|
||||
merged_config = copy.deepcopy(self.defaults)
|
||||
merged_config.update(asdict(self.targets[target]))
|
||||
return merged_config
|
||||
return self._merged_target_configs[target]
|
||||
|
||||
|
||||
class ShurikenArgumentParser:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue