Search code examples
pythonc++cmake

undefined reference to `Py_DecodeLocale'


I'm embedding Python into a C++ project with example code from https://docs.python.org/3/extending/embedding.html#very-high-level-embedding:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(python_in_cpp)

set(CMAKE_CXX_STANDARD 11)

# sudo apt install libpython3.11-dev

find_package(PythonLibs 3.11 REQUIRED)

find_package(Python COMPONENTS Interpreter Development)

message("Python_FOUND:${Python_FOUND}")
message("Python_VERSION:${Python_VERSION}")
message("Python_Development_FOUND:${Python_Development_FOUND}")
message("Python_LIBRARIES:${Python_LIBRARIES}")

include_directories(${Python_INCLUDE_DIRS})

link_directories(
        ${Python3_LIBRARY_DIRS}
        ${Python3_RUNTIME_LIBRARY_DIRS}
)

link_libraries(${Python3_LIBRARIES})

add_executable(python_in_cpp main.cpp)

main.cpp:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int
main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    if (Py_FinalizeEx() < 0) {
        exit(120);
    }
    PyMem_RawFree(program);
    return 0;
}

CMake log shows that both Python and PythonLibs found but when compiling, I got errors about several undefined reference:

main.cpp:(.text+0x1f): undefined reference to `Py_DecodeLocale'
/usr/bin/ld: main.cpp:(.text+0x63): undefined reference to `Py_SetProgramName'
/usr/bin/ld: main.cpp:(.text+0x68): undefined reference to `Py_Initialize'
/usr/bin/ld: main.cpp:(.text+0x7c): undefined reference to `PyRun_SimpleStringFlags'
/usr/bin/ld: main.cpp:(.text+0x81): undefined reference to `Py_FinalizeEx'
/usr/bin/ld: main.cpp:(.text+0x9e): undefined reference to `PyMem_RawFree'

How do I fix it to build this project?


I have several python installed:

$ apt list --installed | grep "lib*python"

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

libpython3-dev/stable,now 3.11.2-1+b1 amd64 [installed]
libpython3-stdlib/stable,now 3.11.2-1+b1 amd64 [installed,automatic]
libpython3.11-dev/stable-security,now 3.11.2-6+deb12u3 amd64 [installed]
libpython3.11-minimal/stable-security,now 3.11.2-6+deb12u3 amd64 [installed,automatic]
libpython3.11-stdlib/stable-security,now 3.11.2-6+deb12u3 amd64 [installed,automatic]
libpython3.11/stable-security,now 3.11.2-6+deb12u3 amd64 [installed,automatic]

Solution

  • It's a stupid typo. You printed Python_LIBRARIES but you used Python3_LIBRARIES in your link_libraries statement.

    To avoid these kind of issues in the future, you should prefer using imported targets if they are provided by the modules.

    You can replace your three statements (include_directories, link_directories and link_libraries) with just this one line:

    target_link_libraries(python_in_cpp PUBLIC Python::Python)
    

    Make sure to put that after the add_executable statement.