Search code examples
c++python-3.xcmake

Attempting to build python binary modules on manylinux: find_package(Python3) only works with Development.Module


I'm building a Python module that I'd like to distribute to multiple linux distributions, some of which will have less recent versions of gcc than I am building with, hence I am using manylinux. In particular, I'm using manylinux_2_28, which is alma (Red Hat family) based and provides gcc12.

Having downloaded the image, I've cloned my repo, and have almost gotten CMake configure to work. The problem starts with

find_package(Python3 ${REQUESTED_PYTHON_VERSION} COMPONENTS Interpreter Development)

which gives

Could NOT find Python3 (missing: Python3_LIBRARIES Development Development.Embed) (found version "3.12.3")

and subsequently the configuration errors out when bringing in pybind11.

The image provides Python

CPython 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 and PyPy 3.7, 3.8, 3.9, 3.10 installed in /opt/python/-. The directories are named after the PEP 425 tags for each environment --e.g. /opt/python/cp37-cp37m contains a CPython 3.7 build, and can be used to produce wheels named like --cp37-cp37m-.whl.

hence before my configuration I prefix my PATH with /opt/python/cp312-cp312/bin so that which python3 => /opt/python/cp312-cp312/bin/python3.

My original question was how to overcome the problem. However, with more searching, I found an answer on CMake discourse. I.e. use Development.Module rather than Development.

find_package(Python3 ${REQUESTED_PYTHON_VERSION} COMPONENTS Interpreter Development.Module)

As I'd hoped, Python development is already available for each version. But what is going here? What is CMake actually looking for that it finds with Development.Module rather than Development, and what are the underlying files that gcc / the linker wants -- presumably these are the files present under include and lib in /opt/python/cp312-cp312/?


Solution

  • Since CMake 3.18, the FindPython module splits Development into Development.Module and Development.Embed. The former is to create Python modules, the latter to create a program that embeds the Python interpreter.

    Manylinux has the libraries for creating modules, but not the ones for embedded Python. So on Manylinux you must use Development.Module.


    By the way, you should use find_package(Python …) instead of find_package(Python3 …). The FindPython2 and FindPython3 modules are needed when both Python 2 and 3 must be managed at the same time. Python 2 has been at end of life for a very long time, Python is always Python 3 nowadays. By not explicitly using “Python 3” everywhere, it’ll be easier to transition to Python 4 when that arrives.