Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance CMakeMake easyblock to check whether correct Python installation was picked up by CMake #3399

Merged
merged 7 commits into from
Oct 16, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions easybuild/easyblocks/generic/cmakemake.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +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_shell_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'
Expand Down Expand Up @@ -331,9 +332,61 @@ def configure_step(self, srcdir=None, builddir=None):
self.cfg['configopts']])

res = run_shell_cmd(command)

self.check_python_paths()
return res.output

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)[^=]*=(.*)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The [^=]* part matches to much. From my test builds, I have things like

PYTHON_EXECUTABLE-ADVANCED:INTERNAL=1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe sufficient to just add a : ?

        python_regex = re.compile(r"_?(?:Python|PYTHON)\d?_(EXECUTABLE|INCLUDE_DIR|LIBRARY):[^=]*=(.*)")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not enough to match variables with a potential suffixes like "_DIR" or "_DEBUG", like PYTHON_LIBRARY_DEBUG. However limiting to word characters should work. See the where I also added some examples in the commit message

for line in cmake_cache.splitlines():
match = python_regex.match(line)
if match:
self.log.debug("Python related CMake cache line found: " + line)
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 path 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
Expand Down
Loading