2

I have made a shared libray in C++ which has multiple code files and want to use the functions in those files in Python. How can I use ctypes to invoke these functions?

I have two code files (with one header file for each of them) which implement simple functions.

foo.cpp         foo.h
palindrome.cpp  palindrome.h

palindrome.h :

extern int isPalindrome(int A);

palindrome.cpp :

int isPalindrome(int A) {
    if (A < 0)
        return 0;
    int rev = 0;
    int num = A;

    while (A != 0){
        rev = rev * 10 + (A % 10);
        A = A / 10;
    }
    if (rev == num)
        return 1;

    return 0;
}

I created the executables using :

g++ -c -Wall -Werror -fpic foo.cpp
g++ -c -Wall -Werror -fpic palindrome.cpp

and used these executables to create a shared libray.

g++ -shared -fpic -o libcalc.so foo.o palindrome.o

Now I want to use the libcalc.so to use the functions defined in different cpp files to create a wrapper module in python. On trying:

import ctypes

_sum = ctypes.CDLL('./libcalc.so')
_sum.isPalindrome.argtypes = (ctypes.c_int)

it gives AttributeError: ./libcalc.so: undefined symbol: isPalindrome

What is the cause of this error and how can I solve it? Is there a way other than ctypes for this purpose?

Ashutosh Kumar
  • 109
  • 1
  • 9
  • If the library exports the functions, the source files where they were defined in, is irrelevant. [\[Python 3.Docs\]: ctypes - A foreign function library for Python](https://docs.python.org/3/library/ctypes.html#module-ctypes) contains all the info you need. – CristiFati Aug 23 '19 at 09:01
  • You should add all relevant info in the question. Check [\[SO\]: How do I ask a good question?](https://stackoverflow.com/help/how-to-ask) or [\[SO\]: How to create a Minimal, Reproducible Example (reprex (mcve))](https://stackoverflow.com/help/mcve) for more asking related details. – CristiFati Aug 23 '19 at 09:28
  • Add the contents of *palindrome.h* and *palindrome.cpp*. Als add the lines used to compile the sources. Better create the lib only out of the 2 file (strip the other ones), in order to have the *mcve* (from my previous comment). – CristiFati Aug 23 '19 at 09:59
  • 1
    I guess you didn't use `extern "C"` so the functions names are mangled. `ctypes` only work with a C interface, not a C++ one. – Neitsa Aug 23 '19 at 10:01
  • 1
    @Ashutosh Kumar You could use shell command `objdump -T libcalc.so | grep -i palindrome` to check whether or not your symbols are C++-mangled. – jpmarinier Aug 23 '19 at 10:12
  • @jpmarinier ```0000000000000965 g DF .text 0000000000000091 Base _Z12isPalindromei``` This is the output. – Ashutosh Kumar Aug 23 '19 at 10:15
  • 1
    @Ashutosh Kumar So it is mangled, as anticipated by Neitsa. You can either use `extern "C"` in your source code, or try your luck with function `_sum._Z12isPalindromei`. I guess the final "i" encodes the return type. – jpmarinier Aug 23 '19 at 10:20
  • Thanks. I got the results on changing the codes from C++ to C. Is there no other way to use a cpp function in python? – Ashutosh Kumar Aug 23 '19 at 10:33
  • @Ashutosh Kumar You might have a look at [SO question 9084111](https://stackoverflow.com/questions/9084111/is-wrapping-c-library-with-ctypes-a-bad-idea). Apparently there is something called [BoostPython](https://wiki.python.org/moin/boost.python/GettingStarted). – jpmarinier Aug 23 '19 at 10:48
  • I think if you compile the files with *gcc* it will also work. For *C* files, check https://stackoverflow.com/questions/47276327/pass-str-as-an-int-array-to-a-python-c-extended-function-extended-using-swig. If you want to use *C++* (although you export a function with *C* like interface), there are other options, one of them is *PyBind*. – CristiFati Aug 23 '19 at 11:05

0 Answers0