Skip to content

[BUG] Isolated build env breaks console scripts installed in other venv (e.g., cmake, ninja) #13222

Open
@XuehaiPan

Description

@XuehaiPan

Description

For packages that contain extension modules, they may need to use build tools such as cmake / ninja. There are PyPI packages that ship those tools with console scripts. E.g., pip3 install cmake will create an executable ${PROJECT}/venv/bin/cmake.

#!${PROJECT}/venv/bin/python3.13
# -*- coding: utf-8 -*-
import re
import sys
from cmake import cmake
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(cmake())

When installing a user package from the source, pip will create an isolated build environment (venv (B)). During installing the user package, the setup script may invoke the cmake executable in the PATH mentioned above (installed in venv (A)). However, in the build environment (venv (B)), the cmake script (interpreted by Python in venv (A)) failed to find the cmake module installed in venv (A).

See issue scikit-build/cmake-python-distributions#586 for more information.

I think this issue is caused by the suspicious sitecustomize.py in the build environment:

# Customize site to:
# - ensure .pth files are honored
# - prevent access to system site packages
system_sites = _get_system_sitepackages()
self._site_dir = os.path.join(temp_dir.path, "site")
if not os.path.exists(self._site_dir):
os.mkdir(self._site_dir)
with open(
os.path.join(self._site_dir, "sitecustomize.py"), "w", encoding="utf-8"
) as fp:
fp.write(
textwrap.dedent(
"""
import os, site, sys
# First, drop system-sites related paths.
original_sys_path = sys.path[:]
known_paths = set()
for path in {system_sites!r}:
site.addsitedir(path, known_paths=known_paths)
system_paths = set(
os.path.normcase(path)
for path in sys.path[len(original_sys_path):]
)
original_sys_path = [
path for path in original_sys_path
if os.path.normcase(path) not in system_paths
]
sys.path = original_sys_path
# Second, add lib directories.
# ensuring .pth file are processed.
for path in {lib_dirs!r}:
assert not path in sys.path
site.addsitedir(path)
"""
).format(system_sites=system_sites, lib_dirs=self._lib_dirs)
)

Expected behavior

The console script (e.g., cmake) should always be runnable if invoked in a subprocess with an absolute path.

pip version

25.0.1

Python version

3.13.2

OS

macOS

How to Reproduce

  1. Create a setup.py with content:
# setup.py

import os
import shutil
from pathlib import Path

from setuptools import Extension, setup
from setuptools.command.build_ext import build_ext


HERE = Path(__file__).absolute().parent


class CMakeExtension(Extension):
    def __init__(self, name, source_dir=".", target=None, **kwargs):
        super().__init__(name, sources=[], **kwargs)
        self.source_dir = Path(source_dir).absolute()
        self.target = target if target is not None else name.rpartition(".")[-1]

    @classmethod
    def cmake_executable(cls):
        cmake = os.getenv("CMAKE_EXECUTABLE", "")
        if not cmake:
            cmake = shutil.which("cmake")
        return cmake


class cmake_build_ext(build_ext):
    def build_extension(self, ext):
        if not isinstance(ext, CMakeExtension):
            super().build_extension(ext)
            return

        cmake = ext.cmake_executable()
        if cmake is None:
            raise RuntimeError("Cannot find CMake executable.")

        self.spawn([cmake, "--version"])


setup(
    name="cmake-venv-test",
    version="0.0.1",
    cmdclass={"build_ext": cmake_build_ext},
    ext_modules=[CMakeExtension("cmake_venv_test._C", source_dir=HERE)],
)
  1. Run the following commands:
$ python3 -m venv venv
$ source venv/bin/activate
$ pip3 install cmake
$ which cmake
${PROJECT}/venv/bin/cmake

$ pip3 install .
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Processing ${PROJECT}
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: cmake-venv-test
  Building wheel for cmake-venv-test (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for cmake-venv-test (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [9 lines of output]
      running bdist_wheel
      running build
      running build_ext
      ${PROJECT}/venv/bin/cmake --version
      Traceback (most recent call last):
        File "${PROJECT}/venv/bin/cmake", line 5, in <module>
          from cmake import cmake
      ModuleNotFoundError: No module named 'cmake'
      error: command '${PROJECT}/venv/bin/cmake' failed with exit code 1
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for cmake-venv-test
Failed to build cmake-venv-test

ERROR: Failed to build installable wheels for some pyproject.toml based projects (cmake-venv-test)

Output

$ pip3 install .
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Processing ${PROJECT}
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: cmake-venv-test
  Building wheel for cmake-venv-test (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for cmake-venv-test (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [9 lines of output]
      running bdist_wheel
      running build
      running build_ext
      ${PROJECT}/venv/bin/cmake --version
      Traceback (most recent call last):
        File "${PROJECT}/venv/bin/cmake", line 5, in <module>
          from cmake import cmake
      ModuleNotFoundError: No module named 'cmake'
      error: command '${PROJECT}/venv/bin/cmake' failed with exit code 1
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for cmake-venv-test
Failed to build cmake-venv-test

ERROR: Failed to build installable wheels for some pyproject.toml based projects (cmake-venv-test)

The error raises when installing with and without the --editable flag.

There will be no error if do either of the following:

  • Add cmake to build-system.requires in pyproject.toml.
  • Install with flag --no-build-isolation.

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    C: PEP 517 impactAffected by PEP 517 processingstate: needs eyesNeeds a maintainer/triager to take a closer looktype: bugA confirmed bug or unintended behavior

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions