From 61c8c965abcbafc018cf3bb9f45495bd37cda190 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 12 May 2025 13:59:30 -0400 Subject: [PATCH 1/4] chore(cmake): add CMake presets Signed-off-by: Henry Schreiner --- .github/workflows/ci.yml | 21 +++++------ CMakeLists.txt | 60 ++++++++++++++++++++++++++++---- CMakePresets.json | 75 ++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + 4 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 CMakePresets.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db75ffaff4..2cf541d329 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -220,25 +220,20 @@ jobs: with: fetch-depth: 0 - - name: Prepare venv - run: python3.13t -m venv .venv + - name: Prepare uv's path + run: echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Install Python deps - run: .venv/bin/pip install -r tests/requirements.txt + - name: Install ninja + run: uv tool install ninja - - name: Configure C++11 - run: > - cmake -S. -Bbuild - -DPYBIND11_WERROR=ON - -DDOWNLOAD_CATCH=ON - -DDOWNLOAD_EIGEN=ON - -DPython_ROOT_DIR=.venv + - name: Configure via preset + run: cmake --preset venv -DPYBIND11_CREATE_WITH_UV=python3.13t - name: Build C++11 - run: cmake --build build -j2 + run: cmake --build --preset venv - name: Python tests C++11 - run: cmake --build build --target pytest -j2 + run: cmake --build --preset venvtests deadsnakes: strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index d570112dd1..4a2122eeda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,13 +113,59 @@ set(PYBIND11_FINDPYTHON ${_pybind11_findpython_default} CACHE STRING "Force new FindPython - NEW, OLD, COMPAT") -# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests -# (makes transition easier while we support both modes). -if(PYBIND11_MASTER_PROJECT - AND PYBIND11_FINDPYTHON - AND DEFINED PYTHON_EXECUTABLE - AND NOT DEFINED Python_EXECUTABLE) - set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}") +if(PYBIND11_MASTER_PROJECT) + + # Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests + # (makes transition easier while we support both modes). + if(PYBIND11_FINDPYTHON + AND DEFINED PYTHON_EXECUTABLE + AND NOT DEFINED Python_EXECUTABLE) + set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}") + endif() + + if(NOT DEFINED Python3_EXECUTABLE + AND NOT DEFINED Python_EXECUTABLE + AND NOT DEFINED Python_ROOT_SIR + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.venv") + message(STATUS "Autodetecting Python in virtual environment") + set(Python_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.venv") + endif() + + # This is a shortcut that is primarily for the venv cmake preset, + # but can be used to quickly setup tests manually, too + set(PYBIND11_CREATE_WITH_UV + "" + CACHE STRING "Create a virtualenv in Python_ROOT_DIR with uv if it doesn't exist") + + if(NOT PYBIND11_CREATE_WITH_UV STREQUAL "") + if(NOT DEFINED Python_ROOT_DIR) + message(FATAL_ERROR "Python_ROOT_DIR must be defined to use PYBIND11_CREATE_WITH_UV") + endif() + if(EXISTS "${Python_ROOT_DIR}") + message(STATUS "Using existing venv at ${Python_ROOT_DIR}, remove to recreate") + else() + find_program(UV uv REQUIRED) + # CMake 3.19+ would be able to use COMMAND_ERROR_IS_FATAL + message( + STATUS "Creating venv with ${UV} venv -p ${PYBIND11_CREATE_WITH_UV} '${Python_ROOT_DIR}'") + execute_process(COMMAND ${UV} venv -p ${PYBIND11_CREATE_WITH_UV} "${Python_ROOT_DIR}" + RESULT_VARIABLE _venv_result) + if(_venv_result AND NOT _venv_result EQUAL 0) + message(FATAL_ERROR "uv venv failed with '${_venv_result}'") + endif() + message( + STATUS + "Installing deps with ${UV} pip install -p '${Python_ROOT_DIR}' -r tests/requirements.txt" + ) + execute_process( + COMMAND ${UV} pip install -p "${Python_ROOT_DIR}" -r + "${CMAKE_CURRENT_SOURCE_DIR}/tests/requirements.txt" RESULT_VARIABLE _pip_result) + if(_pip_result AND NOT _pip_result EQUAL 0) + message(FATAL_ERROR "uv pip install failed with '${_pip_result}'") + endif() + endif() + endif() + endif() # NB: when adding a header don't forget to also add it to setup.py diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..b56fc68615 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,75 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "default", + "displayName": "Default", + "binaryDir": "build/default", + "generator": "Ninja", + "cacheVariables": { + "PYBIND11_FINDPYTHON": "NEW", + "PYBIND11_WERROR": true, + "DOWNLOAD_CATCH": true, + "DOWNLOAD_EIGEN": true + } + }, + { + "name": "venv", + "displayName": "Venv", + "binaryDir": "build/venv", + "generator": "Ninja", + "cacheVariables": { + "PYBIND11_CREATE_WITH_UV": "python3", + "Python_ROOT_DIR": ".venv", + "PYBIND11_WERROR": true, + "PYBIND11_FINDPYTHON": "NEW", + "DOWNLOAD_CATCH": true, + "DOWNLOAD_EIGEN": true + } + } + ], + "buildPresets": [ + { + "name": "default", + "displayName": "Default Build", + "configurePreset": "default" + }, + { + "name": "venv", + "displayName": "Venv Build", + "configurePreset": "venv" + }, + { + "name": "tests", + "displayName": "Default Tests Build", + "configurePreset": "default", + "targets": ["pytest", "cpptest", "test_cmake_build"] + }, + { + "name": "testsvenv", + "displayName": "Venv Tests Build", + "configurePreset": "venv", + "targets": ["pytest", "cpptest", "test_cmake_build"] + } + ], + "workflowPresets": [ + { + "name": "default", + "displayName": "Default Workflow", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "default" }, + { "type": "build", "name": "tests" } + ] + }, + { + "name": "venv", + "displayName": "Default Workflow", + "steps": [ + { "type": "configure", "name": "venv" }, + { "type": "build", "name": "venv" }, + { "type": "build", "name": "testsvenv" } + ] + } + ] +} diff --git a/pyproject.toml b/pyproject.toml index 38deff474a..63fb76a89d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ ignore = [ "pybind11/include/**", "pybind11/share/**", "CMakeLists.txt", + "CMakePresets.json", "noxfile.py", ] From 03170bbac1dec0f86fa5b041a802e4a1f2c83049 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 May 2025 01:23:26 -0400 Subject: [PATCH 2/4] Update .github/workflows/ci.yml --- .github/workflows/ci.yml | 20 +++++++------------- CMakePresets.json | 15 ++++++++++----- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2cf541d329..365829ce18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,7 +233,7 @@ jobs: run: cmake --build --preset venv - name: Python tests C++11 - run: cmake --build --preset venvtests + run: cmake --build --preset testsvenv -t pytest deadsnakes: strategy: @@ -287,33 +287,27 @@ jobs: run: | sudo make install sudo apt-get update - sudo apt-get install libc6-dbg # Needed by Valgrind + sudo apt-get install ninja-build libc6-dbg - name: Prepare env run: | python -m pip install -r tests/requirements.txt - name: Configure - run: > - cmake -S . -B build - -DCMAKE_BUILD_TYPE=Debug - -DPYBIND11_WERROR=ON - -DDOWNLOAD_CATCH=ON - -DDOWNLOAD_EIGEN=ON - -DCMAKE_CXX_STANDARD=17 + run: cmake --preset default -DCMAKE_CXX_STANDARD=17 - name: Build - run: cmake --build build -j 2 + run: cmake --build --preset default - name: Python tests - run: cmake --build build --target pytest + run: cmake --build --preset default --target pytest - name: C++ tests - run: cmake --build build --target cpptest + run: cmake --build --preset default --target cpptest - name: Run Valgrind on Python tests if: matrix.valgrind - run: cmake --build build --target memcheck + run: cmake --build --preset default --target memcheck # Testing on clang using the excellent silkeh clang docker images diff --git a/CMakePresets.json b/CMakePresets.json index b56fc68615..57a1c0b2f3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -4,9 +4,14 @@ { "name": "default", "displayName": "Default", - "binaryDir": "build/default", + "binaryDir": "build", "generator": "Ninja", + "errors": { + "dev": true, + "deprecated": true + }, "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", "PYBIND11_FINDPYTHON": "NEW", "PYBIND11_WERROR": true, "DOWNLOAD_CATCH": true, @@ -16,9 +21,9 @@ { "name": "venv", "displayName": "Venv", - "binaryDir": "build/venv", - "generator": "Ninja", + "inherits": "default", "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", "PYBIND11_CREATE_WITH_UV": "python3", "Python_ROOT_DIR": ".venv", "PYBIND11_WERROR": true, @@ -41,13 +46,13 @@ }, { "name": "tests", - "displayName": "Default Tests Build", + "displayName": "Tests (for workflow)", "configurePreset": "default", "targets": ["pytest", "cpptest", "test_cmake_build"] }, { "name": "testsvenv", - "displayName": "Venv Tests Build", + "displayName": "Tests Venv (for workflow)", "configurePreset": "venv", "targets": ["pytest", "cpptest", "test_cmake_build"] } From e7cf14f39dd3b6fb48297302b938daec606bfa45 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 May 2025 18:13:38 -0400 Subject: [PATCH 3/4] fix: don't autodetect `.venv` if inside a VIRTUALENV already Signed-off-by: Henry Schreiner --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a2122eeda..2cdf6b1c54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,7 @@ if(PYBIND11_MASTER_PROJECT) if(NOT DEFINED Python3_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE AND NOT DEFINED Python_ROOT_SIR + AND NOT DEFINED ENV{VIRTUALENV} AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.venv") message(STATUS "Autodetecting Python in virtual environment") set(Python_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.venv") From e528ebc8b85ced531dee6da8fc2b1cda84c92ce3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 14 May 2025 00:27:11 -0400 Subject: [PATCH 4/4] Update CMakeLists.txt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cdf6b1c54..1028b1b166 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,7 @@ if(PYBIND11_MASTER_PROJECT) if(NOT DEFINED Python3_EXECUTABLE AND NOT DEFINED Python_EXECUTABLE - AND NOT DEFINED Python_ROOT_SIR + AND NOT DEFINED Python_ROOT_DIR AND NOT DEFINED ENV{VIRTUALENV} AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.venv") message(STATUS "Autodetecting Python in virtual environment")