5

I am creating a starter project with CMake (3.16.3) and pybind11 (2.4.3) in VSCode (1.46.1) on Ubuntu (20.04) which has both Python 2.7 and 3.8 on it by default. I want to build a module for Python3. When I use the following two lines in my CMakeLists.txt

find_package(pybind11)
find_package(Python COMPONENTS Interpreter Development REQUIRED)

The CMake configuration is

[cmake] -- Found PythonInterp: /usr/bin/python (found version "2.7.18")  
[cmake] -- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython2.7.so  
[cmake] -- Found Python3: /usr/bin/python3.8 (found version "3.8.2") found components: Interpreter Development 

Switching the order of the find_package statements

find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(pybind11)

Gives the same python links but with the new order

[cmake] -- Found Python: /usr/bin/python3.8 (found version "3.8.2") found components: Interpreter Development 
[cmake] -- Found PythonInterp: /usr/bin/python (found version "2.7.18") 
[cmake] -- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython2.7.so

I am new to this. I have read in the FAQ about inconsistent versions but I think I'm doing all the right things (I do not call find_package(PythonInterp) nor find_package(PythonLibs) but rather stick to find_package(Python)). That seems to be working, it seems find_package(pybind11) is defaulting to python2.7 (incorrectly if I understand the documents) and I do not know how set it. I have tried things like # set(bindings_python_version 3.8) but this does not change anything.

I have this working on a Windows based machine but that only has one version of Python on it so there is no chance for confusion

Steven
  • 253
  • 3
  • 11
  • I solved this by calling set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) after find_package(Python3...). I guess you could do the same for find_package(Python) – tobi_s Aug 03 '20 at 06:09

3 Answers3

6

So in the end, calling set(PYBIND11_PYTHON_VERSION 3.8 CACHE STRING "") before calling find_package(pybind11) solves my problem although it does not help me understand why pybind11 defaults to 2.7. If anyone can point me to an explanation, I would be very grateful.

Steven
  • 253
  • 3
  • 11
4

I found this issue fairly perplexing and I finally decided to not use pybind11_add_module at all. After reviewing the code it was clear that pybind11_add_module doesn't do anything complicated or important while doing a number of things that interfere with the remainder of the CMake project (searching its own Python, setting compiler options). In conclusion, it makes everybody's life simpler to avoid it.

Instead, simply define a target that sets the correct include path

add_library(pybind11::pybind11 IMPORTED)
target_include_directories(pybind11::pybind11 INTERFACE ${PATH_TO_PYBIND11})

Also make sure to make Python available to your CMake project

find_package(Python3 COMPONENTS Interpreter Development)

Then define your python modules in the standard Python way, and add the pybind11 library to them just like you would any other library

Python3_add_library(MyModule MODULE PythonInterface.cpp)
target_link_libraries(MyModule PRIVATE pybind11::pybind11)

You can add multiple source files, compiler flags, libraries etc in the usual way and you remain in complete control of which Python is used, what compiler flags are used and so on.

tobi_s
  • 1,324
  • 13
  • 16
0

This seems to have done the trick for me:

set(PYBIND11_PYTHON_VERSION 3)
set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG)
kjohnsen
  • 360
  • 5
  • 15