Calling a C function with gmp library included from a Python code - python

I am trying to send a string from a function implemented in Python to a function implemented in C, perform some operations using GMP library and return a string to the function implemented in python. Details of code given below:
myModule.c file:
#include<Python.h>
#include<gmp.h>
char* Cnumfunc(char* n)
{
printf("This is the string %s\n",n);
mpz_t p1;
mpz_init(p1);
mpz_set_str(p1,n,10);
gmp_printf("Value of the gmp number is : %Zd \n", p1);
mpz_add_ui(p1,p1,1);//so now p1=11
char retstr[100];//create a buffer of large size
mpz_get_str(retstr,10,p1);
return retstr;//Should return "11"
}
static PyObject* numfunc(PyObject* self, PyObject* args)
{
char* n;
if (!PyArg_ParseTuple(args, "s", &n))
return NULL;
return Py_BuildValue("s", Cnumfunc(n));
}
static PyMethodDef myMethods[] = {
{"numfunc", numfunc, METH_VARARGS, "Calculate the numfunc"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef myModule = {
PyModuleDef_HEAD_INIT,
"myModule", //#name of module.
"numfunc Module",
-1,
myMethods
};
PyMODINIT_FUNC PyInit_myModule(void)
{
return PyModule_Create(&myModule);
}
Now setup.py file:
from distutils.core import setup, Extension
module = Extension('myModule', sources = ['myModule.c'])
setup (name = 'PackageName',
version = '1.0',
description = 'This is a package for myModule',
ext_modules = [module])
And finally the test.py file:
import myModule
a=myModule.numfunc("10")
print(a)
Now I run
python3 setup build
And then I copy the myModule.cpython-38-x86_64-linux-gnu.so file in the build directory to the directory which contains test.py and then do
python3 test.py
This gives the error:
Traceback (most recent call last):
File "test.py", line 1, in <module>
import myModule
ImportError: /home/aghosh/pybind/myModule.cpython-38-x86_64-linux-gnu.so: undefined symbol: __gmpz_set_str
I am really new to this kind of coding involving multiple languages and it will be very helpful if anyone has a solution to this problem

Related

C extension as sub-module for existing python package

I'm trying to add a c extension as a submodule to an existing python package. I've tried following the documentation but most either are focused on a purely C extension package or it doesn't seem to work for me.
Here is what I'm trying to do:
main/
|--> main/
|--> __init__.py
|--> sub/
|--> sub.c
|--> __init__.py
|--> setup.py
Setup.py file has
from setuptools import setup
from setuptools.extension import Extension
extensions = [
Extension(
name="main.sub",
sources=["main/sub/sub.c"])
]
setup(name='main',
version='1.0',
packages=['main'],
ext_modules = extensions,
)
sub.c has
#include <Python.h>
// This is the definition of a method
static PyObject *division(PyObject *self, PyObject *args)
{
long dividend, divisor;
if (!PyArg_ParseTuple(args, "ll", &dividend, &divisor))
{
return NULL;
}
if (0 == divisor)
{
PyErr_Format(PyExc_ZeroDivisionError, "Dividing %d by zero!", dividend);
return NULL;
}
return PyLong_FromLong(dividend / divisor);
}
// Exported methods are collected in a table
PyMethodDef method_table[] = {
{"division", (PyCFunction)division, METH_VARARGS, "Method docstring"},
{NULL, NULL, 0, NULL} // Sentinel value ending the table
};
// A struct contains the definition of a module
PyModuleDef sub_module = {
PyModuleDef_HEAD_INIT,
"main.sub", // Module name
"This is the module docstring",
-1, // Optional size of the module state memory
method_table,
NULL, // Optional slot definitions
NULL, // Optional traversal function
NULL, // Optional clear function
NULL // Optional module deallocation function
};
// The module init function
PyMODINIT_FUNC PyInit_sub(void)
{
return PyModule_Create(&sub_module);
}
I want to be able to do:
import main
main.sub.division(4,2)
but not matter what I do, I can't see division. It's driving me nuts... I've tried a bunch of different variations with no luck.

How can I import so file as a module without using ctype Linux?

File structure under folder /home/cyan/TEMP
test.py
lib
|--libc_test_module.so
c_test_module.cc
CMakeLists.txt
test.py
import sys
sys.path.append("/home/cyan/TEMP/lib")
import c_test_module
c_test_module.cc
#include <Python.h>
int c_test_function(int a) {
return a + 1;
}
static PyObject * _c_test_function(PyObject *self, PyObject *args)
{
int _a;
int res;
if (!PyArg_ParseTuple(args, "i", &_a))
return NULL;
res = c_test_function(_a);
return PyLong_FromLong(res);
}
/* define functions in module */
static PyMethodDef TestMethods[] =
{
{"c_test_function", _c_test_function, METH_VARARGS,
"this is a c_test_function"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef c_test_module = {
PyModuleDef_HEAD_INIT,
"c_test_module", "Some documentation",
-1,
TestMethods
};
PyMODINIT_FUNC PyInit_c_test_module(void) {
PyObject *module;
module = PyModule_Create(&c_test_module);
if(module==NULL) return NULL;
/* IMPORTANT: this must be called */
import_array();
if (PyErr_Occurred()) return NULL;
return module;
}
Error
ModuleNotFoundError: No module named 'c_test_module'
Question
I don't want to use ctype module to import .so file. Instead, I wonder if there is a way to import this file as a module directly.
I created a setup.py file:
from distutils.core import setup, Extension
import numpy
def main():
setup(name="c_test_module",
version="1.0.0",
description="Python interface for the c_test_module C library function",
author="cyan",
author_email="xxx#gmail.com",
ext_modules=[Extension("c_test_module", ["c_test_module.cc"],
include_dirs=[numpy.get_include()])],
)
if __name__ == "__main__":
main()
Now it works to import c_test_module and call the functions.

Can't import C extension file in Python

My extension C function, in pyc.c
#include<Python.h>
static PyObject *add(PyObject* self,PyObject* args) {
int a=9;
int b=10;
int c=a+b;
return Py_BuildValue(c);
//return Py_BuildValue( "s","hiiiii");
}
static char prin_docs[] = "prin( ): Any message you want to put here!!\n";
static PyMethodDef consume_methods[] = {
{"add", (PyCFunction)add,
METH_NOARGS, prin_docs},
{NULL}
};
PyMODINIT_FUNC initadd(void) {
Py_InitModule3(add, consume_methods,
"Extension module example!");
}
My setup file:
from distutils.core import setup, Extension
setup(name='add', version='1.0',
ext_modules=[Extension('add', ['pyc.c'])])
My Python program that uses that C file:
import add
print(add.add());
The above code successfully created a .so object but I can't import in the Python program by executing that. I get the following error:
Traceback (most recent call last):
File "pycall.py", line 1, in <module>
import add
ImportError: No module named add
Did you actually setup.py install your module? If you only built it, it won't be on sys.path.

Custom Python extension - Import error: undefined symbol

Learning how to write a C extension in Python. Running into the following error when executing ptest.py
Traceback (most recent call last):
File "ptest.py", line 1, in <module>
import euler_py as eul
ImportError: /usr/local/lib/python3.6/site-packages/euler_py.cpython-
36m-x86_64-linux-gnu.so: undefined symbol: problem_one
I'm assuming this is some type of linking issue.
setup.py
sources = glob.glob('ext/*.c')
euler = Extension(
'euler_py',
include_dirs=['src'],
sources=sources,
extra_compile_args=['-std=c99']
)
setup(
name='euler_py',
version='0.1',
description='Project Euler Solutions',
ext_modules=[euler]
)
ptest.py
import euler_py as eul
print(eul.problem_one(10))
The underlying functions are in /src and I wrote test.c to test purely in C. My extension is in /ext/euler_py.c shown below
ext/euler_py.c
#include <Python.h>
#include "../src/euler.h"
static char module_docstring[] = "Provides interface to Project Euler problems";
/*
* Function implementations
*/
static PyObject* euler_py_problem_one(PyObject *self, PyObject *args)
{
int max, result;
if (!PyArg_ParseTuple(args, "i", &max))
return NULL;
result = problem_one(max);
return Py_BuildValue("i", result);
}
// END function implementations
// Wire in functions to module
static PyMethodDef module_methods[] = {
{"problem_one", euler_py_problem_one, METH_VARARGS, "Solution to problem 1"},
{NULL, NULL, 0, NULL}
};
// Module definition
static struct PyModuleDef euler_py_module = {
PyModuleDef_HEAD_INIT,
"euler_py",
module_docstring,
-1,
module_methods
};
// Module initialization function
PyMODINIT_FUNC PyInit_euler_py(void)
{
return PyModule_Create(&euler_py_module);
}
Repo is here. I've played around with library_dirs & include_dirs on the Extension() initiation and no luck. Python version 3.6. Need a second look.
EDIT
Repo linked to has changed since original ask. Added linking for other 3 functions in the same manor as previous.
You forget to include all source files:
sources = glob.glob('ext/*.c') + glob.glob('src/*.c')
you could see c extension build detail with setup.py build -fv:
$ python setup.py build -fv
...
clang -bundle -undefined dynamic_lookup build/temp.macosx-10.13-x86_64-3.6/ext/euler_py.o build/temp.macosx-10.13-x86_64-3.6/src/euler.o build/temp.macosx-10.13-x86_64-3.6/src/helpers.o -o build/lib.macosx-10.13-x86_64-3.6/euler_py.cpython-36m-darwin.so
now helpers.o and euler.o properly linked.

Import C++ dll failed in Python

Following document in "Extending and Embedding the Python Interpreter", I created a VC project, and a dll file was successfully created with name "spam_d.dll"
Main code was
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;
if (!PyArg_ParseTuple(args, "s", &command))
return NULL;
sts = system(command);
return Py_BuildValue("i", sts);
}
static PyMethodDef SpamMethods[] = {
{"system", spam_system, METH_VARARGS, "Execute a shell command."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC
initspam(void)
{
(void) Py_InitModule("spam", SpamMethods);
}
Then I typed following command in python:
import spam
[39003 refs]
spam.system("pwd")
/SVN/Python/PCbuild
0
[39005 refs]
It looks working correctly.
But when I rename the dll name from spam_d.pyd to spam.pyd. Python can't find the module.
>>> import spam
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named spam
[39005 refs]
From the first case, it looks python could setup relationship between "import spam" and "spam_d.pyd" correctly.
How did python know "spam" module is "spam_d.pyd", but not "spam.pyd"?
And is there any documents mention it.
The python tries to link against a debug library with suffix _d.pyd, since it's a Debug build. To link aganist spam.pyd, you need a Release build.

Categories