How to solve the 'Segmentation fault' when hybrid programming of C & Python? - python

Under my Ubuntu:
$ cat test.py
#Filename test.py
def Hello():
print "Hello, world!"
$ cat tom.cpp
#include <Python.h>
int main()
{
Py_Initialize();
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
pModule = PyImport_ImportModule("test");
pFunc = PyObject_GetAttrString(pModule, "Hello");
PyEval_CallObject(pFunc, NULL);
Py_Finalize();
return 0;
}
And then compile it:
g++ tom.cpp -I/usr/include/python2.7 -L/usr/lib/python2.7 -lpython2.7
Run:
$ ./a.out
Segmentation fault
Why?
Could anyone help?
Thanks!
BR,
Tom

The previous poster is probably right, so my comment is more "generic"...but in C/C++, you should NEVER accept a pointer back from a function without confirming it's not NULL before attempting to de-refence it. The above code should more rightly be:
pModule = PyImport_ImportModule("test");
if (pModule == NULL) {
printf("ERROR importing module");
exit(-1);
}
pFunc = PyObject_GetAttrString(pModule, "Hello");
if (pFunc == NULL) {
printf("ERROR getting Hello attribute");
exit(-1);
}
PyEval_CallObject(pFunc, NULL);

The issue is caused by PyObject_GetAttrString returning NULL. I have also added the directory path using PyRun_SimpleString as my dev dir was not under python path
#include <Python.h>
int main() {
Py_Initialize();
PyRun_SimpleString("import sys; sys.path.insert(0, 'add the directory path here')");
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
pModule = PyImport_ImportModule("test");
pFunc = PyObject_GetAttrString(pModule, "Hello");
if (pFunc != NULL) {
PyEval_CallObject(pFunc, NULL);
Py_Finalize();
}
else {
printf("pFunc returned NULL\n");
}
return 0;
}

Related

Embedding Python in C++ from anaconda, getting error

Trying to compile this a.cpp file, using
g++ a.cpp -I ~/anaconda3/include/python3.7m/ -l ~/anaconda3/lib/python3.7/
Error I am getting is
/usr/bin/ld: cannot find -l/home/rverma/anaconda3/lib/python3.7/
collect2: error: ld returned 1 exit status
Tried g++ a.cpp -I ~/anaconda3/include/python3.7m/ -l ~/anaconda3/lib/ this as well for giving
/usr/bin/ld: cannot find -l/home/rverma/anaconda3/lib/ collect2: error: ld returned 1 exit status
Where my a.cpp file looks like this:
#include <Python.h>
#include <stdlib.h>
int main()
{
// Set PYTHONPATH TO working directory
setenv("PYTHONPATH",".",1);
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyUnicode_FromString((char*)"arbName");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");
if (PyCallable_Check(pFunc))
{
pValue=Py_BuildValue("(z)",(char*)"something");
PyErr_Print();
printf("Let's give this a shot!\n");
presult=PyObject_CallObject(pFunc,pValue);
PyErr_Print();
} else
{
PyErr_Print();
}
printf("Result is %ld\n",PyLong_AsLong(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
And my argName.py looks like this:
def someFunction(text):
print 'You passed this Python program '+text+' from C! Congratulations!'
return 12345
Please help

Python SWIG wrapper for C++ rvalue std::string &&

I'm trying to build a python wrapper for gnucash c++ parts. In QofBackend I encountered the method const std::string && get_message (). In python this message returns <Swig Object of type 'std::string *' at 0x7f4a20f5c9f0> instead of a string as in my setting as there is no swig typemap for std::string rvalue reference.
I didn't really find a simple explanation so I rebuilt an example setting and dug into c++ which I barely know. I managed to get the string into python but I'd like to know
if this typemap(out) approach is correct (also in respect of memory and error handling).
The conversion in set_s_workaround() is also just a workaround. I don't think that for gnucash the python code ever needs to set this value but for completeness sake it would be nice to also have a typemap(in) std::string&& and
get rid of get_s_workaround
get init_s_2 working.
/* example.hpp */
#include <string>
using namespace std;
struct struct1{
string s;
const std::string&& get_s();
void set_s(string&&);
void set_s_workaround(string);
void init_s();
void init_s_2();
void print_s();
};
string conv_rvalue_string(string);
/* example.cpp */
#include<iostream>
#include"example.hpp"
using namespace std;
void
struct1::set_s (std::string&& msg)
{
s = msg;
}
std::string
conv_rvalue_string (std::string msg)
{
return msg;
}
void
struct1::set_s_workaround(std::string msg)
{
set_s ( conv_rvalue_string(msg) );
}
void
struct1::init_s ()
{
set_s("Some content");
}
void
struct1::init_s_2()
{
std::string msg {"Couldn't find "};
/* set_s( msg ); */
}
void
struct1::print_s ()
{
cout<<get_s()<<endl;
}
const std::string&&
struct1::get_s ()
{
return std::move(s);
}
/* example.i */
%module example
%include "std_string.i"
%typemap(out) std::string&& {
std::string s = *$1;
$result = SWIG_From_std_string(s);
}
%{
#include <string>
#include "example.hpp"
%}
%include "example.hpp"
#!/bin/bash
swig3.0 -c++ -shadow -python example.i
g++ -fpic -c example.hpp example.cpp example_wrap.cxx -I/usr/include/python3.7
g++ -shared example_wrap.o example.o -o _example.so
# pyexample.py
import example
s1 = example.struct1()
s1.set_s_workaround('TEST')
s1.print_s()
print(s1.get_s())
Thanks for the help!
This std::string && typemap uses a temporary std::string that is passed to the method that takes a std::string rvalue reference.
The fragment dependecies in the %typemap ensure that the used fragments are ready in the wrapper file. We simply use the fragments that are already provided by "std_string.i".
/* example.i */
%module example
%include "std_string.i"
%typemap(out, fragment="SWIG_From_std_string") std::string&& {
$result = SWIG_From_std_string(*$1);
}
%typemap(in, fragment="SWIG_AsVal_std_string") std::string&& (std::string temp) {
int res = SWIG_AsVal_std_string($input, &temp);
$1 = &temp;
}
%{
#include <string>
#include "example.hpp"
%}
%include "example.hpp"
init_s2() would work like this:
void
struct1::init_s_2()
{
std::string msg {"Couldn't find "};
set_s( msg + "");
}
credits to S. Holtermann!
%typemap(out) std::string&& {
std::string s = *$1;
$result = SWIG_From_std_string(s);
}
can be shortened to
%typemap(out) std::string&& {
$result = SWIG_From_std_string(*$1);
}
without creating a local var (credits to S. Holtermann!)
A possible typemap(in) could be
%typemap(in) std::string && (std::string *temp){
int res = SWIG_AsPtr_std_string($input, &temp);
$1 = temp;
}
works
hasn't been tested extensively
does it cause memory leaks?

Embedding python in a c program with all dependencies included

I am writing a c application that will let me embed python modules in it. The python modules are responsible for initiating remote procedure calls to python code on remote machine through rpyc library. My python modules will be located in the same place where the application will run from. I am assuming that my c application will run on a machine that does not have the needed python libraries e.g rpyc. I wanted to know if there is a way I can bundle all the dependencies together with my modules when I ship the code for distribution.
I have used cython to compile the python module to .pyd but still this needs the required python libraries installed.
My c code;
int main(){
int argc = 2;
wchar_t* argv[] = { (wchar_t *)"mypythonmodule", (wchar_t *)"-h", NULL };
const char *module = argv[0];
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(module);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pArgs = PyTuple_New(argc);
for (int i = 0; i < argc; i++) {
pValue = PyUnicode_FromString(argv[i]);
PyTuple_SetItem(pArgs, i, pValue);
}
pFunc = PyObject_GetAttrString(pModule, "parse_args");
PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pFunc);
Py_DECREF(pArgs);
//Py_DECREF(pValue);
Py_Finalize();
}
}

Undeclared identifier: PyUnicode_DecodeFSDefault

I try to compile the example code from Python website https://docs.python.org/3/extending/embedding.html. Everything works fine except the following line:
pName = PyUnicode_DecodeFSDefault(argv[1]);
I have Python 3.6 installed on my MacOS El Captain. My make file looks like the following:
call_function: call_function.o
gcc -o call_function call_function.o -export-dynamic -L/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/config-3.6m-darwin -lpython3.6m -lpthread -lm -ldl -lutil
call_function.o:call_function.cpp
gcc -c call_function.cpp -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m
When I compile the C++ code, I get the following error:
gcc -c call_function.cpp -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m
call_function.cpp:16:13: error: use of undeclared identifier 'PyUnicode_DecodeFSDefault'
pName = PyUnicode_DecodeFSDefault(argv[1]);
^
1 error generated.
Does anyone know how to fix the above error? I would greatly appreciated for your help.
Here is the complete example code:
#include <Python/Python.h>
#include <Python/unicodeobject.h>
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
// pName = PyUnicode_FromString(argv[1]); <-- also gives me an error
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyLong_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
I figure out what the problem is. The include <Python/Python.h> statement is actually linked to /System/Library/Frameworks/Python.framework/Versions/Current which currently is Python2.7. I have installed Python 3.6 on my Mac and even I include /Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m in my make file, it's still referred to the Python.h file in MacOS's Python 2.7 folder. I tried to change the symbolic link of the Current to the new 3.6 folder and it's not letting me make the changes. Does anybody know how to change the symbolic link of the Python2.7 current folder so my gcc would look into the Python 3.6 folder for Python.h instead?
It is been a long time since this question got posted, but the solution that I came up is as follows,
char * full_cls_name = argv[1];
Py_Initialize();
pName = PyString_FromString(full_cls_name);
You should also check whether argv[1] exists or not?
This is what worked for me.
gcc -o call $(python3-config --cflags --embed) multiply_embed.c $(python3-config --ldflags --embed)
I got the answer from this post - answer by Ciro Santilli Путлер.
I also got module not found error when running the code, which was overcome by setting the PYTHONPATH variable in the zshrc file as described here.

Calling a Python function from C++

I am trying to make a call to a python module function from my cpp file.
The call i have made is as follows:
#include <iostream>
#include "Python.h"
int
main(int argc, char** argv)
{
Py_Initialize();
PyObject *pName = PyString_FromString("tmpPyth");
PyObject *pModule = PyImport_Import(pName);
std::cout<< "Works fine till here";
PyObject *pDict = PyModule_GetDict(pModule);
if (pModule != NULL) {
PyObject *pFunc = PyObject_GetAttrString(pDict, "pyFunc");
if(pFunc != NULL){
PyObject_CallObject(pFunc, NULL);
}
}
else
std::cout << "Python Module not found";
return 0;
}
My python module is defined as follows:
import numpy
import scipy
import matplotlib
from scipy import stats
def blah():
baseline = [9.74219, 10.2226, 8.7469, 8.69791, 9.96442, 9.96472, 9.37913, 9.75004]
follow_up = [9.94227,9.46763,8.53081,9.43679,9.97695,10.4285,10.159,8.86134]
paired_sample = stats.ttest_rel(baseline , follow_up )
print "The t-statistic is %.3f and the p-value is %.3f." % paired_sample
The code in the cpp file runs fine till the 1st "std::cout" but then ends up giving me a "seg fault". Running the python code separately works fine and gives the desired output.
I cant figure out what is going wrong. Any help will be appreciated.
(Note the program is compiling correctly and running correctly till the 1st "cout")
So there are a couple of things that you were not doing right. See the comments inline. Assuming that both your CPP file and Python file lives at the following path: /home/shanil/project.
test.cpp:
#include <iostream>
#include "Python.h"
int
main(int argc, char** argv)
{
Py_Initialize();
// First set in path where to find your custom python module.
// You have to tell the path otherwise the next line will try to load
// your module from the path where Python's system modules/packages are
// found.
PyObject* sysPath = PySys_GetObject("path");
PyList_Append(sysPath, PyString_FromString("/home/shanil/project"));
// Load the module
PyObject *pName = PyString_FromString("my_mod");
PyObject *pModule = PyImport_Import(pName);
// Random use-less check
std::cout<< "Works fine till here\n";
if (pModule != NULL) {
std::cout << "Python module found\n";
// Load all module level attributes as a dictionary
PyObject *pDict = PyModule_GetDict(pModule);
// Remember that you are loading the module as a dictionary, the lookup you were
// doing on pDict would fail as you were trying to find something as an attribute
// which existed as a key in the dictionary
PyObject *pFunc = PyDict_GetItem(pDict, PyString_FromString("my_func"));
if(pFunc != NULL){
PyObject_CallObject(pFunc, NULL);
} else {
std::cout << "Couldn't find func\n";
}
}
else
std::cout << "Python Module not found\n";
return 0;
}
my_mod.py:
def my_func():
print 'got called'

Categories