0

EDIT: this question was closed by the author of another answer, but the answer linked to doesn't answer my question (it also didn't answer the question of the OP, see his final comment). I understand the importance of order on the command line, but my question still remains unanswered (see my comment below re foo.o), although that answer does give useful tips. Thanks for any other feedback.

I am testing a Python C_API with Python 3.8 on Ubuntu 18.04. I compile and link to an object file using GCC 7.5 -- I will link that object file into the programs where I want to embed the C API program.

When I view the symbols in the resulting object file using nm, I see that all the C API symbols from libpython3.8.so (-lpython3.8) are undefined:

             U PyCallable_Check
             U PyErr_Occurred
             U PyErr_Print
             U PyImport_Import
             U PyLong_AsLong
             U PyLong_FromDouble
             U PyObject_CallObject
             U PyObject_GetAttrString
             U PyTuple_New
             U PyTuple_SetItem
             U PyUnicode_DecodeFSDefault
             U Py_FinalizeEx
             U Py_Initialize

I have tried numerous versions of the compiler and linker options, but still no resolution. Here are the latest two versions. Both versions compile and link without error but the symbols are undefined:

Version 1:

sudo gcc -v -shared -fPIC -I/usr/include/python3.8 -L/usr/lib/x86_64-linux-gnu/ -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu/ -lpython3.8 -lcrypt -lpthread -ldl  -lutil -lm -Wall -o Python_Math.o Python_Math.c

Version 2:

sudo gcc -v -shared -fPIC $(python3-config --cflags) $(python3-config --ldflags) -Wall -o Python_Math.o Python_Math.c

As of Python 3.8 we must add an "--embed" flag. "To embed Python into an application, a new --embed option must be passed to python3-config --libs --embed to get -lpython3.8 (link the application to libpython). To support both 3.8 and older, try python3-config --libs --embed first and fallback to python3-config --libs (without --embed) if the previous command fails." (see https://docs.python.org/3.8/whatsnew/3.8.html#debug-build-uses-the-same-abi-as-release-build

So I added to the new --embed option to the second string above:

sudo gcc -v -shared -fPIC $(python3-config --cflags) $(python3-config --ldflags) $(python3-config --libs --embed) -Wall -o Python_Math.o Python_Math.c

but with that I get this error from gcc:

gcc: error: unrecognized command line option ‘--prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir

A question at Embedding Python in C, linking fails with undefined reference to `Py_Initialize' shows the --embed tag differently -- $(python3-config --cflags --embed) but when I add that as shown I get the same error.

So my questions are: how do we link an object file to use for embedding with the Python C API as of Python 3.8? Why am I getting undefined symbols?

Here is the complete program (Python_Math.c):

#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);

        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 this.

RTC222
  • 2,025
  • 1
  • 20
  • 53
  • C file must come before libs. The duplicate target explains that and goes on to explain how one can link against a static libpython, if needed – ead Oct 10 '21 at 17:05
  • In the answer you linked to you show gcc -L/path foo.o -lpython3.x -- what is foo.o in my case? I can't use Python_Math.o because that's the output. I link to libpython3.8.so but there is no /libpython3.8.o. Can you clarify? Thanks. – RTC222 Oct 10 '21 at 17:47

0 Answers0