Search code examples
python-2.7python-c-extension

Python extension not loading my shared library


I want to create a python extension for my shared library. I am able to build and install it using distutils. However when I import the module I get 'undefined symbol' error.

Say my shared library 'libhello.so' contains one function.

#include <stdio.h>
void hello(void) {
  printf("Hello world\n");
}
g++ -fPIC hello.c -shared -o libhello.so
$ file libhello.so
  libhello.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

This is my setup.py

#!/usr/bin/env python

from distutils.core import setup, Extension

vendor_lib = '/home/sanjeev/trial1/vendor'

module1 = Extension("hello",
                    sources = ["hellomodule.c"],
                    include_dirs = [vendor_lib],
                    library_dirs = [vendor_lib],
                    runtime_library_dirs = [vendor_lib],
                    libraries = ['hello'])

setup(name = 'foo',
      version = '1.0',
      description = 'trying to link extern lib',
      ext_modules = [module1])

On running setup

$ python setup.py install --home install
$ cd install/lib/python
$ python
Python 2.7.2 (default, Aug  5 2011, 13:36:11)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.architecture()
('64bit', 'ELF')

>>> import hello
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: ./hello.so: undefined symbol: hello

Solution

  • Your libhello.so was compiled by g++, and you didn't extern "C" your hello function, so it got name mangled.

    Your hello.so extension was presumably compiled by gcc, which emitted a reference to an unmangled symbol.

    Compile hello.c with gcc, or change hello.c to:

    #include <stdio.h>
    
    extern "C" void hello(void);
    
    void hello(void) {
      printf("Hello world\n");
    }
    

    In cases where a function is defined in one compilation unit and called from another, you should put a function prototype in a header file and include it in both compilation units so that they agree on the linkage and signature.

    #ifndef hello_h_included
    #define hello_h_included
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void hello(void);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif // hello_h_included