Tuesday, May 7, 2019

Using shared library written in C in Python

Using shared library written in C in Python 01

Most of embedded system and legacy codes are written in C and C++ language. I wouldn't argue that Java may also have been used, but as a Communications engineer I haven't had much working experience in Java except making few simple programs. One of the attractive feature of Python is the flexibility of language, people can use it to make big applications, use it for scripting, use it for visualization, and now they have even started to use it on an embedded system.
My purpose for calling C library was to simulation and visualization of system written in C. There may be several ways to do this such as using gnuplot, using octave mex etc, but python is easy to learn and I can find more helps.

C code for a simple library

/* This file is the C source code for complex.c */
/* This contains code that operates on complex numbers */

typedef struct cmplx
{
    float real;
    float imag;
} cmplx;

/* function prototypes for complex numbers */
cmplx add (cmplx num1, cmplx num2);
cmplx subtract (cmplx num1, cmplx num2);
cmplx multiply (cmplx num1, cmplx num2);
cmplx divide (cmplx num1, cmplx num2);
float magnitude (cmplx num);
/* function to add integer numbers and return their sum*/ 
int add_int (int num1, int num2);

cmplx add (cmplx num1, cmplx num2)
{
    cmplx num3;
    num3.real = num1.real + num2.real;
    num3.imag = num1.imag + num2.imag;
    return num3;
}

cmplx subtract (cmplx num1, cmplx num2)
{
    cmplx num3;
    num3.real = num1.real - num2.real;
    num3.imag = num1.imag - num2.imag;
    return num3;
}

cmplx multiply (cmplx num1, cmplx num2)
{
    cmplx num3;
    num3.real = (num1.real * num2.real) - (num1.imag * num2.imag);
    num3.imag = (num1.real * num2.imag) + (num1.imag * num2.real);
    return num3;
}

cmplx divide (cmplx num1, cmplx num2)
{
    cmplx num3;
    cmplx num4;
    num4.real = num2.real;
    num4.imag = -num4.imag;
    num3 = multiply(num1, num4);
    num3.real = num3.real / magnitude(num2);
    num3.imag = num3.imag / magnitude(num2);
    return num3;
}

float magnitude (cmplx num)
{
    return ((num.real * num.real) + (num.imag * num.imag));
    //need sqrt but I don't want
}

int add_int(int num1, int num2)
{
    return (num1 + num2);
}

Compiling complex.c as a shared library file

I am currently using gcc compiler to compile the library. I have tested it with mingw compiler also.

gcc -shared -Wl,-soname,complex -o complex.so -fpic complex.c

Using Python to call the library file and it's functions

import ctypes
libc = ctypes.cdll.LoadLibrary('/home/modick/testCodes/complex.so')

print (vars(libc))
# defining structure cmplx in the library
class cmplx(ctypes.Structure):
    _fields_ = [("real_a", ctypes.c_float), ("imag_b", ctypes.c_float)]

cmplx_01 = cmplx (1.0, 2.0)
cmplx_02 = cmplx (6.0, 5.5)

#return type of the function
libc.add.restype = cmplx
libc.subtract.restype = cmplx
libc.multiply.restype = cmplx
libc.divide.restype = cmplx
libc.add_int.restype = ctypes.c_int
cmplx_03 = libc.add(cmplx_01, cmplx_02)
cmplx_04 = libc.subtract(cmplx_01, cmplx_02)
cmplx_05 = libc.multiply(cmplx_01, cmplx_02)
cmplx_06 = libc.divide(cmplx_01, cmplx_02)

print ('cmplx_01 = {}+i{}'.format(cmplx_01.real_a, cmplx_01.imag_b))
print ('cmplx_02 = {}+i{}'.format(cmplx_02.real_a, cmplx_02.imag_b))
print ('cmplx_03 = {}+i{}'.format(cmplx_03.real_a, cmplx_03.imag_b))
print ('cmplx_04 = {}+i{}'.format(cmplx_04.real_a, cmplx_04.imag_b))
print ('cmplx_05 = {}+i{}'.format(cmplx_05.real_a, cmplx_05.imag_b))
print ('cmplx_06 = {}+i{}'.format(cmplx_06.real_a, cmplx_06.imag_b))
print ('11 + 25 = {}'.format(libc.add_int(ctypes.c_int(11), ctypes.c_int(25))))
print ('11 + 25 = {}'.format(libc.add_int(11, 25)))

Desired output

cmplx_01 = 1.0+i2.0
cmplx_02 = 6.0+i5.5
cmplx_03 = 7.0+i7.5
cmplx_04 = -5.0+i-3.5
cmplx_05 = -5.0+i17.5
cmplx_06 = -0.07547169923782349+i0.2641509473323822
11 + 25 = 36
11 + 25 = 36

No comments:

Post a Comment