cpython-2.7gccarchlinux-arm

Exec format error when compiling C file for Python extension


I am trying to extend python using a simple C file. I succeeded in creating my own python module, but I also need the C file itself to compile and run as a standalone executable. I can successfully compile it, but when I try to run it I get the error "cannot execute binary file: Exec format error".

Here is my C source file (hellomodule.c):

#include <Python.h>

void print_hello(const char* name){
    printf("Hello %s!\n", name);
}

//Only used by Python
static PyObject*
say_hello(PyObject* self, PyObject* args)
{
    const char* name;

    if (!PyArg_ParseTuple(args, "s", &name))
        return NULL;

    //printf("Hello %s!\n", name);
    print_hello("World");

    Py_RETURN_NONE;
}

//Only used by Python
static PyMethodDef HelloMethods[] =
{
    {"say_hello", say_hello, METH_VARARGS, "Greet somebody."},
    {NULL, NULL, 0, NULL}
};

//Only used by Python
PyMODINIT_FUNC
inithello(void)
{
    (void) Py_InitModule("hello", HelloMethods);
}

int main(){
    print_hello("World");
}

I can "successfully" compile it without any errors or warnings with the following:

gcc -I /usr/include/python2.7 -c hellomodule.c -o hellomodule

After making the "hellomodule" file executable, I run it and get the error:

-bash: ./hellomodule: cannot execute binary file: Exec format error

Why would this be causing such an error?


Solution

  • You are trying to execute an object file, that is not an executable. To compile your code as a module you need something like

    gcc -Wall -Werror -Wextra -O2 -I/usr/include/python2.7 \
        -shared hellomodule.c -o hellomodule.so -lpython2.7
    

    but to link correctly to everything and add all the possible include directories there is a script called python-config you just need to invoke it like this

    gcc -Wall -Werror -Wextra -O2 `python-config --includes` \
        -shared hellomodule.c -o hellomodule.so `python-config --libs`
    

    and even better, the script providesCFLAGS and LDFLAGS too, so finally

    gcc -Wall -Werror -Wextra -O2 `python-config --cflags` \
        -shared hellomodule.c -o hellomodule.so `python-config --ldflags`
    

    and then, copy the resulting file to /usr/lib/python2.7/site-packages.

    After that, you can load the module in a python script like this

    import hellomodule
    

    Object files are intermediate binary files used ultimately by the linker (ld probably) to produce the final binary. A python module has no main() function and it has to be a runtime loadable shared object which exports some predefined symbols that the python interpreter will use to load the module into the python script/program.

    Note: To correctly do this and not die trying create a Makefile, like this

    CFLAGS = `python-config --cflags` -Wall -Werror # add more if needed
    LDFLAGS = `python-config --ldflags` # add more if needed
    OBJS = hellomodule.o # add more if needed
    
    all: $(OBJS)
        $(CC) $(CFLAGS) $(LDFLAGS) -shared -o modulename.so $(OBJS)
    
    %.o: %.c
        $(CC) -c $(CFLAGS) $<
    

    ensure that you use tabs instead of spaces for indentation, and then run make in the same directory where the Makefile and the source files are.