Problem with compiling c++ project that is running python code using Python.h -> undefined reference

51 Views Asked by At

I have problem when i try to compile my c++ project using g++ on windows

The code:

#include <python.h>

int main(int argc, char **argv)
{
    Py_Initialize();
    PyRun_SimpleString("print('Hello World!')");
    Py_Finalize();
    
    return 0;
}

I am using this command:

g++ -I C:\Python310\include main.cpp -o output -L C:\Python310\libs -lpython310

And it always gives me this error about undefined references:

AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0x1f): undefined reference to `_imp__Py_DecodeLocale'
AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0x6c): undefined reference to `_imp__Py_SetProgramName'
AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0x73): undefined reference to `_imp__Py_Initialize'
AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0x8d): undefined reference to `_imp__PyRun_SimpleStringFlags'
AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0x94): undefined reference to `_imp__Py_FinalizeEx'
AppData\Local\Temp\ccQdtubj.o:main.cpp:(.text+0xb5): undefined reference to `_imp__PyMem_RawFree'
collect2.exe: error: ld returned 1 exit status
1

There are 1 best solutions below

6
Mike Kinghan On

You are attempting to link a program compiled with Windows g++ (x86_64-w64-mingw32-g++.exe) against an import library C:/Python310/libs/python310.lib that was built with Micosoft MSVC. That will not work because x86_64-w64-mingw32 libraries are incompatible with MSVC libraries. Get the x86_64-w64-mingw32 python library for MSYS2 and build using its header files and libraries.

Consider installing and using MSYS2 as your working gcc/g++ environment on Windows.

With that environment, a compile-and-link commandline (using the Windows filesystem) ought be like:

# Link with explicitly versioned import library 
g++ -I C:\msys64\mingw64\include -I C:\msys64\mingw64\include\python3.11 main.cpp \
    -o output -L C:\msys64\mingw64\lib -lpython3.11

or:

# Link with unversioned import library 
g++ -I C:\msys64\mingw64\include -I C:\msys64\mingw64\include\python3.11 main.cpp \
    -o output -L C:\msys64\mingw64\lib -lpython3
    

An import library in the msys64 environment is not called name.lib as per Windows but libname.dll.a, C:\msys64\mingw64\lib\libpython3.dll.a being for example the import library for C:\msys64\mingw64\bin\libpython3.dll

Later

@MatyVymlátil commented:

I used the second command you gave me and it isn't giving me error about the python library, but about undefined reference to 'PyRun_SimpleStringFlags' and I don't know why.

It turns out that PyRun_SimpleStringFlags is undefined in libpython3.dll.a but is defined in libpython3.11.dll.a. Assuming (which appears to be true) that you have extended your PATH with C:\msys64\mingw64\bin;C:\msys64\mingw64\x86_64-w64-min\bin, you can check things like this in Powershell like:

> nm C:\msys64\mingw64\lib\libpython3.dll.a | findstr PyRun_SimpleStringFlags; echo Done
Done

in contrast with:

> nm C:\msys64\mingw64\lib\libpython3.11.dll.a | findstr PyRun_SimpleStringFlags; echo Done
0000000000000000 I __imp_PyRun_SimpleStringFlags
0000000000000000 T PyRun_SimpleStringFlags
Done

Or in the MSYS2 shell ( = Linux bash) like:

$ nm /c/msys64/mingw64/lib/libpython3.dll.a | grep PyRun_SimpleStringFlags; echo Done
Done

$ nm /c/msys64/mingw64/lib/libpython3.11.dll.a | grep PyRun_SimpleStringFlags; echo Done
0000000000000000 I __imp_PyRun_SimpleStringFlags
0000000000000000 T PyRun_SimpleStringFlags
Done

See the nm manual

That means you have to use the first command for a successful linkage. In Powershell

> g++ -I C:\msys64\mingw64\include -I C:\msys64\mingw64\include\python3.11 main.cpp -o output -L C:\msys64\mingw64\lib -l python3.11
> .\output.exe
Could not find platform dependent libraries <exec_prefix>
Hello World!

Or in MSYS2 shell:

$  g++ -I /c/msys64/mingw64/include -I /c/msys64/mingw64/include/python3.11 main.cpp -o output -L /c/msys64/mingw64/lib -l python3.11
$ ./output.exe
Could not find platform dependent libraries <exec_prefix>
Hello World!

That warning:

Could not find platform dependent libraries <exec_prefix>

will happen if you do not have the environment variables PYTHONHOME and PYTHONPATH set (correctly) in your the shell environment in which output.exe is launched or more specifically the spawned environment is which your program calls python.

You can set those variables and make the warning go away. In Powershell:

> $env:pythonhome = "C:\msys64\\mingw64\lib\"
> $env:pythonpath = "C:\msys64\mingw64\lib\python3.11"
> .\output.exe
Hello World!

Or in MSYS2 shell:

$ export PYTHONHOME=/c/msys64/mingw64/lib
$ export PYTHONPATH=/c/msys64/mingw64/lib/python3.11
$ ./output.exe
Hello World!

And of course you can set these variables permanently in the Windows settings for your user profile or the system profile.

You could also set those environment variables in your program itself before calling Py_Initialize, but that would be unduly hard-coded.