diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..bc9b234 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,37 @@ +name: unit-tests + +on: + pull_request: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install coverage pytest + python -m pip install . + + - name: Run rests + run: | + coverage run -m pytest -v -s + + - name: Generate coverage report + run: | + coverage report -m diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4229458..14b5f7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,14 +3,15 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - - id: check-json # checks that all json files have proper syntax - - id: check-toml # checks that all toml files have proper syntax - - id: debug-statements # check for debug statements + - id: check-json + - id: check-toml + - id: check-yaml + - id: debug-statements exclude: '^(src/aedifix/main.py|src/aedifix/templates/.*)$' # intentional - - id: end-of-file-fixer # check all files end in a newline + - id: end-of-file-fixer - id: pretty-format-json args: ['--autofix', '--indent=4'] - - id: trailing-whitespace # remove trailing whitespace + - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: @@ -41,6 +42,13 @@ repos: pass_filenames: false args: ['src', 'tests'] additional_dependencies: [pytest, rich] + - repo: https://github.com/rhysd/actionlint + rev: v1.7.7 + hooks: + - id: actionlint + types: [yaml] + files: ^\.github/workflows/ + entry: env SHELLCHECK_OPTS="--enable=all --severity=style" actionlint ci: autoupdate_schedule: quarterly diff --git a/pyproject.toml b/pyproject.toml index e204b3f..2890882 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ ] dependencies = [ "rich", + "typing_extensions", ] dynamic = ["version"] diff --git a/src/aedifix/manager.py b/src/aedifix/manager.py index 1950aa9..b11754b 100644 --- a/src/aedifix/manager.py +++ b/src/aedifix/manager.py @@ -25,7 +25,6 @@ from .cmake.cmaker import CMaker from .config import ConfigFile from .logger import Logger -from .package import packages from .reconfigure import Reconfigure from .util.argument_parser import ConfigArgument from .util.callables import classify_callable, get_calling_function @@ -495,6 +494,29 @@ def gen_summary() -> Iterator[str]: align="left", ) + def _collect_deps(self) -> set[type[Package]]: + """Collect all transitive dependencies of the main package. + + Returns + ------- + dependencies: set[type[Package]] + The collected dependencies. + + """ + # perform an iterative Depth-First Search to collect all dependencies + # that are reachable starting from the main package dependencies. + # ref: https://en.wikipedia.org/wiki/Depth-first_search#Pseudocode + + seen: set[type[Package]] = set() + stack: list[type[Package]] = list(self._main_package.dependencies) + + while stack: + if (dep := stack.pop()) not in seen: + seen.add(dep) + stack.extend(x for x in dep.dependencies if x not in seen) + + return seen + # Member variable access @property def argv(self) -> tuple[str, ...]: @@ -954,9 +976,9 @@ def setup(self) -> None: """ self._setup_log() self.log_execute_func(self._log_git_info) - self._modules.extend( - self.log_execute_func(packages.load_packages, self) - ) + + packages = self.log_execute_func(self._collect_deps) + self._modules.extend(cls(self) for cls in packages) # Sort the modules alphabetically for the parsing of arguments, but # keep the main package on top. diff --git a/src/aedifix/package/main_package.py b/src/aedifix/package/main_package.py index 9ff82d4..5be9522 100644 --- a/src/aedifix/package/main_package.py +++ b/src/aedifix/package/main_package.py @@ -146,6 +146,10 @@ class DebugConfigureValue(IntEnum): TRACE = 2 TRACE_EXPAND = 3 + # Enum formatatting changed in 3.11, this is only needed for 3.10 + def __str__(self) -> str: + return str(int(self.value)) + @classmethod def from_string(cls, str_val: str) -> DebugConfigureValue: return cls(int(str_val)) @@ -364,7 +368,6 @@ class MainPackage(Package, ABC): def __init__( # noqa: PLR0913 self, manager: ConfigurationManager, - name: str, argv: Sequence[str], arch_name: str, project_dir_name: str, @@ -372,7 +375,6 @@ def __init__( # noqa: PLR0913 project_config_file_template: Path, project_src_dir: Path | None = None, default_arch_file_path: Path | None = None, - dependencies: tuple[type[Package], ...] = (), ) -> None: r"""Construct the MainPackage. @@ -380,8 +382,6 @@ def __init__( # noqa: PLR0913 ---------- manager : ConfigurationManager The configuration manager that will manage the main package. - name : str - The name of the main package, e.g. 'Legate'. argv : Sequence[str] The command line options. arch_name : str @@ -409,12 +409,7 @@ def __init__( # noqa: PLR0913 If the project arch value is set (either from command line or environment variable) but empty. """ - super().__init__( - manager=manager, - name=name, - always_enabled=True, - dependencies=dependencies, - ) + super().__init__(manager=manager, always_enabled=True) assert not arch_name.startswith("-") assert not arch_name.endswith("_") assert arch_name.isupper() diff --git a/src/aedifix/package/package.py b/src/aedifix/package/package.py index 1c6f783..ea05e73 100644 --- a/src/aedifix/package/package.py +++ b/src/aedifix/package/package.py @@ -30,6 +30,12 @@ def __getattr__(self, value: str) -> Package: class Package(Configurable): + #: A name for the package, e.g. 'CUDA'. + name: str + + # Other package (types) that this package depends on + dependencies: tuple[type[Package], ...] = () + __slots__ = "_always_enabled", "_dep_types", "_deps", "_name", "_state" @dataclass(slots=True, frozen=True) @@ -56,12 +62,7 @@ def implicitly_disabled(self) -> bool: return self.disabled() and (not self.explicit) def __init__( - self, - manager: ConfigurationManager, - name: str, - *, - always_enabled: bool = False, - dependencies: tuple[type[Package], ...] = (), + self, manager: ConfigurationManager, *, always_enabled: bool = False ) -> None: r"""Construct a Package. @@ -69,8 +70,6 @@ def __init__( ---------- manager : ConfigurationManager The configuration manager to manage this package. - name : str - The name of the package, e.g. 'CUDA'. always_enabled : bool, False Whether this package should be considered unconditionally enabled. """ @@ -81,23 +80,11 @@ def __init__( if isinstance(self, MainPackage): always_enabled = True - self._name = name self._state = Package.EnableState(value=always_enabled) self._always_enabled = always_enabled - self._dep_types = dependencies + self._dep_types = self.dependencies self._deps: Dependencies | None = None - @property - def name(self) -> str: - r"""Get the name of the package. - - Returns - ------- - name : str - The name of the package, e.g. 'Legion'. - """ - return self._name - @property def state(self) -> EnableState: r"""Get whether the package is enabled or disabled. diff --git a/src/aedifix/package/packages/__init__.py b/src/aedifix/package/packages/__init__.py index d220107..c655e05 100644 --- a/src/aedifix/package/packages/__init__.py +++ b/src/aedifix/package/packages/__init__.py @@ -2,45 +2,3 @@ # All rights reserved. # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations - -import importlib -from pathlib import Path -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - from ..package import Package - - -def load_packages(manager: ConfigurationManager) -> list[Package]: - r"""Load all package modules in the packages directory, and return the - constructed packages. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager with which to construct the packages. - - Returns - ------- - packages : list[Package] - The list of loaded packages. - """ - assert __package__, "Cannot auto-load packages without relative imports!" - packages = [] - cur_dir = Path(__file__).parent - manager.log(f"Using package directory: {cur_dir}") - for module_file in cur_dir.iterdir(): - manager.log(f"Attempting to load package: {module_file}") - if module_file.is_dir() or module_file.name.startswith("_"): - # skip __init__.py, __pycache__ and any other directories - manager.log( - f"Skipping loading package: {module_file} is not a package!" - ) - continue - module = importlib.import_module(f".{module_file.stem}", __package__) - manager.log(f"Loaded package: {module}") - conf_obj = module.create_package(manager) - manager.log(f"Adding package: {conf_obj}") - packages.append(conf_obj) - return packages diff --git a/src/aedifix/package/packages/cal.py b/src/aedifix/package/packages/cal.py deleted file mode 100644 index 44246ae..0000000 --- a/src/aedifix/package/packages/cal.py +++ /dev/null @@ -1,55 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class CAL(Package): - With_CAL: Final = ConfigArgument( - name="--with-cal", - spec=ArgSpec( - dest="with_cal", type=bool, help="Build with CAL support." - ), - enables_package=True, - primary=True, - ) - CAL_DIR: Final = ConfigArgument( - name="--with-cal-dir", - spec=ArgSpec( - dest="cal_dir", - type=Path, - help="Path to CAL installation directory.", - ), - cmake_var=CMAKE_VARIABLE("CAL_DIR", CMakePath), - enables_package=True, - ) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a CAL Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="CAL") - - def configure(self) -> None: - r"""Configure CAL.""" - super().configure() - if self.state.enabled(): - self.set_flag_if_user_set(self.CAL_DIR, self.cl_args.cal_dir) - - -def create_package(manager: ConfigurationManager) -> CAL: - return CAL(manager) diff --git a/src/aedifix/package/packages/cmake.py b/src/aedifix/package/packages/cmake.py index 1a9ab95..ccc3df3 100644 --- a/src/aedifix/package/packages/cmake.py +++ b/src/aedifix/package/packages/cmake.py @@ -36,6 +36,8 @@ def _determine_default_generator() -> str | None: class CMake(Package): + name = "CMake" + CMAKE_COMMAND: Final = ConfigArgument( name="--cmake-executable", spec=ArgSpec( @@ -67,7 +69,7 @@ def __init__(self, manager: ConfigurationManager) -> None: manager : ConfigurationManager The configuration manager to manage this package. """ - super().__init__(manager=manager, name="CMake", always_enabled=True) + super().__init__(manager=manager, always_enabled=True) def configure_cmake_version(self) -> None: r"""Determine the version of the cmake executable. diff --git a/src/aedifix/package/packages/cuda.py b/src/aedifix/package/packages/cuda.py deleted file mode 100644 index cb0ab2c..0000000 --- a/src/aedifix/package/packages/cuda.py +++ /dev/null @@ -1,195 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -import os -import shutil -from argparse import Action, ArgumentParser, Namespace -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakeExecutable, CMakeList, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from collections.abc import Sequence - - from ...manager import ConfigurationManager - - -def _guess_cuda_compiler() -> str | None: - for env_guess in ("CUDAC", "CMAKE_CUDA_COMPILER"): - if guess := os.environ.get(env_guess): - return guess - for ccguess in ("nvcc", "cudac"): - if guess := shutil.which(ccguess): - return guess - return None - - -class CudaArchAction(Action): - @staticmethod - def map_cuda_arch_names(in_arch: str) -> list[str]: - arch_map = { - "pascal": "60", - "volta": "70", - "turing": "75", - "ampere": "80", - "ada": "89", - "hopper": "90", - "blackwell": "100", - # TODO(jfaibussowit): rubin? - } - arch = [] - for sub_arch in in_arch.split(","): - # support Turing, TURING, and, if the user is feeling spicy, tUrInG - sub_arch_lo = sub_arch.strip().casefold() - if not sub_arch_lo: - # in_arch = "something,,something_else" - continue - arch.append(arch_map.get(sub_arch_lo, sub_arch_lo)) - return arch - - def __call__( - self, - parser: ArgumentParser, # noqa: ARG002 - namespace: Namespace, - values: str | Sequence[str] | None, - option_string: str | None = None, # noqa: ARG002 - ) -> None: - if isinstance(values, (list, tuple)): - str_values = ",".join(values) - elif isinstance(values, str): - str_values = values - elif values is None: - str_values = getattr(namespace, self.dest) - else: - raise TypeError(type(values)) - - cuda_arch = self.map_cuda_arch_names(str_values) - setattr(namespace, self.dest, cuda_arch) - - -class CUDA(Package): - With_CUDA: Final = ConfigArgument( - name="--with-cuda", - spec=ArgSpec( - dest="with_cuda", - type=bool, - default=shutil.which("nvcc") is not None, - help="Build with CUDA support.", - ), - enables_package=True, - primary=True, - ) - CUDAToolkit_ROOT: Final = ConfigArgument( - name="--with-cuda-dir", - spec=ArgSpec( - dest="cuda_dir", - type=Path, - default=os.environ.get("CUDA_HOME"), - required=False, - help="Path to CUDA installation directory.", - ), - cmake_var=CMAKE_VARIABLE("CUDAToolkit_ROOT", CMakePath), - enables_package=True, - ) - CMAKE_CUDA_COMPILER: Final = ConfigArgument( - name="--with-cudac", - spec=ArgSpec( - dest="CUDAC", - type=Path, - default=_guess_cuda_compiler(), - help="Specify CUDA compiler", - ), - cmake_var=CMAKE_VARIABLE("CMAKE_CUDA_COMPILER", CMakeExecutable), - enables_package=True, - ) - CMAKE_CUDA_FLAGS: Final = ConfigArgument( - name="--CUDAFLAGS", - spec=ArgSpec(dest="CUDAFLAGS", nargs=1, help="CUDA compiler flags"), - cmake_var=CMAKE_VARIABLE("CMAKE_CUDA_FLAGS", CMakeList), - ) - CMAKE_CUDA_ARCHITECTURES: Final = ConfigArgument( - name="--cuda-arch", - spec=ArgSpec( - dest="cuda_arch", - required=False, - default=["all-major"], - action=CudaArchAction, - help=( - "Specify the target GPU architecture. Available choices are: " - "'all-major', 'all', 'native', a comma-separated list of " - "numbers: '60' or '70, 80', or comma-separated list of names " - "'ampere' or 'hopper, blackwell'" - ), - ), - cmake_var=CMAKE_VARIABLE("CMAKE_CUDA_ARCHITECTURES", CMakeList), - ) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a CUDA Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="CUDA") - - def configure(self) -> None: - r"""Configure CUDA.""" - super().configure() - if not self.state.enabled(): - return - - self.set_flag_if_user_set(self.CMAKE_CUDA_COMPILER, self.cl_args.CUDAC) - self._configure_language_flags( - self.CMAKE_CUDA_FLAGS, self.cl_args.CUDAFLAGS - ) - self.append_flags_if_set( - self.CMAKE_CUDA_ARCHITECTURES, self.cl_args.cuda_arch - ) - self.set_flag_if_user_set(self.CUDAToolkit_ROOT, self.cl_args.cuda_dir) - - def summarize(self) -> str: - r"""Summarize CUDA. - - Returns - ------- - summary : str - A summary of configured CUDA. - """ - if not self.state.enabled(): - return "" - - arches: list[str] | str | None = self.manager.get_cmake_variable( - self.CMAKE_CUDA_ARCHITECTURES - ) - if not arches: - arches = [] - if isinstance(arches, (list, tuple)): - arches = " ".join(arches) - ret = [("Architectures", arches)] - - if cuda_dir := self.manager.get_cmake_variable(self.CUDAToolkit_ROOT): - ret.append(("CUDA Dir", cuda_dir)) - - cc = self.manager.get_cmake_variable(self.CMAKE_CUDA_COMPILER) - assert cc is not None - ret.append(("Executable", cc)) - - version = self.log_execute_command([cc, "--version"]).stdout - ret.append(("Version", version)) - - ccflags = self.manager.get_cmake_variable(self.CMAKE_CUDA_FLAGS) - if not ccflags: - ccflags = "[]" - ret.append(("Flags", ccflags)) - return self.create_package_summary(ret) - - -def create_package(manager: ConfigurationManager) -> CUDA: - return CUDA(manager) diff --git a/src/aedifix/package/packages/gasnet.py b/src/aedifix/package/packages/gasnet.py deleted file mode 100644 index 351c9eb..0000000 --- a/src/aedifix/package/packages/gasnet.py +++ /dev/null @@ -1,104 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath, CMakeString -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class GASNet(Package): - With_GASNET: Final = ConfigArgument( - name="--with-gasnet", - spec=ArgSpec( - dest="with_gasnet", type=bool, help="Build with GASNet support." - ), - enables_package=True, - primary=True, - ) - GASNet_ROOT_DIR: Final = ConfigArgument( - name="--with-gasnet-dir", - spec=ArgSpec( - dest="gasnet_dir", - type=Path, - help="Path to GASNet installation directory.", - ), - cmake_var=CMAKE_VARIABLE("GASNet_ROOT_DIR", CMakePath), - enables_package=True, - ) - GASNet_CONDUIT: Final = ConfigArgument( - name="--gasnet-conduit", - spec=ArgSpec( - dest="gasnet_conduit", - # TODO: To support UDP conduit, we would need to add a special case - # on the legate launcher. See - # https://github.com/nv-legate/legate.core/issues/294. - choices=("ibv", "ucx", "aries", "mpi", "ofi"), - help="Build with specified GASNet conduit.", - ), - cmake_var=CMAKE_VARIABLE("GASNet_CONDUIT", CMakeString), - enables_package=True, - ) - GASNet_SYSTEM: Final = ConfigArgument( - name="--gasnet-system", - spec=ArgSpec( - dest="gasnet_system", - help="Specify a system-specific configuration to use for GASNet", - ), - cmake_var=CMAKE_VARIABLE("GASNet_SYSTEM", CMakeString), - enables_package=True, - ) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a GASNet Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="GASNet") - - def configure(self) -> None: - r"""Configure GASNet.""" - super().configure() - if not self.state.enabled(): - return - - self.set_flag_if_user_set( - self.GASNet_ROOT_DIR, self.cl_args.gasnet_dir - ) - self.set_flag_if_user_set( - self.GASNet_CONDUIT, self.cl_args.gasnet_conduit - ) - self.set_flag_if_user_set( - self.GASNet_SYSTEM, self.cl_args.gasnet_system - ) - - def summarize(self) -> str: - r"""Summarize GASNet. - - Returns - ------- - summary : str - A summary of configured GASNet. - """ - lines = [] - if root_dir := self.manager.get_cmake_variable(self.GASNet_ROOT_DIR): - lines.append(("Root directory", root_dir)) - if conduit := self.manager.get_cmake_variable(self.GASNet_CONDUIT): - lines.append(("Conduit(s)", conduit)) - if system := self.manager.get_cmake_variable(self.GASNet_SYSTEM): - lines.append(("System", system)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> GASNet: - return GASNet(manager) diff --git a/src/aedifix/package/packages/hdf5.py b/src/aedifix/package/packages/hdf5.py deleted file mode 100644 index 1d63431..0000000 --- a/src/aedifix/package/packages/hdf5.py +++ /dev/null @@ -1,85 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -import shutil -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class HDF5(Package): - With_HDF5: Final = ConfigArgument( - name="--with-hdf5", - spec=ArgSpec( - dest="with_hdf5", - type=bool, - help="Build with HDF5 support.", - default=bool(shutil.which("h5dump")), - ), - enables_package=True, - primary=True, - ) - HDF5_ROOT: Final = ConfigArgument( - name="--with-hdf5-dir", - spec=ArgSpec( - dest="hdf5_dir", - type=Path, - help="Path to HDF5 installation directory.", - ), - cmake_var=CMAKE_VARIABLE("HDF5_ROOT", CMakePath), - enables_package=True, - ) - HDF5_DIR: Final = CMAKE_VARIABLE("HDF5_DIR", CMakePath) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a HDF5 Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="HDF5") - - def configure(self) -> None: - r"""Configure HDF5.""" - super().configure() - if not self.state.enabled(): - return - - self.set_flag_if_user_set(self.HDF5_ROOT, self.cl_args.hdf5_dir) - - def summarize(self) -> str: - r"""Summarize HDF5. - - Returns - ------- - summary : str - A summary of configured HDF5. - """ - if not self.state.enabled(): - return "" - - lines = [] - - def get_root_dir() -> str: - root_dir = self.manager.get_cmake_variable(self.HDF5_ROOT) - if not root_dir: - root_dir = self.manager.get_cmake_variable(self.HDF5_DIR) - return root_dir - - if root_dir := get_root_dir(): - lines.append(("Root directory", root_dir)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> HDF5: - return HDF5(manager) diff --git a/src/aedifix/package/packages/legion.py b/src/aedifix/package/packages/legion.py deleted file mode 100644 index 91eb9c7..0000000 --- a/src/aedifix/package/packages/legion.py +++ /dev/null @@ -1,407 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Any, Final, cast - -from ...cmake import ( - CMAKE_VARIABLE, - CMakeBool, - CMakeInt, - CMakeList, - CMakePath, - CMakeString, -) -from ...util.argument_parser import ( - ArgSpec, - ConfigArgument, - ExclusiveArgumentGroup, -) -from ...util.exception import UnsatisfiableConfigurationError -from ...util.utility import dest_to_flag -from ..package import Package -from .cuda import CUDA -from .gasnet import GASNet -from .mpi import MPI -from .openmp import OpenMP -from .python import Python -from .ucx import UCX -from .zlib import ZLIB - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class Legion(Package): - DirGroup: Final = ExclusiveArgumentGroup( - Legion_ROOT=ConfigArgument( - name="--with-legion-dir", - spec=ArgSpec( - dest="legion_dir", - type=Path, - help="Path to an existing Legion build directory.", - ), - cmake_var=CMAKE_VARIABLE("Legion_ROOT", CMakePath), - ), - CPM_Legion_SOURCE=ConfigArgument( - name="--with-legion-src-dir", - spec=ArgSpec( - dest="with_legion_src_dir", - type=Path, - help="Path to an existing Legion source directory.", - ), - cmake_var=CMAKE_VARIABLE("CPM_Legion_SOURCE", CMakePath), - ), - ) - Legion_BRANCH: Final = ConfigArgument( - name="--legion-branch", - spec=ArgSpec( - dest="legion_branch", help="Git branch to download for Legion" - ), - ) - Legion_MAX_DIM: Final = ConfigArgument( - name="--legion-max-dim", - spec=ArgSpec( - dest="legion_max_dim", - type=int, - default=6, - help="Maximum number of dimensions that Legion will support", - ), - cmake_var=CMAKE_VARIABLE("Legion_MAX_DIM", CMakeInt), - ) - Legion_MAX_FIELDS: Final = ConfigArgument( - name="--legion-max-fields", - spec=ArgSpec( - dest="legion_max_fields", - type=int, - default=256, - help="Maximum number of fields that Legion will support", - ), - cmake_var=CMAKE_VARIABLE("Legion_MAX_FIELDS", CMakeInt), - ) - Legion_SPY: Final = ConfigArgument( - name="--legion-spy", - spec=ArgSpec( - dest="legion_spy", - type=bool, - help="Build with detailed Legion Spy enabled.", - ), - cmake_var=CMAKE_VARIABLE("Legion_SPY", CMakeBool), - ) - Legion_BOUNDS_CHECKS: Final = ConfigArgument( - name="--legion-bounds-checks", - spec=ArgSpec( - dest="legion_bounds_checks", - type=bool, - help=( - "Build Legion with bounds checking enabled " - "(warning: expensive)." - ), - ), - cmake_var=CMAKE_VARIABLE("Legion_BOUNDS_CHECKS", CMakeBool), - ) - Legion_BUILD_RUST_PROFILER: Final = ConfigArgument( - name="--legion-rust-profiler", - spec=ArgSpec( - dest="legion_rust_profiler", - type=bool, - help="Build the Legion profiler (requires rust).", - ), - cmake_var=CMAKE_VARIABLE("Legion_BUILD_RUST_PROFILER", CMakeBool), - ) - Legion_CXX_FLAGS: Final = ConfigArgument( - name="--legion-cxx-flags", - spec=ArgSpec( - dest="legion_cxx_flags", nargs=1, help="C++ flags for Legion" - ), - cmake_var=CMAKE_VARIABLE("Legion_CXX_FLAGS", CMakeList), - ) - Legion_CUDA_FLAGS: Final = ConfigArgument( - name="--legion-cuda-flags", - spec=ArgSpec( - dest="legion_cuda_flags", nargs=1, help="CUDA flags for Legion" - ), - cmake_var=CMAKE_VARIABLE("Legion_CUDA_FLAGS", CMakeList), - ) - - Legion_EMBED_GASNet_CONFIGURE_ARGS: Final = CMAKE_VARIABLE( - "Legion_EMBED_GASNet_CONFIGURE_ARGS", CMakeList - ) - Legion_USE_CUDA: Final = CMAKE_VARIABLE("Legion_USE_CUDA", CMakeBool) - Legion_USE_OpenMP: Final = CMAKE_VARIABLE("Legion_USE_OpenMP", CMakeBool) - Legion_USE_Python: Final = CMAKE_VARIABLE("Legion_USE_Python", CMakeBool) - Legion_USE_ZLIB: Final = CMAKE_VARIABLE("Legion_USE_ZLIB", CMakeBool) - Legion_Python_Version: Final = CMAKE_VARIABLE( - "Legion_Python_Version", CMakeString - ) - Legion_NETWORKS: Final = CMAKE_VARIABLE("Legion_NETWORKS", CMakeString) - Legion_BUILD_JUPYTER: Final = CMAKE_VARIABLE( - "Legion_BUILD_JUPYTER", CMakeBool - ) - Legion_BUILD_BINDINGS: Final = CMAKE_VARIABLE( - "Legion_BUILD_BINDINGS", CMakeBool - ) - CPM_DOWNLOAD_Legion: Final = CMAKE_VARIABLE( - "CPM_DOWNLOAD_Legion", CMakeBool - ) - Legion_DIR: Final = CMAKE_VARIABLE("Legion_DIR", CMakePath) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a Legion Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__( - manager=manager, - name="Legion", - always_enabled=True, - dependencies=(CUDA, GASNet, OpenMP, Python, MPI, UCX, ZLIB), - ) - - def check_conflicting_options(self) -> None: - r"""Check for conflicting options that are too complicated to " - "describe statically. - - Raises - ------ - UnsatisfiableConfigurationError - If both --with-legion-src-dir and --legion-branch are set - """ - with_legion_src_dir = self.cl_args.with_legion_src_dir - legion_branch = self.cl_args.legion_branch - if with_legion_src_dir.value and legion_branch.value: - msg = ( - "Cannot specify both " - f"{dest_to_flag(with_legion_src_dir.name)} and " - f"{dest_to_flag(legion_branch.name)}, their combined meaning " - "is ambiguous. If the source dir is given, the contents of " - "the directory are used as-is (i.e. using whatever branch or " - "commit that dir is currently on), so the chosen Legion " - "branch would have no effect." - ) - raise UnsatisfiableConfigurationError(msg) - - def configure_root_dirs(self) -> None: - r"""Configure the various "root" directories that Legion requires.""" - dir_group = self.DirGroup - if (lg_dir := self.cl_args.legion_dir).cl_set: - self.manager.set_cmake_variable( - dir_group.Legion_ROOT, # type: ignore[attr-defined] - lg_dir.value, - ) - elif (lg_src_dir := self.cl_args.with_legion_src_dir).cl_set: - self.manager.set_cmake_variable( - dir_group.CPM_Legion_SOURCE, # type: ignore[attr-defined] - lg_src_dir.value, - ) - - def configure_variables(self) -> None: - r"""Configure the variable default variables.""" - self.set_flag_if_user_set( - self.Legion_MAX_DIM, self.cl_args.legion_max_dim - ) - self.set_flag_if_user_set( - self.Legion_MAX_FIELDS, self.cl_args.legion_max_fields - ) - self.set_flag_if_user_set(self.Legion_SPY, self.cl_args.legion_spy) - self.set_flag_if_user_set( - self.Legion_BOUNDS_CHECKS, self.cl_args.legion_bounds_checks - ) - self.set_flag_if_user_set( - self.Legion_BUILD_RUST_PROFILER, self.cl_args.legion_rust_profiler - ) - - self.append_flags_if_set( - self.Legion_CXX_FLAGS, self.cl_args.legion_cxx_flags - ) - - def configure_cuda(self) -> None: - r"""If CUDA is enabled, set the various CUDA flags for Legion. - Does nothing otherwise. - - Raises - ------ - RuntimeError - If CUDA flags are requested but CUDA is not enabled. - """ - cuda_state = self.deps.CUDA.state - if cuda_state.enabled(): - self.manager.set_cmake_variable(self.Legion_USE_CUDA, True) - self.append_flags_if_set( - self.Legion_CUDA_FLAGS, self.cl_args.legion_cuda_flags - ) - elif self.cl_args.legion_cuda_flags.cl_set: - msg = ( - "--legion-cuda-flags set " - f"({self.cl_args.legion_cuda_flags.value}), " - "but CUDA is not enabled." - ) - raise RuntimeError(msg) - elif cuda_state.explicitly_disabled(): - self.manager.set_cmake_variable(self.Legion_USE_CUDA, False) - - def configure_gasnet(self) -> None: - r"""Configure Legion to use GASNet. Does nothing if GASNet is not - enabled. - """ - if self.deps.GASNet.state.enabled(): - self.manager.append_cmake_variable( - self.Legion_EMBED_GASNet_CONFIGURE_ARGS, - ["--with-ibv-max-hcas=8"], - ) - - def configure_openmp(self) -> None: - r"""Configure Legion to use OpenMP. Does nothing if OpenMP is not - enabled. - """ - omp_state = self.deps.OpenMP.state - if omp_state.enabled(): - self.manager.set_cmake_variable(self.Legion_USE_OpenMP, True) - elif omp_state.explicitly_disabled(): - self.manager.set_cmake_variable(self.Legion_USE_OpenMP, False) - - def configure_python(self) -> None: - r"""Configure Legion to use Python. Does nothing if Python is not - enabled. - """ - python = cast(Python, self.deps.Python) - py_state = python.state - if py_state.enabled(): - self.manager.set_cmake_variable(self.Legion_BUILD_BINDINGS, True) - self.manager.set_cmake_variable(self.Legion_USE_Python, True) - self.manager.set_cmake_variable(self.Legion_BUILD_JUPYTER, True) - self.manager.set_cmake_variable( - self.Legion_Python_Version, python.lib_version - ) - elif py_state.explicitly_disabled(): - self.manager.set_cmake_variable(self.Legion_BUILD_BINDINGS, False) - self.manager.set_cmake_variable(self.Legion_BUILD_JUPYTER, False) - self.manager.set_cmake_variable(self.Legion_USE_Python, False) - - def configure_zlib(self) -> None: - r"""Configure Legion to use ZLIB. Disables ZLIB if is not enabled.""" - zlib_state = self.deps.ZLIB.state - if zlib_state.enabled(): - self.manager.set_cmake_variable(self.Legion_USE_ZLIB, True) - elif zlib_state.explicitly_disabled(): - self.manager.set_cmake_variable(self.Legion_USE_ZLIB, False) - - def configure_networks(self) -> None: - r"""Configure all of the collected networks, and enable them.""" - networks = [] - explicit_disable = False - network_map = {"GASNet": "gasnetex", "UCX": "ucx", "MPI": "mpi"} - for py_attr, net_name in network_map.items(): - state = getattr(self.deps, py_attr).state - if state.enabled(): - networks.append(net_name) - elif state.explicit: - # explicitly disabled - explicit_disable = True - - if len(networks) > 1: - self.log_warning( - "Building Realm with multiple networking backends " - f"({', '.join(networks)}) is not fully supported currently." - ) - if networks: - self.manager.set_cmake_variable( - self.Legion_NETWORKS, ";".join(networks) - ) - elif explicit_disable: - # ensure that it is properly cleared - self.manager.set_cmake_variable(self.Legion_NETWORKS, "") - - def configure(self) -> None: - r"""Configure Legion.""" - super().configure() - self.log_execute_func(self.check_conflicting_options) - self.log_execute_func(self.configure_root_dirs) - self.log_execute_func(self.configure_variables) - self.log_execute_func(self.configure_cuda) - self.log_execute_func(self.configure_gasnet) - self.log_execute_func(self.configure_openmp) - self.log_execute_func(self.configure_python) - self.log_execute_func(self.configure_zlib) - self.log_execute_func(self.configure_networks) - - def summarize(self) -> str: - r"""Summarize Legion. - - Returns - ------- - summary : str - A summary of configured Legion. - """ - m = self.manager - - def get_location() -> Path | None: - dir_group = self.DirGroup - root_dir = m.get_cmake_variable( - dir_group.Legion_ROOT # type: ignore[attr-defined] - ) - if root_dir: - return Path(root_dir) - - root_dir = m.get_cmake_variable(self.Legion_DIR) - if root_dir: - return Path(root_dir) - - root_dir = m.get_cmake_variable( - dir_group.CPM_Legion_SOURCE # type: ignore[attr-defined] - ) - if root_dir: - root_path = Path(root_dir) - # If the source directory is relative to the cmake - # directory, then we downloaded Legion, but set - # CPM_Legion_Source ourselves. - if not root_path.is_relative_to(m.project_cmake_dir): - return root_path - return None - - lines: list[tuple[str, Any]] = [] - root_dir = get_location() - downloaded = root_dir is None - lines.append(("Downloaded", downloaded)) - if not downloaded: - assert root_dir is not None # pacify mypy - lines.append((" Root dir", root_dir)) - - if cxx_flags := m.get_cmake_variable(self.Legion_CXX_FLAGS): - lines.append(("C++ flags", cxx_flags)) - - lines.append(("With CUDA", m.get_cmake_variable(self.Legion_USE_CUDA))) - if cuda_flags := m.get_cmake_variable(self.Legion_CUDA_FLAGS): - lines.append(("CUDA flags", cuda_flags)) - - if networks := m.get_cmake_variable(self.Legion_NETWORKS): - pass - else: - networks = "None" - lines.append(("Networks", networks)) - lines.append( - ("Bounds checks", m.get_cmake_variable(self.Legion_BOUNDS_CHECKS)) - ) - lines.append(("Max dim", m.get_cmake_variable(self.Legion_MAX_DIM))) - lines.append( - ("Max fields", m.get_cmake_variable(self.Legion_MAX_FIELDS)) - ) - lines.append(("Build Spy", m.get_cmake_variable(self.Legion_SPY))) - lines.append( - ( - "Build Rust profiler", - m.get_cmake_variable(self.Legion_BUILD_RUST_PROFILER), - ) - ) - # TODO continue - - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> Legion: - return Legion(manager) diff --git a/src/aedifix/package/packages/mpi.py b/src/aedifix/package/packages/mpi.py deleted file mode 100644 index 9dd3bde..0000000 --- a/src/aedifix/package/packages/mpi.py +++ /dev/null @@ -1,119 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -import shutil -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakeExecutable, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -def _gen_mpiexec_guesses() -> str | None: - for guess in ("mpiexec", "mpirun"): - if found := shutil.which(guess): - return found - return None - - -class MPI(Package): - With_MPI: Final = ConfigArgument( - name="--with-mpi", - spec=ArgSpec( - dest="with_mpi", type=bool, help="Build with MPI support." - ), - enables_package=True, - primary=True, - ) - MPI_HOME: Final = ConfigArgument( - name="--with-mpi-dir", - spec=ArgSpec( - dest="mpi_dir", - type=Path, - help="Path to MPI installation directory.", - ), - cmake_var=CMAKE_VARIABLE("MPI_HOME", CMakePath), - enables_package=True, - ) - MPIEXEC_EXECUTABLE: Final = ConfigArgument( - name="--with-mpiexec-executable", - spec=ArgSpec( - dest="mpiexec", - default=_gen_mpiexec_guesses(), - type=Path, - help="Path to mpiexec executable.", - ), - cmake_var=CMAKE_VARIABLE("MPIEXEC_EXECUTABLE", CMakeExecutable), - enables_package=True, - ) - MPI_CXX_COMPILER: Final = CMAKE_VARIABLE( - "MPI_CXX_COMPILER", CMakeExecutable - ) - MPI_CXX_COMPILER_INCLUDE_DIRS: Final = CMAKE_VARIABLE( - "MPI_CXX_COMPILER_INCLUDE_DIRS", CMakePath - ) - MPI_C_COMPILER: Final = CMAKE_VARIABLE("MPI_C_COMPILER", CMakeExecutable) - MPI_C_COMPILER_INCLUDE_DIRS: Final = CMAKE_VARIABLE( - "MPI_C_COMPILER_INCLUDE_DIRS", CMakePath - ) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a MPI Package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="MPI") - - def configure(self) -> None: - r"""Configure MPI.""" - super().configure() - if not self.state.enabled(): - return - - self.set_flag_if_user_set(self.MPI_HOME, self.cl_args.mpi_dir) - self.set_flag_if_user_set( - self.MPIEXEC_EXECUTABLE, self.cl_args.mpiexec - ) - - def summarize(self) -> str: - r"""Summarize MPI. - - Returns - ------- - summary : str - A summary of configured MPI. - """ - if not self.state.enabled(): - return "" - - lines = [] - if mpi_dir := self.manager.get_cmake_variable(self.MPI_HOME): - lines.append(("Root dir", mpi_dir)) - if mpicc := self.manager.get_cmake_variable(self.MPI_C_COMPILER): - lines.append(("mpicc", mpicc)) - if mpicc_inc := self.manager.get_cmake_variable( - self.MPI_C_COMPILER_INCLUDE_DIRS - ): - lines.append(("C Include Dirs", mpicc_inc)) - if mpicxx := self.manager.get_cmake_variable(self.MPI_CXX_COMPILER): - lines.append(("mpicxx", mpicxx)) - if mpicxx_inc := self.manager.get_cmake_variable( - self.MPI_CXX_COMPILER_INCLUDE_DIRS - ): - lines.append(("C++ Include Dirs", mpicxx_inc)) - if mpiexec := self.manager.get_cmake_variable(self.MPIEXEC_EXECUTABLE): - lines.append(("mpiexec", mpiexec)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> MPI: - return MPI(manager) diff --git a/src/aedifix/package/packages/nccl.py b/src/aedifix/package/packages/nccl.py deleted file mode 100644 index 0553230..0000000 --- a/src/aedifix/package/packages/nccl.py +++ /dev/null @@ -1,70 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package -from .cuda import CUDA - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class NCCL(Package): - With_NCCL: Final = ConfigArgument( - name="--with-nccl", - spec=ArgSpec( - dest="with_nccl", type=bool, help="Build with NCCL support." - ), - enables_package=True, - primary=True, - ) - NCCL_DIR: Final = ConfigArgument( - name="--with-nccl-dir", - spec=ArgSpec( - dest="nccl_dir", - type=Path, - help="Path to NCCL installation directory.", - ), - cmake_var=CMAKE_VARIABLE("NCCL_DIR", CMakePath), - enables_package=True, - ) - - def __init__(self, manager: ConfigurationManager) -> None: - super().__init__(manager=manager, name="NCCL", dependencies=(CUDA,)) - - def configure(self) -> None: - r"""Configure NCCL.""" - super().configure() - # TODO(jfaibussowit) - # Make this kind of relationship statically declarable from the CTOR, - # by updating the dependencies argument to include a "this dependency - # also enables the current package" - if not self.state.explicit and self.deps.CUDA.state.enabled(): - self._state = Package.EnableState(value=True) - if not self.state.enabled(): - return - - self.set_flag_if_user_set(self.NCCL_DIR, self.cl_args.nccl_dir) - - def summarize(self) -> str: - r"""Summarize NCCL. - - Returns - ------- - summary : str - A summary of configured NCCL. - """ - lines = [] - if nccl_dir := self.manager.get_cmake_variable(self.NCCL_DIR): - lines.append(("Root dir", nccl_dir)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> NCCL: - return NCCL(manager) diff --git a/src/aedifix/package/packages/openmp.py b/src/aedifix/package/packages/openmp.py deleted file mode 100644 index 1f16f66..0000000 --- a/src/aedifix/package/packages/openmp.py +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakeString -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class OpenMP(Package): - With_OpenMP: Final = ConfigArgument( - name="--with-openmp", - spec=ArgSpec( - dest="with_openmp", type=bool, help="Build with OpenMP support." - ), - enables_package=True, - primary=True, - ) - OpenMP_VERSION = CMAKE_VARIABLE("OpenMP_VERSION", CMakeString) - OpenMP_CXX_FLAGS = CMAKE_VARIABLE("OpenMP_CXX_FLAGS", CMakeString) - - def __init__(self, manager: ConfigurationManager) -> None: - super().__init__(manager=manager, name="OpenMP") - - def summarize(self) -> str: - r"""Summarize configured OpenMP. - - Returns - ------- - summary : str - The summary of OpenMP - """ - if not self.state.enabled(): - return "" - - lines = [] - if version := self.manager.get_cmake_variable(self.OpenMP_VERSION): - lines.append(("Version", version)) - if flags := self.manager.get_cmake_variable(self.OpenMP_CXX_FLAGS): - lines.append(("Flags", flags)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> OpenMP: - return OpenMP(manager) diff --git a/src/aedifix/package/packages/python.py b/src/aedifix/package/packages/python.py index 37afb27..b3692be 100644 --- a/src/aedifix/package/packages/python.py +++ b/src/aedifix/package/packages/python.py @@ -16,6 +16,8 @@ class Python(Package): + name = "Python" + With_Python: Final = ConfigArgument( name="--with-python", spec=ArgSpec( @@ -26,7 +28,7 @@ class Python(Package): ) def __init__(self, manager: ConfigurationManager) -> None: - super().__init__(manager=manager, name="Python") + super().__init__(manager=manager) def configure_lib_version_and_paths(self) -> None: r"""Determine the Python library version and its location.""" diff --git a/src/aedifix/package/packages/ucx.py b/src/aedifix/package/packages/ucx.py deleted file mode 100644 index 307317e..0000000 --- a/src/aedifix/package/packages/ucx.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class UCX(Package): - With_UCX: Final = ConfigArgument( - name="--with-ucx", - spec=ArgSpec( - dest="with_ucx", type=bool, help="Build with UCX support." - ), - enables_package=True, - primary=True, - ) - UCX_ROOT: Final = ConfigArgument( - name="--with-ucx-dir", - spec=ArgSpec( - dest="ucx_dir", - type=Path, - help="Path to UCX installation directory.", - ), - cmake_var=CMAKE_VARIABLE("UCX_ROOT", CMakePath), - enables_package=True, - ) - - def __init__(self, manager: ConfigurationManager) -> None: - super().__init__(manager=manager, name="UCX") - - def configure(self) -> None: - r"""Configure UCX.""" - super().configure() - if self.state.enabled(): - return - - self.set_flag_if_user_set(self.UCX_ROOT, self.cl_args.ucx_dir) - - def summarize(self) -> str: - r"""Summarize UCX. - - Returns - ------- - summary : str - The summary of UCX. - """ - lines = [] - if self.state.enabled() and ( - root_dir := self.manager.get_cmake_variable(self.UCX_ROOT) - ): - lines.append(("Root dir", root_dir)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> UCX: - return UCX(manager) diff --git a/src/aedifix/package/packages/zlib.py b/src/aedifix/package/packages/zlib.py deleted file mode 100644 index 1d74c2c..0000000 --- a/src/aedifix/package/packages/zlib.py +++ /dev/null @@ -1,86 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -# ruff: noqa: A005 -from pathlib import Path -from typing import TYPE_CHECKING, Final - -from ...cmake import CMAKE_VARIABLE, CMakePath, CMakeString -from ...util.argument_parser import ArgSpec, ConfigArgument -from ..package import Package - -if TYPE_CHECKING: - from ...manager import ConfigurationManager - - -class ZLIB(Package): - With_ZLIB: Final = ConfigArgument( - name="--with-zlib", - spec=ArgSpec( - dest="with_zlib", type=bool, help="Build with Zlib support." - ), - enables_package=True, - primary=True, - ) - ZLIB_ROOT: Final = ConfigArgument( - name="--with-zlib-dir", - spec=ArgSpec( - dest="zlib_dir", - type=Path, - help="Path to ZLIB installation directory.", - ), - cmake_var=CMAKE_VARIABLE("ZLIB_ROOT", CMakePath), - enables_package=True, - ) - ZLIB_VERSION = CMAKE_VARIABLE("ZLIB_VERSION", CMakeString) - ZLIB_INCLUDE_DIRS = CMAKE_VARIABLE("ZLIB_INCLUDE_DIRS", CMakePath) - ZLIB_INCLUDE_DIR = CMAKE_VARIABLE("ZLIB_INCLUDE_DIR", CMakePath) - ZLIB_LIBRARIES = CMAKE_VARIABLE("ZLIB_LIBRARIES", CMakeString) - - def __init__(self, manager: ConfigurationManager) -> None: - r"""Construct a ZLIB package. - - Parameters - ---------- - manager : ConfigurationManager - The configuration manager to manage this package. - """ - super().__init__(manager=manager, name="ZLIB") - - def configure(self) -> None: - r"""Configure ZLIB.""" - super().configure() - if not self.state.enabled(): - return - - self.set_flag_if_user_set(self.ZLIB_ROOT, self.cl_args.zlib_dir) - - def summarize(self) -> str: - r"""Summarize configured ZLIB. - - Returns - ------- - summary : str - The summary of ZLIB - """ - if not self.state.enabled(): - return "" - - lines = [] - # Some versions of FindZLIB don't actually set these variables in the - # cache, so we may or may not find them - if version := self.manager.get_cmake_variable(self.ZLIB_VERSION): - lines.append(("Version", version)) - if inc_dirs := self.manager.get_cmake_variable(self.ZLIB_INCLUDE_DIRS): - lines.append(("Include Dirs", inc_dirs)) - elif inc_dir := self.manager.get_cmake_variable(self.ZLIB_INCLUDE_DIR): - lines.append(("Include Dir", inc_dir)) - if libs := self.manager.get_cmake_variable(self.ZLIB_LIBRARIES): - lines.append(("Libraries", libs)) - return self.create_package_summary(lines) - - -def create_package(manager: ConfigurationManager) -> ZLIB: - return ZLIB(manager) diff --git a/tests/fixtures/dummy_main_module.py b/tests/fixtures/dummy_main_module.py index 97af03e..186a742 100644 --- a/tests/fixtures/dummy_main_module.py +++ b/tests/fixtures/dummy_main_module.py @@ -20,13 +20,14 @@ class DummyMainModule(DummyMainPackage): + name = "DummyMainModule" + def __init__( self, manager: ConfigurationManager, argv: Sequence[str] ) -> None: super().__init__( manager=manager, argv=argv, - name="DummyMainModule", arch_name="AEDIFIX_PYTEST_ARCH", project_dir_name="AEDIFIX_PYTEST_DIR", project_dir_value=Path(environ["AEDIFIX_PYTEST_DIR"]), diff --git a/tests/package/packages/__init__.py b/tests/package/packages/__init__.py deleted file mode 100644 index 182ad12..0000000 --- a/tests/package/packages/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 diff --git a/tests/package/packages/test_cuda.py b/tests/package/packages/test_cuda.py deleted file mode 100644 index 98d864a..0000000 --- a/tests/package/packages/test_cuda.py +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. -# All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -from __future__ import annotations - -import sys - -import pytest - -from aedifix.package.packages.cuda import CudaArchAction - -ARCH_STR: tuple[tuple[str, list[str]], ...] = ( - ("", []), - (",,", []), - ("70", ["70"]), - ("70,80", ["70", "80"]), - ("ampere", ["80"]), - ("turing,hopper", ["75", "90"]), - ("volta,60,all-major", ["70", "60", "all-major"]), - ("60,,80", ["60", "80"]), -) - - -class TestCudaArchAction: - @pytest.mark.parametrize(("argv", "expected"), ARCH_STR) - def test_map_cuda_arch_names(self, argv: str, expected: list[str]) -> None: - ret = CudaArchAction.map_cuda_arch_names(argv) - assert ret == expected - - -if __name__ == "__main__": - sys.exit(pytest.main()) diff --git a/tests/test_manager.py b/tests/test_manager.py index e476320..ba38762 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -85,7 +85,7 @@ def test_setup( orig_argv = deepcopy(manager.argv) assert len(manager._modules) == 1 manager.setup() - assert len(manager._modules) > 1 + assert len(manager._modules) == 1 assert manager.argv == orig_argv assert ( CLArg(