Hi,
I need to call a C++ function (or a class, if there is such an option), from Panda’s Python code. A function will be part of a DLL, I can also define it in the lib… whatever necessary.
Could you please point me to a proper example? As simple as possible, like call a function, pass it parameters, get the return value, and/or values of parameters, passed by reference?
If you’re looking for a way to extend python using C++ like panda does, I’d recomend using Boost.Python, it gives you a much easier interface to work with then the raw python bindings. You can find some examples here:
There are several ways to call a C/C++ function from Python. First, you can access C/C++ functions directly from Python, using the ctypes module. In Python 2.5 it is already included, for Python 2.4 you have to download it from sourceforge: http://sourceforge.net/project/showfiles.php?group_id=71702
Here is a short example, for accessing some of the the functions contained in msvcrt dll (should be on every windows system, and in the search path):
As simple as possible, just calling functions and passing arguments. But you should still read the tutorial for this module, or you will end up getting one access violation after the other: http://python.net/crew/theller/ctypes/tutorial.html
Another way is to wrap the C/C++ code to build (compile) a DLL that can be used by Python like any other module. About one third of the Python documentation actually covers this topic: http://docs.python.org/ext/ext.html
Again, a short example how to do a such a wrapper.
#include <Python.h>
#include "structmember.h"
static PyObject* my_function( PyObject *self, PyObject *args )
{
const char* _filename;
if ( ! PyArg_ParseTuple( args, "s", &_filename ) ) return NULL;
// do something in C++, for example calling other function
// and return some values
return Py_BuildValue( "i", 0 );
}
static PyMethodDef foo_methods[ ] = {
{ "myFunc", ( PyCFunction ) my_function, METH_VARARGS, "" },
{ NULL } /* Sentinel */
};
PyMODINIT_FUNC initfoo( void )
{
( void ) Py_InitModule( "foo", foo_methods );
}
Both ways are quite powerfull tools, but I am afraid they require some reading by yourself. Hope this helps for getting started,
enn0x
I started learning C++ weeks ago, using MinGW (Dev-C++ IDE).
In my case, it’s always exported as ordinal indices. I just realized a simple way to export a function name “as is”, as follows :
force the linker to use an altered .def file (say hacked-DefFile.def) by adding this linking option :
–def hacked-DefFile.def
hacked-DefFile.def came from the original .def file
original .def example :
in this line : _ZN8DllClass11getGLvendorEv @ 1, _ZN8DllClass11getGLvendorEv is DllClass::getGLvendor function, which is available as index 1 (@ 1)
so by setting : getGLvendor = _ZN8DllClass11getGLvendorEv, we can access this function using getGLvendor reference, as clear and simple as expected.
my defFileHacker.py :
# the original .def filename
filename = 'libOGL2.def'
# the exported dll class
DllClass = 'DllClass'
origDefFile = open(filename,'r')
lineList = origDefFile.readlines()
origDefFile.close()
exportedNames=[]
filename='hacked-'+filename
hackedDefFile = open(filename,'w')
for i in range(len(lineList)):
pos = lineList[i].rfind('::')
if pos>0:
pos+=2
name = lineList[i][pos:]
bracketPos = name.rfind('(')
if bracketPos>0:
name = name[:bracketPos]
# print name
if name!=DllClass and name!='~'+DllClass:
_beg=lineList[i+1].find('_')
lineList[i+1]= '%s%s = %s' %( lineList[i+1][:_beg], name, lineList[i+1][_beg:] )
exportedNames.append("'"+name+"',")
hackedDefFile.writelines(lineList)
hackedDefFile.close()
exportedNamesFile = open('exportedNames.txt','w')
exportedNamesFile.writelines('\n'.join(exportedNames))
exportedNamesFile.close()
the result are :
the hacked .def file (newly created), and
exportedNames.txt : includes all exported functions names.
simple Panda Python sample :
from direct.gui.OnscreenText import OnscreenText
import direct.directbase.DirectStart
from ctypes import *
OGLlib=cdll.OGL2
def OSD(parent, text1,text2,tab,z):
OnscreenText(
parent=parent, text=text1, pos=(-tab,-z*.05), scale=.045, align=0
)
OnscreenText(
parent=parent, text=text2, pos=(0,-z*.05), scale=.045, align=0
)
# JUST TO MAINTAIN ORDER OF APPEARANCE, use a sequence
wanted=(
'Vendor','getGLvendor',
'Renderer','getGLrenderer',
'Driver version','getGLversion',
'Maximum texture size','getMaxTexSize',
'Texture stages','getMaxTexStages',
'Clip planes','getMaxClipPlanes',
'Lights','getMaxLights',
'Point Anti-Alias max range','getPointAAmaxRange',
'Point Anti-Alias Granularity','getPointAAgranularity',
'Line Anti-Alias Granularity','getLineWidthAAgranularity',
)
print '''
#######################################################
## ##
## SOME GRAPHICS HARDWARE INFORMATION ##
## ##
#######################################################'''
parent=aspect2d.attachNewNode('')
for d in range(0,len(wanted),2):
funct = getattr(OGLlib,wanted[d+1])
val = c_char_p(funct()).value
OSD(parent, wanted[d],': '+val, .47, d*.5)
print '%28s : %s' %(wanted[d],val)
parent.setZ(-parent.getBounds().getCenter()[2])
Actually, my favorite way to do it is to insert my classes into the panda source tree, and then recompile panda. That way, panda’s mechanisms will take care of it for you. I find it fairly convenient.
As of panda 1.4.0, I created a directory panda/src/skel that contains some sample classes that don’t do anything, but which give you a starting point — it’s easy to insert your own methods into these classes. Then you can rename them, then you can copy them if you need more classes, and you can sort of build from there.
sure, you’re an expert and I’m just get started, so I’m still playing around with ctypes, at least I don’t have to re-build everything again and again.
[EDIT]
my barrier was – according to Python v2.4.3 docs – that I need .lib -> .a (MinGW import lib) converter, and I couldn’t find one. That’s why I fell back to ctypes.
But later, I realized that libpython24.a is already included in the dist. OMG, why couldn’t I see this before ?
Well, now I think I can do things more correctly, and yes it’s getting simpler and fun, at least I get types converter (num->str) for free.