diff --git a/repos/spack_repo/builtin/build_systems/cmake.py b/repos/spack_repo/builtin/build_systems/cmake.py index f41091ba5ac..e8972e1f451 100644 --- a/repos/spack_repo/builtin/build_systems/cmake.py +++ b/repos/spack_repo/builtin/build_systems/cmake.py @@ -42,24 +42,6 @@ def _extract_primary_generator(generator): return _primary_generator_extractor.match(generator).group(1) -def _maybe_set_python_hints(pkg: PackageBase, args: List[str]) -> None: - """Set the PYTHON_EXECUTABLE, Python_EXECUTABLE, and Python3_EXECUTABLE CMake variables - if the package has Python as build or link dep and ``find_python_hints`` is set to True. See - ``find_python_hints`` for context.""" - if not getattr(pkg, "find_python_hints", False) or not pkg.spec.dependencies( - "python", deptype=("build", "link") - ): - return - python_executable = pkg.spec["python"].command.path - args.extend( - [ - define("PYTHON_EXECUTABLE", python_executable), - define("Python_EXECUTABLE", python_executable), - define("Python3_EXECUTABLE", python_executable), - ] - ) - - def _supports_compilation_databases(pkg: PackageBase) -> bool: """Check if this package (and CMake) can support compilation databases.""" @@ -172,6 +154,9 @@ class CMakePackage(PackageBase): https://cmake.org/cmake/help/latest/ """ + #: List of package names for which CMake argument injection should be disabled + disable_cmake_hints_from: List[str] = [] + #: This attribute is used in UI queries that need to know the build #: system base class build_system_class = "CMakePackage" @@ -179,13 +164,6 @@ class CMakePackage(PackageBase): #: Legacy buildsystem attribute used to deserialize and install old specs default_buildsystem = "cmake" - #: When this package depends on Python and ``find_python_hints`` is set to True, pass the - #: defines {Python3,Python,PYTHON}_EXECUTABLE explicitly, so that CMake locates the right - #: Python in its builtin FindPython3, FindPython, and FindPythonInterp modules. Spack does - #: CMake's job because CMake's modules by default only search for Python versions known at the - #: time of release. - find_python_hints = True - build_system("cmake") with when("build_system=cmake"): @@ -405,7 +383,25 @@ def std_args(pkg: PackageBase, generator: Optional[str] = None) -> List[str]: ) _conditional_cmake_defaults(pkg, args) - _maybe_set_python_hints(pkg, args) + + # Append extra hint/option arguments from dependencies + # TODO: Consider properties from virtual packages like Mpi + disable_cmake_hints_from = getattr(pkg, "disable_cmake_hints_from", []) + for dep in pkg.spec.edges_to_dependencies(): + # Skip packages without the callback + dep_pkg = dep.spec.package + if not hasattr(dep_pkg, "dependent_cmake_args"): + continue + + # Skip disabled dependency cmake args + if dep_pkg.name in disable_cmake_hints_from: + continue + + # Skip disabled virtual dependency cmake args + if any(v in disable_cmake_hints_from for v in dep.virtuals): + continue + + args.extend(dep_pkg.dependent_cmake_args(pkg.spec)) return args diff --git a/repos/spack_repo/builtin/packages/opencv/package.py b/repos/spack_repo/builtin/packages/opencv/package.py index ded7baeab0f..382e294f2e1 100644 --- a/repos/spack_repo/builtin/packages/opencv/package.py +++ b/repos/spack_repo/builtin/packages/opencv/package.py @@ -17,7 +17,7 @@ class Opencv(CMakePackage, CudaPackage): homepage = "https://opencv.org/" url = "https://github.com/opencv/opencv/archive/4.5.0.tar.gz" git = "https://github.com/opencv/opencv.git" - find_python_hints = False # opencv uses custom OpenCVDetectPython.cmake + disable_cmake_hints_from = ["python"] # opencv uses custom OpenCVDetectPython.cmake maintainers("bvanessen", "adamjstewart") diff --git a/repos/spack_repo/builtin/packages/python/package.py b/repos/spack_repo/builtin/packages/python/package.py index 3b202d21d57..6d28e2e2288 100644 --- a/repos/spack_repo/builtin/packages/python/package.py +++ b/repos/spack_repo/builtin/packages/python/package.py @@ -1324,6 +1324,16 @@ def setup_dependent_package(self, module, dependent_spec): module.python_platlib = join_path(dependent_spec.prefix, self.platlib) module.python_purelib = join_path(dependent_spec.prefix, self.purelib) + def dependent_cmake_args(self, dependent_spec: Spec) -> List[str]: + # pkg.spec["python"] can re-direct to python-venv if pkg extends python + # ref. https://github.com/spack/spack/pull/40773 + python_executable = dependent_spec["python"].command.path + return [ + f"-DPYTHON_EXECUTABLE:PATH={python_executable}", + f"-DPython_EXECUTABLE:PATH={python_executable}", + f"-DPython3_EXECUTABLE:PATH={python_executable}", + ] + def add_files_to_view(self, view, merge_map, skip_if_exists=True): """Make the view a virtual environment if it isn't one already. diff --git a/tests/build_systems.py b/tests/build_systems.py index 795be957b87..2a88516462e 100644 --- a/tests/build_systems.py +++ b/tests/build_systems.py @@ -257,6 +257,12 @@ def test_cmake_std_args(self, default_mock_concretization): s = default_mock_concretization("mpich") assert cmake.CMakeBuilder.std_args(s.package) + def test_cmake_dependent_args(self, default_mock_concretization): + # Call the function on a CMakePackage instance + s = default_mock_concretization("cmake-client +cmake_hints") + args = cmake.CMakeBuilder.std_args(s.package) + assert '-DCMAKE_HINTS_ARG:STRING="Foo"' in args + def test_cmake_bad_generator(self, default_mock_concretization): s = default_mock_concretization("cmake-client") with pytest.raises(InstallError): diff --git a/tests/repos/spack_repo/builtin_mock/packages/cmake_client/package.py b/tests/repos/spack_repo/builtin_mock/packages/cmake_client/package.py index dddf55dea42..fd028deae04 100644 --- a/tests/repos/spack_repo/builtin_mock/packages/cmake_client/package.py +++ b/tests/repos/spack_repo/builtin_mock/packages/cmake_client/package.py @@ -30,8 +30,10 @@ class CmakeClient(CMakePackage): ) variant("single", description="", default="blue", values=("blue", "red", "green"), multi=False) variant("truthy", description="", default=True) + variant("cmake_hints", description="", default=False) depends_on("c", type="build") + depends_on("cmake-hints", when="+cmake_hints") callback_counter = 0 diff --git a/tests/repos/spack_repo/builtin_mock/packages/cmake_hints/package.py b/tests/repos/spack_repo/builtin_mock/packages/cmake_hints/package.py new file mode 100644 index 00000000000..1a5c67028a1 --- /dev/null +++ b/tests/repos/spack_repo/builtin_mock/packages/cmake_hints/package.py @@ -0,0 +1,24 @@ +# Copyright Spack Project Developers. See COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +from typing import List + +from spack.package import Package, PackageBase, version + + +def check(condition, msg): + """Raise an install error if condition is False.""" + if not condition: + raise InstallError(msg) + + +class CmakeHints(Package): + """A dummy package that uses cmake.""" + + homepage = "https://www.example.com" + url = "https://www.example.com/cmake-hints-1.0.tar.gz" + version("1.0", md5="4cb3ff35b2472aae70f542116d616e63") + + def dependent_cmake_args(self, pkg: PackageBase) -> List[str]: + return ['-DCMAKE_HINTS_ARG:STRING="Foo"']