Install Python package from CMake

To handle the case where the user is using system Python, or otherwise has Python site-packages as a non-writable directory, we need the pip “–user” option to install the package under the user home directory. However, if using Python virtualenv (with or without conda) the pip “–user” option is invalid. CMake can use environment variables set by Python to detect when a virtualenv is being used by Python currently.

Using “pip” instead of “setup.py” is also important for locally installed packages, since pip via pyproject.toml will automatically use the latest setuptools. This is quite important as too many user systems have too-old setuptools. The project’s pyproject.toml file should contain at least:

pyproject.toml:

[build-system]
requires = ["setuptools", "wheel"]

CMakeLists.txt

find_package(Python3 COMPONENTS Interpreter REQUIRED)

# detect virtualenv and set Pip args accordingly
if(DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})
  set(_pip_args)
else()
  set(_pip_args "--user")
endif()

To install a package (named in CMake variable _pypkg_name) from PyPi:

# install PyPi Python package using pip
execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install ${_pypkg_name} ${_pip_args})

To install a local package in development mode (live changes):

# install Python package locally in development mode
execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install -e . ${_pip_args})

References

This is how CMake itself in Modules/FindPython/Support.cmake detects Python virtualenv.