Sunday, June 27, 2021

Simultaneous assembly of Python External C++ procedures returning vector and sum of it's member

 Simultaneous assembly of two Python External C++ procedures returning sum and sequence of factorials of the first n members of the natural series via Python API. You might want to compare code below with another one proposed in Enhancing Python with Custom C Extensions ( calculating the only sum )

Looks like under any circumstances building external Python procedure in C++ has a significant advantage over C. Just setup.py should be configured to run "gcc" properly against C++ code.

(.env) [boris@fedora33server FACTORNEW]$ cat factor.h

#pragma once

#include <vector>

#include <cstddef>

namespace abc

{

std::vector<int> factList(int lim_up) ;

long factorial(int n);

long factorialSum(int m);

}

(.env) [boris@fedora33server FACTORNEW]$ cat factorialProc.cpp

#include <iostream>

#include "factor.h" 

namespace abc {

    std::vector<int>  factList(int lim_up)

    {    

       std::vector<int> result;

       int n;

       for(n=0; n <= lim_up; n++)

        {

           result.push_back(factorial(n));

        }

        return result;

    };

    long factorial(int n)

    {

       if (n == 0)

           return 1;

       else

          return(n * factorial(n-1));

     };

    long factorialSum(int m)

    {

     long rez = 0;

     for(int i=0 ; i<= m ; i++)

      {

       rez += factorial(i);

      }

     return rez;

    };

} // namespace abc

(.env) [boris@fedora33server FACTORNEW]$ cat factorialSigma.cpp

#include <Python.h>

#include "factor.h"

#pragma GCC diagnostic ignored "-Wsign-compare"

extern "C"{}

namespace {

static PyObject *factorsList(PyObject* self, PyObject* args)

{

    int m;

    if(!PyArg_ParseTuple(args,"i",&m))

        return NULL;

    std::vector<int>facts = abc::factList(m);

    PyObject* result = PyList_New(facts.size());

    for(int i = 0; i < facts.size(); i++) {

        PyList_SetItem(result, i, PyLong_FromLong(facts[i]));

    }

    return result;

};

static PyObject *factorsSum(PyObject* self, PyObject* args)

{

    int n;

    long result;

    if(!PyArg_ParseTuple(args, "i", &n))

        return NULL;

    result = abc::factorialSum(n);

    return Py_BuildValue("i",result);

};

// Our Module's Function Definition structure

// We require this `NULL` to signal the end of our method

// definition

static PyMethodDef myMethodsTable[] = {

    { "factorsSum", factorsSum, METH_VARARGS, "Tracking factorial" },

    { "factorsList",factorsList, METH_VARARGS, "Tracking factorial" },

    { NULL, NULL, 0, NULL }

};

// Our Module Definition struct
static struct PyModuleDef myModule = {
    PyModuleDef_HEAD_INIT,
    "myModule",
    "Test Module",
    -1,
    myMethodsTable
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
    return PyModule_Create(&myModule);
};
} //namespace

(.env) [boris@fedora33server FACTORNEW]$ cat setup.py
from distutils.core import setup, Extension
import sysconfig

language = 'c++'
std = 'c++20'
default_compile_args = sysconfig.get_config_var('CFLAGS').split()
extra_compile_args = [f"-std={std}", "-Wall", "-Wextra", "-Werror", "-DNDEBUG", "-O3"]
setup(name = 'myModule', version = '1.0',  \
   ext_modules = [Extension('myModule', ['factorialSigma.cpp','factorialProc.cpp'])])

(.env) [boris@fedora33server FACTORNEW]$ python setup.py install
running install
running build
running build_ext
building 'myModule' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FACTORNEW/.env/include -I/usr/include/python3.9 -c factorialProc.cpp -o build/temp.linux-x86_64-3.9/factorialProc.o
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FACTORNEW/.env/include -I/usr/include/python3.9 -c factorialSigma.cpp -o build/temp.linux-x86_64-3.9/factorialSigma.o
creating build/lib.linux-x86_64-3.9
g++ -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/factorialProc.o build/temp.linux-x86_64-3.9/factorialSigma.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so -> /home/boris/FACTORNEW/.env/lib64/python3.9/site-packages
running install_egg_info
Removing /home/boris/FACTORNEW/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
Writing /home/boris/FACTORNEW/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info

(.env) [boris@fedora33server FACTORNEW]$ cd build
(.env) [boris@fedora33server build]$ ls -CRl
.:
total 0
drwxrwxr-x. 2 boris boris 53 Jun 28 08:04 lib.linux-x86_64-3.9
drwxrwxr-x. 2 boris boris 53 Jun 28 08:04 temp.linux-x86_64-3.9

./lib.linux-x86_64-3.9:
total 96
-rwxrwxr-x. 1 boris boris 97112 Jun 28 08:04 myModule.cpython-39-x86_64-linux-gnu.so

./temp.linux-x86_64-3.9:
total 172
-rw-rw-r--. 1 boris boris 96904 Jun 28 08:04 factorialProc.o
-rw-rw-r--. 1 boris boris 75568 Jun 28 08:04 factorialSigma.o

(.env) [boris@fedora33server FACTORNEW]$ cat MyProg.py
import myModule
a = int(input("Input the upper bound : " ))
print(myModule.factorsList(a))
print(myModule.factorsSum(a))





Saturday, June 26, 2021

Building Fibonacci sequence via Python C++ Extensions on Fedora Linux 34

 Building  Fibonacci sequence is supposed to be performed by C++ code below as a procedure invoked from Python via Python API. 


Vectors are part of STL. Vectors in C++ are sequence containers representing arrays that can change their size during runtime . They use contiguous storage locations for their elements just as efficiently as in arrays, which means that their elements can also be accessed using offsets on regular pointers to its elements.

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos.h

#pragma once
#include <vector>
#include <cstddef>

namespace xps {

std::vector<int> fibosList(int lim_up) ;

}  // namespace xps

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos.cpp
#include <iostream>
#include <vector>
#include "fibos.h"

namespace xps {

int cpp_fib(int n)
{
    if (n < 2)
        return n;
    else
        return cpp_fib(n-1)+cpp_fib(n-2);
}

std::vector<int>  fibosList(int lim_up)
{    
    std::vector<int> result;
    int n;
    for(n=0; n <= lim_up; n++)
    {
           result.push_back(cpp_fib(n));
    }
    return result;
 }
} //namespace

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos_wrapper.cpp
#include <Python.h>
#include <iostream>
#include <vector>
#include "fibos.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

// Our Python binding to our C function
extern "C"{}

namespace {

static PyObject *fibos(PyObject* self, PyObject* args)
{
    int m;
    if(!PyArg_ParseTuple(args,"i",&m))
        return NULL;

    std::vector<int>fibos = xps::fibosList(m);
    PyObject* result = PyList_New(fibos.size());
    for(int i = 0; i < fibos.size(); i++) {
        PyList_SetItem(result, i, PyLong_FromLong(fibos[i]));
    }
    return result;
}

// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
    { "fibos", fibos, METH_VARARGS, "Calculate prime numbers" },
    { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef myModule = {
    PyModuleDef_HEAD_INIT,
    "myModule",
    "Test Module",
    -1,
    myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
    return PyModule_Create(&myModule);
};
} // namespace
(.env) [boris@fedora33server FIBOPLUS]$ cat setup.py
from distutils.core import setup, Extension
import sysconfig

language = 'c++'
std = 'c++20'
default_compile_args = sysconfig.get_config_var('CFLAGS').split()
extra_compile_args = [f"-std={std}", "-Wall", "-Wextra", "-Werror", "-DNDEBUG", "-O3"]
setup(name = 'myModule', version = '1.0',  \
   ext_modules = [Extension('myModule', ['fibos_wrapper.cpp','fibos.cpp'])])
   
(.env) [boris@fedora33server FIBOPLUS]$ python setup.py install
running install
running build
running build_ext
building 'myModule' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FIBOPLUS/.env/include -I/usr/include/python3.9 -c fibos.cpp -o build/temp.linux-x86_64-3.9/fibos.o
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FIBOPLUS/.env/include -I/usr/include/python3.9 -c fibos_wrapper.cpp -o build/temp.linux-x86_64-3.9/fibos_wrapper.o
creating build/lib.linux-x86_64-3.9
g++ -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/fibos.o build/temp.linux-x86_64-3.9/fibos_wrapper.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so -> /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages
running install_egg_info
Removing /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
Writing /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info

(.env) [boris@fedora33server FIBOPLUS]$ ll
total 24
drwxrwxr-x. 4 boris boris   63 Jun 26 18:41 build
-rw-rw-r--. 1 boris boris  394 Jun 26 18:34 fibos.cpp
-rw-rw-r--. 1 boris boris  131 Jun 26 18:28 fibos.h
-rw-rw-r--. 1 boris boris 1215 Jun 26 18:37 fibos_wrapper.cpp
-rw-rw-r--. 1 boris boris   84 Jun 26 18:06 MyProgList.py
-rw-rw-r--. 1 boris boris  280 Jun 26 17:43 MyProg.py
-rw-rw-r--. 1 boris boris  368 Jun 26 18:31 setup.py

(.env) [boris@fedora33server FIBOPLUS]$ cat MyProgList.py
import myModule

a = int(input("\nInput upper limit : "))
print(myModule.fibos(a))

(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 11
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 13
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 15
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 17
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]






















Thursday, June 24, 2021

Create Basic Python 3.10(beta) C++ Extensions on Fedora Linux 34

 Detecting all prime numbers in given range is supposed to be performed by C++ code below as a procedure invoked from Python.  Tested with both Python 3.9.5 and Python 3.10 (beta)  via Python API.  Refactoring code proposed in python-cpp-extension @github


Vectors are part of STL. Vectors in C++ are sequence containers representing arrays that can change their size during runtime . They use contiguous storage locations for their elements just as efficiently as in arrays, which means that their elements can also be accessed using offsets on regular pointers to its elements.

Procedure primesList(int lim_down,int lim_up) has type of std::vector<int> and accept 2 parameters rather then 1 in original version. Logic itself of primesList is different from the one implemented in "sieve_of_eratosthenes" in original code.

(.env) [boris@sever33fedora PRIMESPLUS]$ cat test.h   
#pragma once
#include <vector>
#include <cstddef>

namespace xps {

std::vector<int> primesList(int lim_down,int lim_up) ;

}  // namespace xps

(.env) [boris@sever33fedora PRIMESPLUS]$ cat test.cpp
#include <Python.h>
#include <iostream>
#include <vector>
#include "test.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

namespace xps {

std::vector<int>  primesList(int lim_down,int lim_up)
{     
   std::vector<int> result;
   int i,prime,n;
   for(n=lim_down; n <= lim_up; n++)
   {
       prime = 1;
       for(i=2; i<n; i++)
           if(n%i == 0)
           {
               prime = 0;
               break;
           }
       if(prime)
       {
          result.push_back(n);
       }
   }
   return result;
 }
} //namespace

// Our Python binding to our C function
// This will take two non-keyword arguments

extern "C"{}
namespace {


static PyObject *primes(PyObject* self, PyObject* args)
{
   // PyArg_ParseTuple accepts two integer arguments
   // to obtain all prime numbers between "k" and "m"

   int m,k;
   if(!PyArg_ParseTuple(args,"ii",&k,&m))
       return NULL;

   std::vector<int> primes = xps::primesList(k,m);
   PyObject* result = PyList_New(primes.size());
   for(int i = 0; i < primes.size(); i++) {
       PyList_SetItem(result, i, PyLong_FromLong(primes[i]));
   }
   return result;
}

// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
   { "primes", primes, METH_VARARGS, "Calculate prime numbers" },
   { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef myModule = {
   PyModuleDef_HEAD_INIT,
   "myModule",
   "Test Module",
   -1,
   myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
   return PyModule_Create(&myModule);
};
} // namespace

(.env) [boris@sever33fedora PRIMESPLUS]$ cat setup.py
from distutils.core import setup, Extension
import sysconfig

language = 'c++'
std = 'c++20'
default_compile_args = sysconfig.get_config_var('CFLAGS').split()
extra_compile_args = [f"-std={std}", "-Wall", "-Wextra", "-Werror", "-DNDEBUG", "-O3"]

setup(name = 'myModule', version = '1.0',  \
  ext_modules = [Extension('myModule', ['test.cpp'])])

(.env) [boris@sever33fedora PRIMESPLUS]$ python3.10 setup.py install

(.env) [boris@sever33fedora PRIMESPLUS]$ ll
total 20
drwxrwxr-x. 4 boris boris   63 Jun 25 01:19 build
-rw-rw-r--. 1 boris boris  144 Jun 25 00:06 MyProgList.py
-rw-rw-r--. 1 boris boris  280 Jun 24 22:26 MyProg.py
-rw-rw-r--. 1 boris boris  348 Jun 24 21:32 setup.py
-rw-rw-r--. 1 boris boris 1690 Jun 25 01:17 test.cpp
-rw-rw-r--. 1 boris boris  145 Jun 25 01:14 test.h


(.env) [boris@sever33fedora PRIMESPLUS]$ cat MyProgList.py    
import myModule
b = int(input("\nInput down limit :"))
a = int(input("\nInput upper limit : "))
print(myModule.primes(b,a))

(.env) [boris@sever33fedora PRIMESPLUS]$ python3.10 MyProgList.py

Input down limit :100

Input upper limit : 500  
[101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191
, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 28
3, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 4
01, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]











































Create Basic Python C++ Extensions on Fedora Linux 34

Building  Fibonacci sequence is supposed to be performed by C++ code below as a procedure invoked from Python via Python API. 

Vectors are part of STL. Vectors in C++ are sequence containers representing arrays that can change their size during runtime . They use contiguous storage locations for their elements just as efficiently as in arrays, which means that their elements can also be accessed using offsets on regular pointers to its elements.

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos.h

#pragma once
#include <vector>
#include <cstddef>

namespace xps {

std::vector<int> fibosList(int lim_up) ;

}  // namespace xps

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos.cpp
#include <iostream>
#include <vector>
#include "fibos.h"

namespace xps {

int cpp_fib(int n)
{
    if (n < 2)
        return n;
    else
        return cpp_fib(n-1)+cpp_fib(n-2);
}

std::vector<int>  fibosList(int lim_up)
{    
    std::vector<int> result;
    int n;
    for(n=0; n <= lim_up; n++)
    {
           result.push_back(cpp_fib(n));
    }
    return result;
 }
} //namespace

(.env) [boris@fedora33server FIBOPLUS]$ cat fibos_wrapper.cpp
#include <Python.h>
#include <iostream>
#include <vector>
#include "fibos.h"
#pragma GCC diagnostic ignored "-Wsign-compare"

// Our Python binding to our C function
extern "C"{}

namespace {

static PyObject *fibos(PyObject* self, PyObject* args)
{
    int m;
    if(!PyArg_ParseTuple(args,"i",&m))
        return NULL;

    std::vector<int>fibos = xps::fibosList(m);
    PyObject* result = PyList_New(fibos.size());
    for(int i = 0; i < fibos.size(); i++) {
        PyList_SetItem(result, i, PyLong_FromLong(fibos[i]));
    }
    return result;
}

// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
    { "fibos", fibos, METH_VARARGS, "Calculate prime numbers" },
    { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef myModule = {
    PyModuleDef_HEAD_INIT,
    "myModule",
    "Test Module",
    -1,
    myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
    return PyModule_Create(&myModule);
};
} // namespace
(.env) [boris@fedora33server FIBOPLUS]$ cat setup.py
from distutils.core import setup, Extension
import sysconfig

language = 'c++'
std = 'c++17'
default_compile_args = sysconfig.get_config_var('CFLAGS').split()
extra_compile_args = [f"-std={std}", "-Wall", "-Wextra", "-Werror", "-DNDEBUG", "-O3"]
setup(name = 'myModule', version = '1.0',  \
   ext_modules = [Extension('myModule', ['fibos_wrapper.cpp','fibos.cpp'])])
   
(.env) [boris@fedora33server FIBOPLUS]$ python setup.py install
running install
running build
running build_ext
building 'myModule' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FIBOPLUS/.env/include -I/usr/include/python3.9 -c fibos.cpp -o build/temp.linux-x86_64-3.9/fibos.o
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FIBOPLUS/.env/include -I/usr/include/python3.9 -c fibos_wrapper.cpp -o build/temp.linux-x86_64-3.9/fibos_wrapper.o
creating build/lib.linux-x86_64-3.9
g++ -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/fibos.o build/temp.linux-x86_64-3.9/fibos_wrapper.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so -> /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages
running install_egg_info
Removing /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
Writing /home/boris/FIBOPLUS/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info

(.env) [boris@fedora33server FIBOPLUS]$ ll
total 24
drwxrwxr-x. 4 boris boris   63 Jun 26 18:41 build
-rw-rw-r--. 1 boris boris  394 Jun 26 18:34 fibos.cpp
-rw-rw-r--. 1 boris boris  131 Jun 26 18:28 fibos.h
-rw-rw-r--. 1 boris boris 1215 Jun 26 18:37 fibos_wrapper.cpp
-rw-rw-r--. 1 boris boris   84 Jun 26 18:06 MyProgList.py
-rw-rw-r--. 1 boris boris  280 Jun 26 17:43 MyProg.py
-rw-rw-r--. 1 boris boris  368 Jun 26 18:31 setup.py
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 11
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 13
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 15
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
(.env) [boris@fedora33server FIBOPLUS]$ python MyProgList.py

Input upper limit : 17
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]































Monday, June 21, 2021

Working on Basic Python C Extensions on Fedora Linux 34 (2)

 Relatively complicated sample based on

with  minor refactoring just to make things clear 


(.env) [boris@sever33fedora enhancePython]$ cat demo.h
unsigned long cfactorial_sum(char num_chars[]);
unsigned long ifactorial_sum(long nums[], int size);
unsigned long factorial(long n);

(.env) [boris@sever33fedora enhancePython]$ cat demolib.c
#include <stdio.h>
#include "demo.h"


unsigned long cfactorial_sum(char num_chars[]) {
    unsigned long fact_num;
    unsigned long sum = 0;

    for (int i = 0; num_chars[i]; i++) {
        int ith_num = num_chars[i] - '0';
        fact_num = factorial(ith_num);
        sum = sum + fact_num;
    }
    return sum;
}

unsigned long ifactorial_sum(long nums[], int size) {
    unsigned long fact_num;
    unsigned long sum = 0;
    for (int i = 0; i < size; i++) {
        fact_num = factorial(nums[i]);
        sum += fact_num;
    }
    return sum;
}

unsigned long factorial(long n) {
    if (n == 0)
        return 1;
    return (unsigned)n * factorial(n-1);
}

(.env) [boris@sever33fedora enhancePython]$ cat demo.c   
#include <Python.h>
#include <stdio.h>
#include "demo.h"
/*
Just to suppress warnings, which don't affect runtime phase
*/
#pragma GCC diagnostic ignored   "-Wincompatible-pointer-types"


// wrapper function for cfactorial_sum
static PyObject *DemoLib_cFactorialSum(PyObject *self, PyObject *args) {
    char *char_nums;
    if (!PyArg_ParseTuple(args, "s", &char_nums)) {
        return NULL;
    }

    unsigned long fact_sum;
    fact_sum = cfactorial_sum(char_nums);

    return Py_BuildValue("i", fact_sum);
}

// wrapper function for ifactorial_sum
static PyObject *DemoLib_iFactorialSum(PyObject *self, PyObject *args) {

/* 
  I believe this declaration is a cause of several
   "-Wincompatible-pointer-types" warnings,
   which are easy to see commenting #pragma GCC
   directive out
*/
    
    PyObject *lst; 

    if (!PyArg_ParseTuple(args, "O", &lst)) {
        return NULL;
    }

    int n = PyObject_Length(lst);
    if (n < 0) {
        return NULL;
    }

    long nums[n];
    for (int i = 0; i < n; i++) {
        PyLongObject *item = PyList_GetItem(lst, i);
        /* long num = PyLong_AsLong(item); */

        nums[i] = PyLong_AsLong(item);
    }

    unsigned long fact_sum;
    fact_sum = ifactorial_sum(nums, n);

    return Py_BuildValue("i", fact_sum);
}

// module's function table
static PyMethodDef DemoLib_FunctionsTable[] = {
    {
        "sfactorial_sum", // name exposed to Python
        DemoLib_cFactorialSum, // C wrapper function
        METH_VARARGS, // received variable args (but really just 1)
        "Calculates factorial sum from digits in string of numbers" // documentation
    }, {
        "ifactorial_sum", // name exposed to Python
        DemoLib_iFactorialSum, // C wrapper function
        METH_VARARGS, // received variable args (but really just 1)
        "Calculates factorial sum from list of ints" // documentation
    }, {
        NULL, NULL, 0, NULL
    }
};

// modules definition
static struct PyModuleDef DemoLib_Module = {
    PyModuleDef_HEAD_INIT,
    "demo",     // name of module exposed to Python
    "Demo Python wrapper for custom C extension library.", // module documentation
    -1,
    DemoLib_FunctionsTable
};

PyMODINIT_FUNC PyInit_demo(void) {
    return PyModule_Create(&DemoLib_Module);
}

(.env) [boris@sever33fedora enhancePython]$ cat setup.py
from setuptools import Extension, setup

module = Extension("demo",
                  sources=[
                    'demo.c',
                    'demolib.c'
                  ])
setup(name='demo',
     version='1.0',
     description='Python wrapper for custom C extension',
     ext_modules=[module])

(.env) [boris@sever33fedora enhancePython]$ cat MyProg.py    
import demo
print("Calling sfactorial_sum(\"1234567\") gives \n",demo.sfactorial_sum("1234567"))
print("Calling ifactorial_sum([1,2,3,4,5,6,7]) gives \n",\
       demo.ifactorial_sum([1,2,3,4,5,6,7]))

     
(.env) [boris@sever33fedora enhancePython]$ python setup.py
 install

running install
running bdist_egg
running egg_info
creating demo.egg-info
writing demo.egg-info/PKG-INFO
writing dependency_links to demo.egg-info/dependency_links.txt
writing top-level names to demo.egg-info/top_level.txt
writing manifest file 'demo.egg-info/SOURCES.txt'
reading manifest file 'demo.egg-info/SOURCES.txt'
writing manifest file 'demo.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_ext
building 'demo' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/enhancePython/.env/include -I/usr/include/python3.9 -c demo.c -o build/temp.linux-x86_64-3.9/demo.o
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/enhancePython/.env/include -I/usr/include/python3.9 -c demolib.c -o build/temp.linux-x86_64-3.9/demolib.o
creating build/lib.linux-x86_64-3.9
gcc -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/demo.o build/temp.linux-x86_64-3.9/demolib.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/demo.cpython-39-x86_64-linux-gnu.so
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
copying build/lib.linux-x86_64-3.9/demo.cpython-39-x86_64-linux-gnu.so -> build/bdist.linux-x86_64/egg
creating stub loader for demo.cpython-39-x86_64-linux-gnu.so
byte-compiling build/bdist.linux-x86_64/egg/demo.py to demo.cpython-39.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying demo.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying demo.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying demo.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying demo.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt
zip_safe flag not set; analyzing archive contents...
__pycache__.demo.cpython-39: module references __file__
creating dist
creating 'dist/demo-1.0-py3.9-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing demo-1.0-py3.9-linux-x86_64.egg
removing '/home/boris/enhancePython/.env/lib/python3.9/site-packages/demo-1.0-py3.9-linux-x86_64.egg' (and everything under it)
creating /home/boris/enhancePython/.env/lib/python3.9/site-packages/demo-1.0-py3.9-linux-x86_64.egg
Extracting demo-1.0-py3.9-linux-x86_64.egg to /home/boris/enhancePython/.env/lib/python3.9/site-packages
demo 1.0 is already the active version in easy-install.pth

Installed /home/boris/enhancePython/.env/lib/python3.9/site-packages/demo-1.0-py3.9-linux-x86_64.egg
Processing dependencies for demo==1.0
Finished processing dependencies for demo==1.0

(.env) [boris@sever33fedora enhancePython]$ python MyProg.py
Calling sfactorial_sum("1234567") gives 
 5913
Calling ifactorial_sum([1,2,3,4,5,6,7]) gives 
 5913