diff --git a/easybuild/easyblocks/generic/cmakemake.py b/easybuild/easyblocks/generic/cmakemake.py index 3074193df0b..5b58594d6e8 100644 --- a/easybuild/easyblocks/generic/cmakemake.py +++ b/easybuild/easyblocks/generic/cmakemake.py @@ -1,5 +1,5 @@ ## -# Copyright 2009-2023 Ghent University +# Copyright 2009-2024 Ghent University # # This file is part of EasyBuild, # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), @@ -42,13 +42,13 @@ from easybuild.framework.easyconfig import BUILD, CUSTOM from easybuild.tools.build_log import EasyBuildError, print_warning from easybuild.tools.config import build_option -from easybuild.tools.filetools import change_dir, create_unused_dir, mkdir, which +from easybuild.tools.filetools import change_dir, create_unused_dir, mkdir, read_file, which from easybuild.tools.environment import setvar from easybuild.tools.modules import get_software_root, get_software_version from easybuild.tools.run import run_cmd from easybuild.tools.systemtools import get_shared_lib_ext from easybuild.tools.utilities import nub - +import easybuild.tools.toolchain as toolchain DEFAULT_CONFIGURE_CMD = 'cmake' @@ -317,9 +317,61 @@ def configure_step(self, srcdir=None, builddir=None): self.cfg['configopts']]) (out, _) = run_cmd(command, log_all=True, simple=False) + self.check_python_paths() return out + def check_python_paths(self): + """Check that there are no detected Python paths outside the Python dependency provided by EasyBuild""" + if not os.path.exists('CMakeCache.txt'): + self.log.warning("CMakeCache.txt not found. Python paths checks skipped.") + return + cmake_cache = read_file('CMakeCache.txt') + if not cmake_cache: + self.log.warning("CMake Cache could not be read. Python paths checks skipped.") + return + + self.log.info("Checking Python paths") + + python_paths = { + "executable": [], + "include_dir": [], + "library": [], + } + python_regex = re.compile(r"_?(?:Python|PYTHON)\d?_(EXECUTABLE|INCLUDE_DIR|LIBRARY)[^=]*=(.*)") + for line in cmake_cache.splitlines(): + match = python_regex.match(line) + if match: + path_type = match[1].lower() + path = match[2].strip() + self.log.info("Python %s path: %s", path_type, path) + python_paths[path_type].append(path) + + ebrootpython_path = get_software_root("Python") + if not ebrootpython_path: + if any(python_paths.values()) and not self.toolchain.comp_family() == toolchain.SYSTEM: + self.log.warning("Found Python paths in CMake cache but Python is not a dependency") + # Can't do the check + return + ebrootpython_path = os.path.realpath(ebrootpython_path) + + errors = [] + for path_type, paths in python_paths.items(): + for path in paths: + if path.endswith('-NOTFOUND'): + continue + if not os.path.exists(path): + errors.append("Python %s does not exist: %s" % (path_type, path)) + elif not os.path.realpath(path).startswith(ebrootpython_path): + errors.append("Python %s path '%s' is outside EBROOTPYTHON (%s)" % + (path_type, path, ebrootpython_path)) + + if errors: + # Combine all errors into a single message + error_message = "\n".join(errors) + raise EasyBuildError("Python path errors:\n" + error_message) + self.log.info("Python check successful") + def test_step(self): """CMake specific test setup""" # When using ctest for tests (default) then show verbose output if a test fails