Python3_INCLUDE_DIRS does not exist

Hi CMake,

I am trying to use CMake (3.25) on Windows with Visual Studio (2022). I need to include Python3 in my project. When I try to build the project it complains that it cannot find “Python.h”.
Both CMake and Python3 have been added to the system path.

I have the following in my “CMakeLists.txt”:

find_package (Python3 COMPONENTS Interpreter Development)

if (${Python3_FOUND})
message ("Found Python3 " ${Python3_VERSION})
message ("Found Python3 in " ${Python3_EXECUTABLE})
else()
message (“Couldn’t find Python3!”)
endif()

if (${Python3_INCLUDE_DIR})
message ("Found Python3 include directories: ")
else()
message (“Couldn’t find Python3 include directories!”)
endif()

if (${Python3_Interpreter_FOUND})
message (“Found Python3 Interpreter”)
else()
message (“Couldn’t find Python3 Interpreter!”)
endif()

if (${Python3_Development_FOUND})
message (“Found Python3 Development”)
else()
message (“Couldn’t find Python3 Development!”)
endif()

And when CMake generation runs, I get the following:

1> [CMake] Looking for Python3…
1> [CMake] Found Python3 3.11.1
1> [CMake] Found Python3 in C:/Tools/Python311_64/python.exe
1> [CMake] Couldn’t find Python3 include directories!
1> [CMake] Found Python3 Interpreter
1> [CMake] Found Python3 Development
1> [CMake] – Configuring done
1> [CMake] – Generating done
1> [CMake] – Build files have been written to: C:/Users/het/source/python_test/Python_in_CPP_CMake/out/build/x64-release
1> Extracted CMake variables.
1> Extracted source files and headers.
1> Extracted code model.
1> Extracted toolchain configurations.
1> Extracted includes paths.
1> CMake generation finished.

As far as I can see, everything looks fine, except for “Couldn’t find Python3 include directories!”! Which I assume also is the reason why it fails to build? Should the “Python3_INCLUDE_DIRS” variable not be automatically populated when Python3 is successfully located?

Am I doing something wrong? I hope you can help me make my project build.
Thanks.

Did you mean to check Python3_INCLUDE_DIRS here?

Yes. But the way you ask, makes me think I got something wrong :slight_smile:
I thought that “Python3_INCLUDE_DIRS” contained the path to the Python installation “include” directory. But maybe that is not the case?
Just as I assmue (guess) that “Python3_ROOT_DIR” should hold the path to the Python3 installation root directory. But that is maybe also not the case?
The root problem is that “Python.h” is not found, even though it is indeed in the “<python_root>/include” directory (that is discovered - CMake finds the “python.exe” file).

How are you trying to use Python that the header is not found? You should prefer using the Python3::… targets, not the variables.

As you have probably already guessed, I am new to CMake, but I thought I had at least understood some things. But maybe I was wrong.

I create a new CMake project in Visual Studio, and then make modifications for testing purposes. My CPP-file contains:

#include <stdio.h>
#include <conio.h>
#include <Python.h>

int main()
{
PyObject* pInt;

Py_Initialize();

PyRun_SimpleString(“print(‘Hello World from Embedded Python!!!’)”);

Py_Finalize();

printf(“\nPress any key to exit…\n”);
if (!_getch()) _getch();
return 0;
}

My top-level CMakeLists.txt file contains:

CMakeList.txt : Top-level CMake project file, do global configuration

and include sub-projects here.

cmake_minimum_required (VERSION 3.8)

project (“vs_cmake_test”)

Include sub-projects.

add_subdirectory (“vs_cmake_test”)

And the CMakeLists.txt file next to the CPP-file contains:

CMakeList.txt : CMake project for vs_cmake_test, include source and define

project specific logic here.

find_package (Python3 COMPONENTS Interpreter Development)
if (${Python3_FOUND})
message("Found Python3 " ${Python3_VERSION})
else()
message(“Couldn’t find Python3!”)
endif()

Add source to this project’s executable.

add_executable (vs_cmake_test “vs_cmake_test.cpp” “vs_cmake_test.h”)

if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET vs_cmake_test PROPERTY CXX_STANDARD 20)
endif()

If I try to build this, I get:

…vs_cmake_test\vs_cmake_test.cpp(6): fatal error C1083: Cannot open include file: ‘Python.h’: No such file or directory

I tried to add the following (before the “add_executable” statement):

Python3_add_library (vs_cmake_test SHARED Python3::Python)

But during CMake generation, this results in

[CMake] CMake Error at vs_cmake_test/CMakeLists.txt:15 (add_executable):
1> [CMake] add_executable cannot create target “vs_cmake_test” because another target
1> [CMake] with the same name already exists. The existing target is a shared library
1> [CMake] created in source directory
1> [CMake] “C:/Users/het/source/python_test/vs_cmake_test/vs_cmake_test”. See
1> [CMake] documentation for policy CMP0002 for more details.

I hope this sheds more light on what I am trying to do and what I have tried. And hopefully you can quickly spot what I am doing wrong.

What you’ve misunderstood is the name and spelling of the variable.

FindPython3 — CMake 3.25.2 Documentation

image

Whereas in your code you have written

if (${Python3_INCLUDE_DIR})

No variable of that name is set. If, instead, you wrote:

if (Python3_INCLUDE_DIRS)  # test if the variable is set and non-empty
   ...

then it would work. But this makes it look like you are learning CMake 2 and not modern CMake. You should instead write:

find_package (Python3 REQUIRED COMPONENTS Interpreter Development)

it will make an error of not finding the components you want.

The next step is where many people lose the plot with cmake, because it’s a major piece of common sense threaded onto what is a trivial piece of implementation detail for a cmake user. “target_link_libraries” is how you link two actual on-disk libraries together, but in cmake terms it’s also how you create a directed association between two “property libraries”.

Old CMake was entirely dependent on variables. New CMake is almost object-oriented, it wants you to associate things with targets.

But it only has two kinds of target, executables and libraries. So they used libraries, and they reused the term “link” :frowning: I think maybe it was an experiment and they lazily re-used existing features, and it stuck…

add_library ( graphics graphics.cpp graphics.h ...)
target_include_directories (graphics PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/gfx/internal)
target_include_directories (graphics PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/gfx)
target_compile_definitions (graphics INTERFACE -DENABLE_GRAPHICS=1)
target_link_libraries (graphics PUBLIC opengl)

The point of confusion is that sometimes a “library” target has no library, no source files, it’s just properties.

In the old days, that would have been done with lots of global variables:

### OLD: Do not do
add_library (graphics ...)
# make everything we build have this define, which may not be what you want.
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_GRAPHICS")
set (GRAPHICS_LIBS "${GRAPHICS_LIBS} graphics opengl")
...

as a consumer, you would need to know all the global variables you were supposed to use against your own code. If you missed the “GRAPHICS_LIBS” variable, you might get link errors.

### OLD: Do not do
add_executable (myprog main.cpp)
target_link_libraries (myprog ${GRAPHICS_LIBS})

If we go back to the new approach:

add_library ( graphics graphics.cpp graphics.h ...)
target_include_directories (graphics PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/gfx/internal)
target_include_directories (graphics PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/gfx)
target_compile_definitions (graphics INTERFACE -DENABLE_GRAPHICS=1)
target_link_libraries (graphics PUBLIC opengl)

we no-longer need to worry about variables. By attaching everything TO the target any being careful about ‘visibility’ (PRIVATE: only the target sees it, PUBLIC: target and any consumer sees it, INTERFACE: only consumers see it) we can do things in a much more logical, easier to reason about way:

add_executable (myprog main.cpp)
target_link_libraries (myprog graphics)

TLDR: “graphics” target brought everything we needed with it.

The Python3 find package supports this approach. Instead of worrying about the variables, you can simply link against one of the helper targets.

find_package (Python3 REQUIRED Interpreter Development)
add_executable (myprog myprog.cpp)
target_link_libraries (myprog Python3::Python)

this target has all the include paths, compiler flags, defines etc that you need. All you need to do is link - as in connect - the two libraries together.

Here is a complete example: kfsone/cmake-target: Using CMake targets instead of global variables (github.com)

Thank you for the thorough explanation and sorting things out! :slight_smile:

I have been searching high and low for guidance and examples, but guess I have mainly found legacy examples, which did not lead me in the right direction. And not understanding exactly what I doing wrong, didn’t make things easier.

My misspelling of “Python3_INCLUDE_DIRS” (omitting the final “S”) lead me to believe that the include directory was not found - while I could see that Python3 was indeed discovered. But in the end, the real error was “simply” not including Python in the right way.

Thanks!