Friday, June 18, 2021

GCC build of shared library to verify calling C-function from Python 3.9.5 module on Fedora 34 Linux (Server Edition)

 1) We are using "ctype" native Python module to load the shared library.

2) The ctype Python module is available starting with Python 2.5. Make sure you have the most recent Python installed on your system


 (.env) [boris@fedora33server CPYTHON]$ cat arithmatic.h
void connect();
int randNum();
int multNum(int a, int b);

(.env) [boris@fedora33server CPYTHON]$ cat arithmatic.c
#include <stdio.h>
#include <stdlib.h>
#include "arithmatic.h"
void connect()
{
   printf("Connected to C extension\n");
}
//return random value in range of 0-100
int randNum()
{
    int nRand = rand() % 100; 
    return nRand;
}
//Multiply two integer numbers and return value
int multNum(int a, int b)
{
    int nMult = a*b;
    return nMult;
}

That is supposed to run in one line, otherwise you have to place
"\" to let gcc know that the rest of line would go after cartridge return

(.env) [boris@fedora33server CPYTHON]$ gcc -shared -o libcalci.so -fPIC arithmatic.c

(.env) [boris@fedora33server CPYTHON]$ ll
total 28
-rw-rw-r--. 1 boris boris   291 Jun 18 19:23 arithmatic.c
-rw-rw-r--. 1 boris boris    57 Jun 18 18:34 arithmatic.h
-rwxrwxr-x. 1 boris boris 16280 Jun 18 19:31 libcalci.so
-rw-rw-r--. 1 boris boris   374 Jun 18 19:21 MyTest.py

(.env) [boris@fedora33server CPYTHON]$ cat  MyTest.py

from ctypes import *
libCalc = CDLL("./libcalci.so")
 
#call C function to check connection
libCalc.connect() 
 
#calling randNum() C function
#it returns random number
varRand = libCalc.randNum()
print ("Random Number:", varRand, type(varRand))
 
#calling multNum() C function
#it returns multiplication of two numbers
varMult = libCalc.multNum(38,27)
print ("Multiplication : ", varMult)


(.env) [boris@fedora33server CPYTHON]$ python  MyTest.py
Connected to C extension
Random Number: 83 <class 'int'>
Multiplication :  1026











A bit more complicated sample

(.env) [boris@fedora33server CDEVPY]$ cat sum.c
int our_function(int num_numbers, int *numbers) {
    int i;
    int sum = 0;
    for (i = 0; i < num_numbers; i++) {
        sum += numbers[i];
    }
    return sum;
}

(.env) [boris@fedora33server CDEVPY]$ gcc -fPIC -shared -o libsum.so sum.c

(.env) [boris@fedora33server CDEVPY]$ ll
total 28
-rwxrwxr-x. 1 boris boris 16160 Jun 18 21:35 libsum.so
-rw-rw-r--. 1 boris boris   107 Jun 18 21:33 MyRun.py
-rw-rw-r--. 1 boris boris   169 Jun 18 21:29 sum.c
-rw-rw-r--. 1 boris boris   345 Jun 18 21:29 sum.py

(.env) [boris@fedora33server CDEVPY]$ cat sum.py
import ctypes

_sum = ctypes.CDLL('./libsum.so')
_sum.our_function.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.c_int))

def our_function(numbers):
    global _sum
    num_numbers = len(numbers)
    array_type = ctypes.c_int * num_numbers
    result = _sum.our_function(ctypes.c_int(num_numbers), array_type(*numbers))
    return int(result)

(.env) [boris@fedora33server CDEVPY]$ cat  MyRun.py
import sum
def main():
    print (sum.our_function([11,2,-3,4,-3,6]))

if __name__=="__main__":
    main()
(.env) [boris@fedora33server CDEVPY]$ python  MyRun.py
17

(.env) [boris@fedora33server CDEVPY]$ ll
total 28
-rwxrwxr-x. 1 boris boris 16160 Jun 18 21:35 libsum.so
-rw-rw-r--. 1 boris boris   107 Jun 18 21:33 MyRun.py
drwxrwxr-x. 2 boris boris    32 Jun 18 21:36 __pycache__
-rw-rw-r--. 1 boris boris   169 Jun 18 21:29 sum.c
-rw-rw-r--. 1 boris boris   345 Jun 18 21:29 sum.py

PyCharm project based ctypes wrapper

Pretty short sample in C++

[boris@fedora33server ]$ ll
total 8
-rw-rw-r--. 1 boris boris 126 Jun 19 08:46 dullmath.cpp
-rw-rw-r--. 1 boris boris  79 Jun 19 08:52 MyProg.py

[boris@fedora33server ]$ cat dullmath.cpp
extern "C" int fibonacci(int n) {
  if (n <= 0) return 0;
  if (n == 1) return 1;
  return fibonacci(n-1) + fibonacci(n-2);
}

[boris@fedora33server]$ g++ -shared  dullmath.cpp -o   libdullmath.so

[boris@fedora33server ]$ ll
total 24
-rw-rw-r--. 1 boris boris   126 Jun 19 08:46 dullmath.cpp
-rwxrwxr-x. 1 boris boris 16176 Jun 19 08:52 libdullmath.so
-rw-rw-r--. 1 boris boris    79 Jun 19 08:52 MyProg.py

[boris@fedora33server]$ cat MyProg.py
import ctypes

lib = ctypes.CDLL(f'./libdullmath.so')
print(lib.fibonacci(11))

[boris@fedora33server ]$ python MyProg.py
89

One more sample

[boris@fedora33server ]$ cat function.c
int myFunction(int num)
{
    if (num == 0)
 
        // if number is 0, do not perform any operation.
        return 0;
    else
        // if number divides by 11, return 1 else return 0
          return (num % 11 == 0 ? 1 : 0) ;
 
}
[boris@fedora33server ]$ gcc -fPIC -shared -o libfun.so function.c
[boris@fedora33server ]$ ll libfun.so
-rwxrwxr-x. 1 boris boris 16168 Jun 19 10:31 libfun.so

[boris@fedora33server ]$ cat MyProg.py

import ctypes
  
test_text = input ("Введите число: ")
test_number = int(test_text)

# libfun loaded to the python file
# using fun.myFunction(),
# C function can be accessed
# but type of argument is the problem.
                        
fun = ctypes.CDLL("./libfun.so")  

# Now whenever argument
# will be passed to the function                                                       
# ctypes will check it.
           
fun.myFunction.argtypes = [ctypes.c_int]
 
returnVale = fun.myFunction(test_number)  
print(returnVale)

[boris@fedora33server ]$ python MyProg.py
Введите число: 121
1
[boris@fedora33server ]$ python MyProg.py
Введите число: 555
0
[boris@fedora33server ]$ python MyProg.py
Введите число: 550
1


REFERENCES

No comments:

Post a Comment