Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

/usr/bin/ld: cannot find -lpython-dev on Ubuntu. Compiling C program using PyObject

Tags:

python

c

gcc

ubuntu

I have the following C program which I need to integrate with Python:

#include <Python.h>

PyObject* get_details(){
    PyObject *details = PyDict_New();
    PyObject *key, *value;
    key = PyUnicode_FromString("full name");
    value = PyUnicode_FromString("Pete Graham");
    PyDict_SetItem(details, key, value);
    return details;
}

I can compile the program on OS X using:

gcc -I /Library/Frameworks/Python.framework/Versions/3.4/Headers \
-L /Library/Frameworks/Python.framework/Versions/3.4/lib \
-lpython3.4 get_person_dict.c

I get an error when I try and compile the program on Ubuntu /usr/bin/ld: cannot find -lpython3.4.

This is the command I'm using on Ubuntu I've tried various values for the python lib path.

gcc -I /usr/include/python3.4 \
-L /usr/local/lib \
-lpython3.4 get_person_dict.c

I installed python with sudo apt-get install python3.4-dev the version of Ubuntu trusty64 and is being used on Vagrant.

like image 936
pxg Avatar asked Jul 18 '26 01:07

pxg


2 Answers

There are several things wrong.

As @JJHakala has advised you,

python3.4-config --libs

will tell you the libraries you need in order to link an executable with the Python 3.4 runtime, viz:

-lpython3.4m -lpthread -ldl  -lutil -lm

And

python3.4-config --ldflags

will tell you all the options you must pass to the linker to achieve the same end, viz:

-L/usr/lib/python3.4/config-3.4m-x86_64-linux-gnu \
-L/usr/lib -lpython3.4m -lpthread -ldl  -lutil -lm \
 -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

So let's try putting those linker options into your gcc commandline instead of the linker options you've used. Your commandline was:

$ gcc -I /usr/include/python3.4 -L/usr/local/lib -lpython3.4 get_person_dict.c

with linker options:

-L/usr/local/lib -lpython3.4

So we'll try:

$ gcc -I /usr/include/python3.4 `python3.4-config --ldflags` get_person_dict.c

That doesn't work. The output is:

/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
/build/buildd/glibc-2.21/csu/../sysdeps/x86_64/start.S:114: undefined reference to `main'
/tmp/ccrczTMI.o: In function `get_details':
get_person_dict.c:(.text+0x9): undefined reference to `PyDict_New'
get_person_dict.c:(.text+0x17): undefined reference to `PyUnicode_FromString'
get_person_dict.c:(.text+0x25): undefined reference to `PyUnicode_FromString'
get_person_dict.c:(.text+0x40): undefined reference to `PyDict_SetItem'
collect2: error: ld returned 1 exit status

We have undefined references to all the Python 3.4 functions that are called in get_person_dict.c, and an undefined reference to main

The reason for that the undefined Python 3.4 references is that you were, and still are, passing the libraries to the linker before any file that calls functions defined in them. So the linker comes to each library on the commandline in turn and says to itself: Have I yet noted any calls to undefined functions that have definitions in this library? No. Then I don't need to link anything from this library. And passes on. After all the libraries have been ignored, it reaches your get_person_dict.c (or in reality, the temporary object file /tmp/ccrczTMI.o that the compiler has previously compiled from get_person_dict.c). There is finds undefined references PyDict_New, PyUnicode_FromString PyUnicode_FromString, PyDict_SetItem. But now there are no libraries left in which they might be defined. The libraries in which they are defined are water under the bridge, so the undefined references remain as linkage errors.

In the linkage sequence, files that need definitions must appear before the files that provide the definitions.

Well that's easily corrected:

$ gcc -I /usr/include/python3.4  get_person_dict.c `python3.4-config --ldflags`

Now the output is:

/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
/build/buildd/glibc-2.21/csu/../sysdeps/x86_64/start.S:114: undefined reference to `main'
collect2: error: ld returned 1 exit status

The linker has now found definitions for all the Python 3.4 functions. But it still says it can't find a definition for main.

The reason for that is the the C "program" you've posted isn't a program, it's just a definition of a function PyObject* get_details(). Every C program, by definition, has a main function, which is the first function called. For that reason, when you try to link some files and libraries into a C program, as you are trying to do, the linker automatically links startup code that calls main. But you have no main.

So you can't link your get_person_dict.c as a program, even if you get the linkage order right. You can compile it, without linking it:

$ gcc -I /usr/include/python3.4  -c -o get_person_dict.o get_person_dict.c

That gives you an object file get_person_dict.o which contains the compiled, but unlinked, definition of PyObject* get_details(). It will be identical to the temporary object file /tmp/ccrczTMI.o that gcc compiled for you without being told to in the failed compile-and-link attempt above.

But having compiled your get_person_dict.o like that, you can link it in a program, as long as you also link - after it - the other libraries that define the functions that it calls:

get_person_prog.c

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

extern PyObject * get_details(); // Ought to be put in a header

int main(void)
{
    PyObject * pyobj = get_details();
    if (pyobj) {
        puts("Got the details");
    }
    return  0;
}

Compile that:

$ gcc -I /usr/include/python3.4  -c -o get_person_prog.o get_person_prog.c

Link your object files and libraries, in the right order, to make a program prog:

$ gcc -o prog get_person_prog.o get_person_dict.o `python3.4-config --ldflags`

Run:

$ ./prog
Got the details
like image 129
Mike Kinghan Avatar answered Jul 19 '26 18:07

Mike Kinghan


In debian / jessie

python3.4-config --ldflags

tells what link parameters should be used, which should work on Ubuntu also. The command is in python3.4-dev package.

python3.4-config --libs

Tells the names of the libraries needed when linking.

The output

-L/usr/lib/python3.4/config-3.4m-x86_64-linux-gnu -L/usr/lib -lpython3.4m 
-lpthread -ldl -lutil -lm -Xlinker -export-dynamic 
-Wl,-O1 -Wl,-Bsymbolic-functions`

contains -lpython3.4m i.e not -lpython3.4 as in the question. Using it instead should help with this specific problem.

like image 22
J.J. Hakala Avatar answered Jul 19 '26 17:07

J.J. Hakala



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!