I am writing C extension for python. All I want to do is to take size as input, create an object of that size and return the reference of that created object. My code looks like:
static PyObject *capi_malloc(PyObject *self, PyObject *args)
{
int size;
if (!PyArg_ParseTuple(args, "i", &size))
return NULL;
//Do something to create an object or a character buffer of size `size`
return something
}
How can I do this? I am able to allocate a memory using PyMem_Malloc() but confused about returning a reference of an object.
If all you really want to do is to allocate a raw memory area of size size and return it, (even though it's not really a correctly initialized PyObject type), just do the following:
char *buf = (char *)PyMem_Malloc(size);
return (PyObject *)buf;
Not sure if that's useful in any way but it'll compile and get you a pointer to a raw memory buffer that's been cast as a PyObject pointer.
(This was not in your question but if you really want an honest to goodness PyObject pointer, you'll have to deal with calling something like PyObject_New() function. Docs here: http://docs.python.org/2/c-api/allocation.html )
Creating the previous example using SWIG is much more straight forward. To follow this path you need to get SWIG up and running first. To install it on an Ubuntu system, you might need to run the following commands
$ sudo apt-get install libboost-python-dev
$ sudo apt-get install python-dev
After that create two files.
/hellomodule.c/
#include <stdio.h>
void say_hello(const char* name) {
printf("Hello %s!\n", name);
}
/hello.i/
%module hello
extern void say_hello(const char* name);
Now comes the more difficult part, gluing it all together.
First we need to let SWIG do its work.
swig -python hello.i
This gives us the files hello.py and hello_wrap.c.
The next step is compiling (substitute /usr/include/python2.4/ with the correct path for your setup!).
gcc -fpic -c hellomodule.c hello_wrap.c -I/usr/include/python2.4/
Now linking and we are done!
gcc -shared hellomodule.o hello_wrap.o -o _hello.so
The module is used in the following way.
>>> import hello
>>> hello.say_hello("World")
Hello World!
if you want to use directly into IDE you can use http://cython.org/#about
and still if you want to develop your own, you may browse through source code of cython.
Related
I have a cpp file that compiles fine with g++ by using the shell:
extern "C"{
#include <quadmath.h>
}
inline char* print( const __float128& val)
{
char* buffer = new char[128];
quadmath_snprintf(buffer,128,"%+.34Qe", val);
return buffer;
}
int main(){
__float128 a = 1.0;
print(a);
return 0;
}
However, when I try to compile it via a python scrit, it fails with the following error:
"undefined reference to quadmath_snprintf"
Here the code of the python script:
import commands
import string
import os
(status, output) = commands.getstatusoutput("(g++ test/*.c -O3 -lquadmath -m64)")
Any idea how to solve this? Thanks.
When you open a shell a whole of stuff is silently initialized for you, and most important for your issue, environment variables are set. What you most likely miss is the definition of LIBRARY_PATH, which is the variable used by the linker to look for libraries matching the ones you instruct it to link using the -lNAME flags.
What the linker needs is a list of directories where it will search for files matching libNAME.{a,so}. You can also pass these directories directly using the -L flag, but in general, you should probably try to use a program like CMake, Make or any other build tool.
This will give you access to commands like find_package and target_link_libraries (CMake), to find, respectively add libraries to your build targets, instead of having to maintain your python to compile your stuff.
I'm making an Qt Quick GUI application(for windows), which uses OpenGL and C++ for some computationally intensive stuff. I want to embed python code into the app, for doing some stuff which is comparatively easier in python.
Basically, I just want the c++ code to call a function in a python script and let the script do the job, then store the returned data in a variable(string, or float etc.) for further use. I'm using Qt creator, and I got python3 lib for MinGW compiler. I tried some code, but its looks like python lib is not quite compatible with Qt creator. IS using pyqt for this will be a good idea? What will be the best and easiest way to do this ?
EDIT: This is the basic code I tried, first it gave me an error saying, cannot find pyconfig.h. Then I added an INCUDEPATH to my python34 include directory.
#include "mainwindow.h"
#include <QApplication>
#include <boost/python.hpp>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
using namespace boost::python;
PyObject *pName, *pModule, *pDict, *pFunc, *pValue;
Py_Initialize();
pName = PyString_FromString(argv[1]);
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, argv[2]);
if (PyCallable_Check(pFunc))
{
PyObject_CallObject(pFunc, NULL);
} else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
Py_Finalize();
return a.exec();
}
My .pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TestWidgetApp
TEMPLATE = app
INCLUDEPATH += C:/boost_1_57_0
INCLUDEPATH += C:/Python34/include
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
OTHER_FILES +=
Then the following errors:
C:\Python34\include\object.h:435: error: C2059: syntax error : ';'
C:\Python34\include\object.h:435: error: C2238: unexpected token(s) preceding ';'
C:\Users\Amol\Desktop\TestWidgetApp\main.cpp:19: error: C3861: 'PyString_FromString': identifier not found
The problem here is that Python 3.4 has a struct member called "slots", (file object.h, in the typedef for PyType_Spec), which Qt defines out from under you so that you can say things like:
public slots:
in your code. The solution is to add:
#undef slots
just before you include Python.h, and to redefine it before you include anything that uses "slots" in the way that Qt does:
#undef slots
#include <Python.h>
#define slots
#include "myinclude.h"
#include <QString>
A bit of a hack (because you're depending on a particular definition of slots in Qt), but it should get you going.
I have removed all the Qt code from your example and then I tried to compile it (Qt has nothing to do with your compile error). And it compiles for me. The difference was I used the include files from Python 2.7.
So I did a little search for the string PyString_FromString in the folders: C:\Python33\includes (I noted you use python 3.4 and not 3.3 but I suspect this is a 3.x thing) and C:\Python27\includes.
Results:
Python 3.3
Python 2.7
So, apparently, Python 3.4 is not supported by your BoostPython version.
Python3 has no PyString_FromString function. Python3 str type internally is unicode objects with complex structure.
Use PyUnicode_FromString or PyUnicode_FromStringAndSize for constructing str object from UTF-8 encoded C string (char*).
Move your
#include "boost/python.hpp"
...to be before your other includes and it will resolve your problem.
The actual issue is as Scott Deerwester described in his answer.
So I have a Python program that's finding .txt file directories and then passing those directories as a list(I believe) to my C++ program. The problem I am having is that I am not sure how to pass the list to C++ properly. I have used :
subprocess.call(["path for C++ executable"] + file_list)
where file_list is the [] of txt file directories.
My arguments that my C++ code accepts are:
int main (int argc, string argv[])
Is this correct or should I be using a vector? When I do use this as my argument and try to print out the list I get the directory of my executable, the list, and then smiley faces, symbols, and then the program crashes.
Any suggestions? My main point that I am trying to find out is the proper syntax of utilizing subprocess.call. Any help would be appreciated! thanks!
Another option is to use cython, (not a direct answer). Here is a simple complete example:
Suppose you have the following files:
cython_file.cpp
python_file.py
setup.py
sum_my_vector.cpp
sum_my_vector.h
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension(
name="cython_file",
sources=["cython_file.pyx", "sum_my_vector.cpp"],
extra_compile_args=["-std=c++11"],
language="c++",
)]
setup(
name = 'cython_file',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
)
cython_file.pyx
from libcpp.vector cimport vector
cdef extern from "sum_my_vector.h":
int sum_my_vector(vector[int] my_vector)
def sum_my_vector_cpp(my_list):
cdef vector[int] my_vector = my_list
return sum_my_vector(my_vector)
sum_my_vector.cpp
#include <iostream>
#include <vector>
#include "sum_my_vector.h"
using namespace::std;
int sum_my_vector(vector<int> my_vector)
{
int my_sum = 0;
for (auto iv = my_vector.begin(); iv != my_vector.end(); iv++)
my_sum += *iv;
return my_sum;
}
sum_my_vector.h
#ifndef SUM_MY_VECTOR
#define SUM_MY_VECTOR
using namespace::std;
int sum_my_vector(vector<int> my_vector);
#endif
python_file.py
from cython_file import sum_my_vector_cpp
print sum_my_vector_cpp([1,2,3,5])
Now run
python setup.py build_ext --inplace
and the you can run the python file
python python_file.py
11
"Passing a list through Python to C++"
An alternative approach would be to use Boost.Python, this may not answer your question directly, but still its worth pointing out another solution.
#include <boost/python.hpp>
#include <vector>
#include <string>
void get_dir_list( boost::python::list dir_list )
{
for (int i = 0; i < len(dir_list); ++i)
{
std::string x = boost::python::extract<std::string>(dir_list[i]);
// perform stuffs
std::cout << "This is " << x << std::endl ;
}
}
BOOST_PYTHON_MODULE(get_dir_list)
{
def("get_dir_list", get_dir_list);
}
Compiled Using :
g++ main.cpp -shared -fPIC -o get_dir_list.so -I/usr/include/python2.7 -lboost_python
Usage :
import get_dir_list
import os
get_dir_list.get_dir_list(os.listdir('.'))
Live Demo Here
I'll post this alternative solution since it would also work for other long lists of strings that needed to be passed.
In your Python script create a text file (I'll call it "masterFile") and write the file paths to the masterFile. You could give each file path a separate line. Then pass the masterFile's file path to your C++ program. This way you don't have to worry about the length of your command line arguments. Let your C++ program open and read the file for processing.
You can use something like os.remove() to get rid of the masterFile in your Python script once the C++ program has finished.
Also, you mentioned in the comments that you need to do different tasks dependent on different file paths: A suggestion would be to add a char at the beginning of each line in the masterFile to signal what needs to be done for the particular file. Example:
a Random/path/aFile.txt # a could mean do task 1
b Random2/path2/differentFile.c # b could mean do task 2
You pass a list to subprocess.call. subprocess.call converts this to what is needed for the system (which may vary, but certainly isn't a Python list). The system then arranges for this to be copied somewhere in the new process, and sets up the standard arguments to main, which are int, char**. In your C++ program, you must define main as int main( int argc, char** argv ); nothing else will work. (At least... a system could support int main( std::string const& ) or some such as an extension. But I've never heard of one that did.)
I've just started working with Python with C++ and I'm a bit confused on why I'm unable to call functions in Python from C++.
Here is my current test code in C++:
#include <iostream>
#include <Python.h>
using namespace std;
int main()
{
Py_Initialize();
PyObject* myModuleString = PyString_FromString("test");
PyObject* myModule = PyImport_Import(myModuleString);
if( myModule )
{
PyObject* myFunction = PyObject_GetAttrString(myModule, "Hello");
if( myFunction )
{
PyEval_CallObject( myFunction, NULL );
}
else
{
fprintf( stderr, "myFunction is NULL" );
}
}
else
{
fprintf( stderr, "myModule is NULL" );
}
Py_Finalize();
cin.get();
return 0;
}
Here is my test.py Python code:
import sys
def Hello():
print "Hello, world!"
Before I had a more complicated test, but I ran into an issue where PyObject_GetAttrString passed back NULL, so I wanted to make a simpler test and I still received NULL after calling PyObject_GetAttrString. From my understanding PyObject_GetAttrString gets you the PyObject* to the function and then I call it after, so receiving NULL there basically means I can't call the function.
Also yes I have looked at https://docs.python.org/2.7/ and even tested the example given in step 5.3 of https://docs.python.org/release/2.6.5/extending/embedding.html#pure-embedding (I'm using 2.7.7 because I'm planning to integrate with 3ds Max ). It still runs into the same issues with PyObject_GetAttrString.
I'm assuming it's a simple mistake or step I'm missing in the C++ or Python code.
Changing the Python script name from test.py to anything else worked for me.
I was having a similar problem. I found that the whitespace in the string I was passing to python was way off. From what I could tell, your print statement has 6 spaces in lieu of 4. Back it up and see if everything doesn't clear up.
I had the same problem. Although test.py and mycode.c were in the same folder (/home/user/python/example), I had to add a reference to the path after Py_Initialize(); as shown in following line
PyRun_SimpleString ("import sys; sys.path.insert(0, '/home/user/python/spp')");*
Replace /home... to your path.
My previous code did not have that line of code but PyImport_Importwas working and PyObject_GetAttrString wasn't. Makes no sense to me, "don't ask me, I don't know - Ozzy".
Win7 x64, Python3.3 32bit, Visual Studio 2010/2012 (same behavior). The following code compiles and runs just fine (i.e. prints current date):
extern "C"{ // not having it doesn't make any difference either
#include <Python.h>
}
int main() {
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
Py_Finalize();
return 0;
}
while this here fails with a MessageBox saying The application was unable to start correctly (0xc0000005). Click OK to close the application. before main executed (so no breakpoint possible).
extern "C"{ // not having it doesn't make any difference either
#include <Python.h>
}
int main() {
Py_Initialize();
PyObject *p = PyUnicode_FromString("test");
Py_Finalize();
return 0;
}
So the problem seems to have been the following: I was linking with python3.lib but since the string functions were completely overworked with Python3.3 there seemed to have been some problem with correctly linking them. (can't really explain why this would be so, since PyUnicode_FromString existed obviously in earlier versions of python3 too).
Why I couldn't get a useful error message about that fact is also beyond me, but there we go: linking against python33.lib solved the problem perfectly.
I think this could be for 2 reasons, but I'm pretty sure its this one:
http://docs.python.org/2/c-api/unicode.html
You need to null terminate y our constant string "test" by making it "test\0". If that doesn't work, it might have to do with the fact that c files are ansi and not utf8.
Your broken program is linking against a build of Python that uses UCS-2 as the internal unicode representation, but the installed Python uses UCS-4, and therefore the PyUnicodeUCS2_* imports can't be resolved. You'll need to link against the UCS-4 build instead.