cmake: use python from venv if available #31411

pull willcl-ark wants to merge 1 commits into bitcoin:master from willcl-ark:use-python-venv changing 1 files +25 −7
  1. willcl-ark commented at 1:46 pm on December 3, 2024: member

    When running targets that depend on a python, such as:

    0cmake --build . --target test-security-check
    1cmake --build . --target check-symbols
    2cmake --build . --target check-security
    

    … it can be tricky to configure cmake to use a python venv. This change checks for the $VIRTUAL_ENV env var and uses python from there using the following logic:

    • First check if $VIRTUAL_ENV is set. If it is, use the python binary from this venv.
    • Fall back to system python otherwise.
  2. build: use python from venv if available
    First check if $VIRTUAL_ENV is set. If it is, use the python binary from
    this venv.
    
    Fall back to system python otherwise.
    
    This helps run various targets which use python, when system python is
    not being used.
    0ad4461589
  3. DrahtBot commented at 1:46 pm on December 3, 2024: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31411.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #31233 (cmake: Improve robustness and usability by hebasto)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  4. DrahtBot added the label Build system on Dec 3, 2024
  5. willcl-ark commented at 1:46 pm on December 3, 2024: member

    cmake >= 3.17 does support a Python_FIND_VIRTUALENV variable, but this doesn’t seem to support all venv providers (I use uv).

    As far as I know, all venv providers set VIRTUAL_ENV, so I think this solution should be more universal.

  6. hebasto commented at 1:51 pm on December 3, 2024: member

    cmake >= 3.17 does support a Python_FIND_VIRTUALENV variable, but this doesn’t seem to support all venv providers (I use uv).

    A quick note. This PR seems incompatible with #31233.

  7. willcl-ark commented at 1:53 pm on December 3, 2024: member

    Thanks hebasto, I had not seen this PR. Will compare/review.

    It has come to my attention that having these checks complete in a dev environment is not that useful anyway, so perhaps “making things easier for me to run locally” is not a great motivation for this change in any case…

  8. hebasto commented at 3:35 pm on December 3, 2024: member

    I use uv

    This one?

  9. willcl-ark commented at 3:37 pm on December 3, 2024: member
    Yes, and I highly recommend it!
  10. hebasto commented at 9:36 pm on December 3, 2024: member

    … it can be tricky to configure cmake to use a python venv.

    I’ve read https://github.com/astral-sh/uv/blob/main/README.md#python-management and used the following script for simplicity:

    0cmake_minimum_required(VERSION 3.22)
    1project(test_py LANGUAGES NONE)
    2find_package(Python3 COMPONENTS Interpreter)
    3message("Python3_EXECUTABLE=${Python3_EXECUTABLE}")
    

    I have no problems with finding uv’s Python on my Ubuntu 24.04:

     0$ python3 --version  # system's Python
     1Python 3.12.3
     2$ uv python install 3.10
     3Installed Python 3.10.15 in 9.33s
     4 + cpython-3.10.15-linux-x86_64-gnu
     5$ uv venv --python 3.10
     6Using CPython 3.10.15
     7Creating virtual environment at: .venv
     8Activate with: source .venv/bin/activate
     9$ source .venv/bin/activate
    10$ cmake -B build --fresh
    11-- Found Python3: /home/hebasto/.venv/bin/python3 (found version "3.10.15") found components: Interpreter 
    12Python3_EXECUTABLE=/home/hebasto/.venv/bin/python3
    13-- Configuring done (0.2s)
    14-- Generating done (0.0s)
    15-- Build files have been written to: /home/hebasto/TEST_CMAKE_PYTHON/build
    

    What did I miss?

  11. maflcko commented at 7:36 am on December 4, 2024: member
    I had the same thought. Shouldn’t a venv “just work” out of the box, because they set the PATH appropriately?
  12. fanquake commented at 9:55 am on December 4, 2024: member

    Shouldn’t a venv “just work” out of the box, because they set the PATH appropriately?

    Apparently not. Here’s another case where CMake just picks some other Python:

    0# python --version
    1Python 3.13.1
    2# python3 --version
    3Python 3.13.1
    4# which python
    5/Users/xxx/.pyenv/shims/python
    6# cmake -B build
    7<snip>
    8-- Found Python3: /opt/homebrew/Frameworks/Python.framework/Versions/3.13/bin/python3.13 (found suitable version "3.13.0", minimum required is "3.10") found components: Interpreter
    
  13. hebasto commented at 10:44 am on December 4, 2024: member

    Shouldn’t a venv “just work” out of the box, because they set the PATH appropriately?

    Apparently not. Here’s another case where CMake just picks some other Python:

    0# python --version
    1Python 3.13.1
    2# python3 --version
    3Python 3.13.1
    4# which python
    5/Users/xxx/.pyenv/shims/python
    6# cmake -B build
    7<snip>
    8-- Found Python3: /opt/homebrew/Frameworks/Python.framework/Versions/3.13/bin/python3.13 (found suitable version "3.13.0", minimum required is "3.10") found components: Interpreter
    

    I cannot reproduce this on my Sequoia 15.1.1 (Intel):

    0% python3 --version
    1Python 3.10.15
    2% which python3
    3/Users/xxx/.venv/bin/python3
    4% cmake -B build
    5-- Found Python3: /Users/xxx/.venv/bin/python3.10 (found version "3.10.15") found components: Interpreter
    6<snip>
    

    CMake picks the Python from .venv while leaving system’s and Homebrew’s ones.

    Any specific steps are required to reproduce your issue?

  14. fanquake commented at 10:50 am on December 4, 2024: member

    CMake picks the Python from .venv

    I’m not using a .venv. It’s Python installed with pyenv.

  15. willcl-ark commented at 10:52 am on December 4, 2024: member

    Thanks @hebasto for the double-check. It has helped me work out what was going wrong for me (I think)…

    Looks like I had not bumped my python version in the venv since #30527 so I was still running 3.9 in my venv. This caused the cmake check to (silently) skip that version during configure and fallback to a “system” version (3.13).

    This was then combined with me manually exporting PYTHONPATH in this dir (to make Pyright perform better in nvim), which was causing a right mismatch of modules and python versions; with cmake launching files using one python and then importing modules from another env completely.

    So this seems to have been my error indeed.

    I can confirm that using a python 3.10 venv fixes the issue for me.

    I think I can probably close this now, and perhaps move to an issue while we figure out what cmake is doing with @fanquake’s setup? As this PR does not apparently fix that case, so seems largely useless now.

    NB I would note that it could be nice to give a warning when a venv is detected but not used (as it doesn’t meet requirements), but seems like a nice-to-have, rather than something essential.

  16. hebasto commented at 11:45 am on December 4, 2024: member

    CMake picks the Python from .venv

    I’m not using a .venv. It’s Python installed with pyenv.

    My apologies.

    Adding -DPython3_FIND_FRAMEWORK=LAST should work.

  17. fanquake commented at 11:50 am on December 4, 2024: member

    Adding -DPython3_FIND_FRAMEWORK=LAST should work.

    Right, so CMake just picks a different version here for some reason? Is this a bug? Do we need to document this, so it’s clear to users/developers that sometimes CMake will just ignore the shell/in-use Python version?

  18. hebasto commented at 12:01 pm on December 4, 2024: member

    Adding -DPython3_FIND_FRAMEWORK=LAST should work.

    Right, so CMake just picks a different version here for some reason? Is this a bug? Do we need to document this, so it’s clear to users/developers that sometimes CMake will just ignore the shell/in-use Python version?

    The behaviour is extensively documented:

    1. From the FindPython3 module docs:

    On macOS the Python3_FIND_FRAMEWORK variable determine the order of preference between Apple-style and unix-style package components. This variable can take same values as CMAKE_FIND_FRAMEWORK variable.

    Note: Value ONLY is not supported so FIRST will be used instead.

    If Python3_FIND_FRAMEWORK is not defined, CMAKE_FIND_FRAMEWORK variable will be used, if any.

    1. From the CMAKE_FIND_FRAMEWORK variable docs:

    This variable affects how find_* commands choose between macOS Frameworks and unix-style package components.

  19. fanquake commented at 12:12 pm on December 4, 2024: member

    The behaviour is extensively documented:

    Sure, but none of that means anything to a (new) developer, who doesn’t care about the intricacies of the build system. It’s just unintuituve that CMake would pick some version of Python, other than the one their shell/sytem is (globally) configured to use.

    We even suggest using pyenv in our documentation, so it makes even less sense that this workflow would be broken, or require workarounds that we haven’t documented.

  20. maflcko commented at 12:50 pm on December 4, 2024: member

    Does any of this matter in practise for running the tests? The tests should be passing for any supported python version, as long as it is above the minimum, which is what cmake already checks for. Also, the tests can be run with a python version explicitly, like python3.NN ./bld-cmake/test/functional/test_runner.py.

    Though, even for writing tests in python, the version should mostly be irrelevant now that python3 has matured for the commonly used batteries. Historically, one could accidentally write python3.6 code, when the minimum supported was 3.5, however I don’t think this is relevant today when new python features aren’t applicable to the tests in this repo anyway.

    In any case, if people think that forcing Python3_FIND_FRAMEWORK to one value or the other on macOS is helpful, I wont’ mind.

  21. fanquake commented at 1:02 pm on December 4, 2024: member

    Does any of this matter in practise for running the tests?

    If CMake picks a different Python to the one you expect it to use, which is not the one you’ve pip installed any requirements into, i.e pyzmq, aren’t you now (likely unknowningly) skipping tests that otherwise should be run.

  22. willcl-ark commented at 3:46 pm on December 4, 2024: member

    OK the issue here is that most venv providers export the VIRTUAL_ENV variable. I say most, because this appears to specifically exclude pyenv, for some reason.

    From the cmake docs:

    Python3_FIND_VIRTUALENV

    Added in version 3.15.
    
    This variable defines the handling of virtual environments managed by virtualenv or conda. It is meaningful only when a virtual environment is active (i.e. the activate script has been evaluated). In this case, it takes precedence over Python3_FIND_REGISTRY and CMAKE_FIND_FRAMEWORK variables. The Python3_FIND_VIRTUALENV variable can be set to one of the following:
    
        FIRST: The virtual environment is used before any other standard paths to look-up for the interpreter. This is the default.
    
        ONLY: Only the virtual environment is used to look-up for the interpreter.
    
        STANDARD: The virtual environment is not used to look-up for the interpreter but environment variable PATH is always considered. In this case, variable Python3_FIND_REGISTRY (Windows) or CMAKE_FIND_FRAMEWORK (macOS) can be set with value LAST or NEVER to select preferably the interpreter from the virtual environment.
    

    As FIRST is the default for this, all venv providers that set VIRTUAL_ENV should just work. I believe this is the case, as when I updated my venv to the required minimum version it began working again, without the need for this patch.

    Therefore the only remaining issue here IMO is how to handle pyenv. According to my research using pyenv-virtualenv as a plugin link sets this variable. But that doesn’t seem particularly nice. Alternatively start writing custom activation or bashrc scripts to set VIRTUAL_ENV, but that also is not appealing.

    I don’t think it can be solved in a cmake context without custom cmake find package logic, which I think we should avoid.

    Therefore my preference would be to recommend that folks move to uv, and we update our docs accordingly.

  23. hebasto commented at 5:12 pm on December 4, 2024: member

    Shouldn’t a venv “just work” out of the box, because they set the PATH appropriately?

    Apparently not. Here’s another case where CMake just picks some other Python:

    0# python --version
    1Python 3.13.1
    2# python3 --version
    3Python 3.13.1
    4# which python
    5/Users/xxx/.pyenv/shims/python
    6# cmake -B build
    7<snip>
    8-- Found Python3: /opt/homebrew/Frameworks/Python.framework/Versions/3.13/bin/python3.13 (found suitable version "3.13.0", minimum required is "3.10") found components: Interpreter
    

    Fixed in #31421.

  24. willcl-ark commented at 9:04 pm on December 4, 2024: member

    Fixed in #31421.

    Great, will close here then.

  25. willcl-ark closed this on Dec 4, 2024


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-21 15:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me