I am testing the Python C_API using the program shown below with Python 3.8 on Ubuntu 18.04. I have tried compiling with Clang-10 and GCC 7.5, but in both cases the compiler is unable to locate Python.h.
When I run this string:
sudo gcc -v -shared -fPIC -l /usr/include/python3.8 -I/usr/lib -I/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -I/usr/lib/python3.8 -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -Wall -o Python_Math.o Python_Math.c
I get "Python_Math.c:2:10: fatal error: Python.h: No such file or directory #include <Python.h>"
I changed the string to this:
sudo gcc Python_Math.c -o Python_Math.o -v -shared -fPIC -l/usr/lib -l/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -I/usr/include/python3.8 -l/usr/lib/python3.8 -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -Wall
and I get:
/usr/bin/ld: cannot find -l/usr/lib /usr/bin/ld: cannot find -l/usr/lib/python3.8/config-3.8-x86_64-linux-gnu /usr/bin/ld: cannot find -l/usr/lib/python3.8
So I reduced the string to this:
sudo gcc Python_Math.c -o Python_Math.o -v -shared -fPIC -I/usr/include/python3.8 -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -Wall
Now the program compiles and links but when I run "nm" on Python_Math.o it shows all the imported symbols (including Py_Initialize) as undefined.
Finally I reduced the string to this:
sudo gcc Python_Math.c -o Python_Math.o -v -shared -fPIC -I/usr/include/python3.8 -lpython3.8 -Wall
and again it compiles and links but nm still shows symbols as "undefined."
If I change "I" in the string above to "L" for -L/usr/include/python3.8 I again get "Python.h" not found, and a message re the search paths for includes, which shows usr/include in the path.
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
The problem appears to be the path to Python.h. Locate says Python.h is located in /usr/include/python3.8/Python.h.
A question at Embedding Python in C, linking fails with undefined reference to `Py_Initialize' said to add "embed" on Ubuntu 20.04, but I haven't found a way to make that work with Ubuntu 18.04.
Here is the complete program:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int Lib_Math(char* module_name, char* fn_name, double value_in)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i = 0;
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(module_name);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, fn_name);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(value_in);
pValue = PyLong_FromDouble(value_in);
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", fn_name);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", module_name);
return 1;
}
if (Py_FinalizeEx() < 0) {
return 120;
}
return 0;
}
Thanks for any help with getting the right link options.