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