Implemented targets/base.py
This commit is contained in:
parent
9ea4edcc77
commit
387bbfd9fe
|
|
@ -0,0 +1,232 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Base target interface for the build system.
|
||||||
|
Defines the abstract Target class that all specific targets must implement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Optional
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class BuildType(Enum):
|
||||||
|
"""Type of build to perform."""
|
||||||
|
RELEASE = "release"
|
||||||
|
DEBUG = "debug"
|
||||||
|
TEST = "test"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class Target(ABC):
|
||||||
|
"""Abstract base class for all build targets."""
|
||||||
|
|
||||||
|
def __init__(self, name: str):
|
||||||
|
"""
|
||||||
|
Initialize the target.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Target name (e.g., "linux", "windows", "rp2040")
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
self._build_type = BuildType.RELEASE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def build_type(self) -> BuildType:
|
||||||
|
"""Get the current build type."""
|
||||||
|
return self._build_type
|
||||||
|
|
||||||
|
@build_type.setter
|
||||||
|
def build_type(self, value: BuildType) -> None:
|
||||||
|
"""Set the build type."""
|
||||||
|
self._build_type = value
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def build(self) -> bool:
|
||||||
|
"""
|
||||||
|
Build the target.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if build succeeded, False otherwise
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def clean(self) -> bool:
|
||||||
|
"""
|
||||||
|
Clean build artifacts for this target.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if clean succeeded, False otherwise
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self) -> bool:
|
||||||
|
"""
|
||||||
|
Run the built executable.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if execution succeeded, False otherwise
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: If the target doesn't support running
|
||||||
|
"""
|
||||||
|
raise NotImplementedError(f"Target '{self.name}' does not support running")
|
||||||
|
|
||||||
|
def test(self) -> bool:
|
||||||
|
"""
|
||||||
|
Build and run tests for this target.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if tests passed, False otherwise
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: If the target doesn't support testing
|
||||||
|
"""
|
||||||
|
raise NotImplementedError(f"Target '{self.name}' does not support testing")
|
||||||
|
|
||||||
|
def debug(self) -> bool:
|
||||||
|
"""
|
||||||
|
Launch debugger with the built executable.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if debugger launched successfully, False otherwise
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: If the target doesn't support debugging
|
||||||
|
"""
|
||||||
|
raise NotImplementedError(f"Target '{self.name}' does not support debugging")
|
||||||
|
|
||||||
|
def get_output_path(self) -> Optional[Path]:
|
||||||
|
"""
|
||||||
|
Get the path to the main output binary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path to output binary, or None if not applicable
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_test_output_path(self) -> Optional[Path]:
|
||||||
|
"""
|
||||||
|
Get the path to the test binary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path to test binary, or None if not applicable
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_build_dir(self) -> Optional[Path]:
|
||||||
|
"""
|
||||||
|
Get the build directory for this target.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Path to build directory, or None if using shared directories
|
||||||
|
"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
def supports_command(self, command: str) -> bool:
|
||||||
|
"""
|
||||||
|
Check if this target supports a specific command.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
command: Command name ("build", "run", "test", "debug", "clean")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if command is supported, False otherwise
|
||||||
|
"""
|
||||||
|
if command == "build":
|
||||||
|
return True
|
||||||
|
elif command == "clean":
|
||||||
|
return True
|
||||||
|
elif command == "run":
|
||||||
|
try:
|
||||||
|
# Check if run() is overridden
|
||||||
|
return type(self).run != Target.run
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
elif command == "test":
|
||||||
|
try:
|
||||||
|
return type(self).test != Target.test
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
elif command == "debug":
|
||||||
|
try:
|
||||||
|
return type(self).debug != Target.debug
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_sources(self, exclude: Optional[List[str]] = None) -> List[Path]:
|
||||||
|
"""
|
||||||
|
Get list of source files to compile.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
exclude: List of source file names to exclude
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of source file paths
|
||||||
|
"""
|
||||||
|
from build_system.config import get_config
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
sources = list(config.src_dir.glob("*.c"))
|
||||||
|
|
||||||
|
if exclude:
|
||||||
|
sources = [s for s in sources if s.name not in exclude]
|
||||||
|
|
||||||
|
return sources
|
||||||
|
|
||||||
|
def get_test_sources(self) -> List[Path]:
|
||||||
|
"""
|
||||||
|
Get list of test source files.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of test source file paths
|
||||||
|
"""
|
||||||
|
from build_system.config import get_config
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
if not config.test_dir.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
return list(config.test_dir.glob("*.c"))
|
||||||
|
|
||||||
|
def generate_tests(self) -> bool:
|
||||||
|
"""
|
||||||
|
Generate test files from YAML if needed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if generation succeeded or was not needed, False otherwise
|
||||||
|
"""
|
||||||
|
from build_system.config import get_config
|
||||||
|
from build_system.utils import run
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
script = config.test_script_path
|
||||||
|
yaml = config.test_yaml_path
|
||||||
|
output = config.test_output_file
|
||||||
|
|
||||||
|
if not script.exists() or not yaml.exists():
|
||||||
|
print("Test generation skipped (missing files).")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if output.exists() and output.stat().st_mtime > yaml.stat().st_mtime:
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
run([config.python_command, str(script), str(yaml), str(output)])
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: Test generation failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
"""String representation of the target."""
|
||||||
|
return f"{self.name}"
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
"""Detailed string representation."""
|
||||||
|
return f"Target(name='{self.name}', build_type={self.build_type})"
|
||||||
Loading…
Reference in New Issue