I'm trying to extend Python 3 using instructions given here and I'm fairly confident I've followed the instructions correctly so far, but it asks me to include this code:
PyMODINIT_FUNC
PyInit_spam(void)
{
PyObject *m;
m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;
SpamError = PyErr_NewException("spam.error", NULL, NULL);
Py_INCREF(SpamError);
PyModule_AddObject(m, "error", SpamError);
return m;
}
I'm writing this in MSVC++ 2010 and it's warning me that &spammodule is undefined (the name of the module is spammodule.cpp), but it doesn't define it anywhere in the instructions so I assume that it should recognise it automatically as the name of the module.
The full code is:
#include <Python.h>
#include <iostream>
using namespace std;
static PyObject *SpamError;
int main()
{
cout << "Test" << endl;
system("PAUSE");
return(0);
}
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 PyLong_FromLong(sts);
}
PyMODINIT_FUNC
PyInit_spam(void)
{
PyObject *m;
m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;
SpamError = PyErr_NewException("spam.error", NULL, NULL);
Py_INCREF(SpamError);
PyModule_AddObject(m, "error", SpamError);
return m;
}
You're still writing C++, so you still need to declare spammodule somewhere. This is given later on the same page:
static struct PyModuleDef spammodule = {
PyModuleDef_HEAD_INIT,
"spam", /* name of module */
spam_doc, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
SpamMethods
};
No no no, PyModule_Create() accepts a pointer to the module definition structure and has absolutely nothing to do with the name of the source file.
Related
I'm trying to write a basic plugin for gstreamer in C++. I am working from another person's examples and have followed the structure of the code (I believe) exactly. However, I've been trying to compile the code and I am seeing an error saying
unresolved external symbol gst_adder_get_type referenced in function "int __cdecl plugin_init(struct _GstPlugin *)" (?plugin_init##YAHPEAU_GstPlugin###Z)
I have declared but not implemented gst_adder_get_type. I did that because the examples I have seen have not had any implementation of the function either, they just have the declaration in the header file and somehow that works.
I have tried implementing the function myself anyway, but other errors pop up instead.
Adder.h:
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
G_BEGIN_DECLS
#define GST_TYPE_ADDER (gst_adder_get_type())
#define GST_ADDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADDER,Gstadder))
#define GST_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADDER,GstadderClass))
#define GST_IS_ADDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADDER))
#define GST_IS_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADDER))
struct _Gstadder
{
GstElement element;
//pads
GstPad* srcpadadder; //publish data
// property values
gint _num_one;
gint _num_two;
gint _sum;
};
struct _GstadderClass
{
GstElementClass parent_class;
};
GType gst_adder_get_type(void);
typedef struct _Gstadder Gstadder;
typedef struct _GstadderClass GstadderClass;
GST_ELEMENT_REGISTER_DECLARE(adder);
G_END_DECLS
Adder.cpp:
// Adder.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "pch.h"
#include <gst/gst.h>
#include "Adder.h"
#include <gstreamer-1.0/gst/base/gstbasesrc.h>
#include <gstreamer-1.0/gst/base/gstpushsrc.h>
GST_DEBUG_CATEGORY(gst_adder_debug);
// This defines the properties owned by this class.
enum
{
PROP_NUMONE,
PROP_NUMTWO,
PROP_SUM
};
// Definitions of functions later in this file so that we can access them now.
static void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec);
static gboolean gst_adder_start(GstBaseSrc* basesrc);
static gboolean gst_adder_stop(GstBaseSrc* basesrc);
static GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps);
static GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf);
static void gst_adder_finalize(GObject* object);
/*
* "CAPS" are literally capabilities. They seem only to be descriptions, not functions.
* I think this means that when I run an inspect on the DLL, this gets called to write out
* what the capabilities of the function actually are and what kinds of pads exist.
*/
static GstStaticPadTemplate src_det_factory = GST_STATIC_PAD_TEMPLATE(
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS("Integer"));
static void gst_adder_class_init(GstadderClass * klass) {
/*
Class starting initiation. Different from the object instantiation.
*/
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS(klass);
GstElementClass* element_class;
element_class = GST_ELEMENT_CLASS(klass);
GstBaseSrcClass* gstbasesrc_class;
gstbasesrc_class = (GstBaseSrcClass*)klass;
GstPushSrcClass* gstpushsrc_class;
gstpushsrc_class = (GstPushSrcClass*)klass;
// Metadata. Not sure if this is redundant or not. Assuming not.
const gchar* m_a = "AdditionMan";
gst_element_class_set_static_metadata(
element_class,
m_a,
"MY_ADDER",
"Add two numbers, return the sum",
"John Garst <john.garst#parsons.com>");
// Initialize pad for the source
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&src_det_factory));
// This appears to be where we are linking the callback functions for the adder.
gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_adder_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_adder_get_property);
gstbasesrc_class->start = GST_DEBUG_FUNCPTR(gst_adder_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR(gst_adder_stop);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_adder_get_caps);
gstpushsrc_class->fill = GST_DEBUG_FUNCPTR(gst_adder_fill);
gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_adder_finalize);
// Property Definitions. This is linked to an enum at the top of this file,
// and will be used more in the adder instantiation and getters/setters.
g_object_class_install_property(
gobject_class,
PROP_NUMONE,
g_param_spec_string(
"NumOne",
"NumOne",
"The first number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_NUMTWO,
g_param_spec_string(
"NumTwo",
"NumTwo",
"The second number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_SUM,
g_param_spec_string(
"Sum",
"Sum",
"The sum of NumOne and NumTwo.",
0,
G_PARAM_READWRITE
)
);
}
static void gst_adder_init(Gstadder* filter) {
/*
instantiate the element. This happens after class initiation.
*/
//initialize pads
filter->srcpadadder = gst_pad_new_from_static_template(&src_det_factory, "src");
//initialize values
filter->_num_one = 0;
filter->_num_two = 0;
filter->_sum = 0;
//configure
gst_base_src_set_format(GST_BASE_SRC(filter), GST_FORMAT_TIME);
gst_base_src_set_live(GST_BASE_SRC(filter), true);
gst_base_src_set_do_timestamp(GST_BASE_SRC(filter), true);
}
static gint gst_adder_add_two_numbers(Gstadder* filter) {
/*
This function takes two numbers and adds them together, returning the sum of those numbers.
*/
filter->_sum = filter->_num_one + filter->_num_two;
return filter->_sum;
}
void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can set the two numbers to add, but not the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
that->_num_one = g_value_get_int(value);
break;
case PROP_NUMTWO:
that->_num_two = g_value_get_int(value);
break;
}
}
void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can get any property, including the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
g_value_set_int(value, that->_num_one);
break;
case PROP_NUMTWO:
g_value_set_int(value, that->_num_two);
break;
case PROP_SUM:
g_value_set_int(value, that->_sum);
break;
}
}
gboolean gst_adder_start(GstBaseSrc* basesrc) {
/*
Start the adder. There is nothing else necessary to initialize, so we won't do anything here.
*/
return gboolean();
}
gboolean gst_adder_stop(GstBaseSrc* basesrc) {
/*
Stop the adder. There is nothing to clean, so we won't do anything here.
*/
return gboolean();
}
GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf) {
/*
Fill the adder from buffer. This seems to be where the magic actually happens.
*/
Gstadder* filter = GST_ADDER(src);
gst_adder_add_two_numbers(filter);
return GstFlowReturn();
}
GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps) {
/*
Return Adder capabilities
*/
#ifdef __linux__
return gst_caps_new_simple(0, NULL, NULL);
#else
return gst_caps_new_simple(0, nullptr);
#endif
}
void gst_adder_finalize(GObject* object) {
/*
Release memory and clean up the workspace.
*/
}
GType gst_adder_get_type(void)
{
static GType gst_adder_get_type = 0;
if (!gst_adder_get_type) {
static const GTypeInfo gst_adder_get_type_info = {
sizeof(GstadderClass),
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
};
gst_adder_get_type = g_type_register_static(G_TYPE_INTERFACE,
"GstVideoOverlay", &gst_adder_get_type_info, G_TYPE_FLAG_ABSTRACT);
}
return gst_adder_get_type;
}
gst_Plugin_Test.h
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the VIDEOSTRETCH_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// VIDEOSTRETCH_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef GST_PLUGIN_TEST_EXPORTS
#define GST_PLUGIN_TEST_API __declspec(dllexport)
#else
#define GST_PLUGIN_TEST_API __declspec(dllimport)
#endif
gst_Plugin_Test.cpp
// GST_Plugin_Test.cpp : Seems to initialize only the other classes that are involved. Doesn't seem
// like this can do it's own processing, which is a little odd to me. I don't know if that's correct.
//Includes. stdafx is required for some reason, as is pch.
#include "stdafx.h"
#include "pch.h"
#include "Adder.h"
#include <gst/gst.h>
#include "gst_Plugin_Test.h"
GST_DEBUG_CATEGORY(gst_gst_plugin_test_debug);
static gboolean plugin_init(GstPlugin* plugin)
{
/*
One of (?) the initialization functions. Seems like the main entry point.
*/
gboolean ret = TRUE;
GST_DEBUG_CATEGORY_INIT(gst_gst_plugin_test_debug, "gst_plugin_test", 0, "Test Stuff");
// The adder class is where things actually happen. We register it here.
ret = gst_element_register(plugin, "MY_ADDER", GST_RANK_NONE, GST_TYPE_ADDER);
return ret;
}
#define PACKAGE "GST_Plugin_Test"
// This is where the plugin metadata is defined. Shown on a gst-inspect-1.0
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
GST_VERSION_MINOR,
GST_Plugin_Test,
"Just Testing Things",
plugin_init, "1.0", "LGPL",
"TEST", "http://www.polarisalpha.com");
UPDATE:
I did find a place that has another example where the get_type function is declared in the header and implemented in the C file, which makes a lot more sense. I've done it myself, again following the structure as best I can, and now can compile the DLL and put it into my plugins folder. However, I can't successfully inspect the plugin. It give me the error:
gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
which seems odd. I've updated the Adder file to include the implementation of the get_type function.
I have got an example from here and I faced with a run error
LLVM ERROR: Target does not support MC emission!
which I fixed it by this.
nevertheless, I still observe runtime problem:
./example 3 5
LLVM ERROR: MCJIT::runFunction does not support full-featured argument passing. Please use ExecutionEngine::getFunctionAddress and cast the result to the desired function pointer type.
main.cpp
/**
* LLVM equivalent of:
*
* int sum(int a, int b) {
* return a + b;
* }
*/
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");
LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
LLVMValueRef sum = LLVMAddFunction(mod, "sum", ret_type);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), "tmp");
LLVMBuildRet(builder, tmp);
char *error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
LLVMExecutionEngineRef engine;
error = NULL;
LLVMLinkInMCJIT();
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter(); // added
LLVMInitializeNativeAsmParser(); // added
if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0)
{
fprintf(stderr, "failed to create execution engine\n");
abort();
}
if (error)
{
fprintf(stderr, "error: %s\n", error);
LLVMDisposeMessage(error);
exit(EXIT_FAILURE);
}
if (argc < 3)
{
fprintf(stderr, "usage: %s x y\n", argv[0]);
exit(EXIT_FAILURE);
}
long long x = strtoll(argv[1], NULL, 10);
long long y = strtoll(argv[2], NULL, 10);
LLVMGenericValueRef args[] = {
LLVMCreateGenericValueOfInt(LLVMInt32Type(), x, 0),
LLVMCreateGenericValueOfInt(LLVMInt32Type(), y, 0)
};
LLVMGenericValueRef res = LLVMRunFunction(engine, sum, 2, args);
printf("%d\n", (int)LLVMGenericValueToInt(res, 0));
// Write out bitcode to file
if (LLVMWriteBitcodeToFile(mod, "sum.bc") != 0) {
fprintf(stderr, "error writing bitcode to file, skipping\n");
}
LLVMDisposeBuilder(builder);
LLVMDisposeExecutionEngine(engine);
}
Though the meessage is clear for the view point of the code author, for me as a user it is so cryptic. How can I solve this?
From the documentation of MCJIT::runFunction:
For MCJIT execution engines, clients are encouraged to use the "GetFunctionAddress" method (rather than runFunction) and cast the returned uint64_t to the desired function pointer type. However, for backwards compatibility MCJIT's implementation can execute 'main-like' function (i.e. those returning void or int, and taking either no arguments or (int, char*[])).
So you can't call MCJIT::runFunction (and by extension the C API's LLVMRunFunction when used with an MCJIT engine) unless the arguments array is either empty or consists of only an i32 and an i8* (in that order). Your array contains two i32s, so it does not meet those restrictions.
As stated in the documentation (and the exception message), you should instead use ExecutionEngine::getFunctionAddress (or its C wrapper LLVMGetFunctionAddress), cast the result to int (*)(int, int) and then call it as f(0, 0);.
I've been trying to get lua scripting working for a small game I'm working on, but lua seems to be more trouble than its worth. After much googling and hair tearing, I managed to get simple scripts running but quickly hit a wall. C functions don't seem to want to bind to lua, or at least don't want to run after binding. g++ compiles the c code without incident but the lua interpreter generates this syntax error:
LUA ERROR: bin/lua/main.lua:1: syntax error near 'getVersion'
My C(++) code:
#include <lua.hpp>
static const luaL_Reg lualibs[] =
{
{"base", luaopen_base},
{"io", luaopen_io},
{NULL, NULL}
};
void initLua(lua_State* state);
int getVersion(lua_State* state);
int main(int argc, char* argv[])
{
lua_State* state = luaL_newstate();
initLua(state);
lua_register(state, "getVersion", getVersion);
int status = luaL_loadfile(state, "bin/lua/main.lua");
if(status == LUA_OK){
lua_pcall(state, 0, LUA_MULTRET, 0);
}else{
fprintf(stderr, "LUA ERROR: %s\n", lua_tostring(state, -1));
lua_close(state);
return -1;
}
lua_close(state);
return 0;
}
void initLua(lua_State* state)
{
const luaL_Reg* lib = lualibs;
for (; lib->func != NULL; lib ++)
{
luaL_requiref(state, lib->name, lib->func, 1);
lua_settop(state, 0);
};
delete lib;
}
int getVersion(lua_State* state)
{
lua_pushnumber(state, 1);
return 1;
};
The Lua code:
print getVersion()
print is a function. Since its argument is neither a table constructor nor a string literal, you have to call it using ():
print(getVersion())
Read the funny manual here.
I have a little project with cocos2d-x libraries. I'm trying to use C++ to call a Java function but i get a signal 11 exception at line:
// Get Status
status = jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
But i don't know why this is happening.
In my Java class Getsocial.java exist this function:
private void tweet()
{
String score = "123";
String tweetUrl = "https://twitter.com/intent/tweet?text=Hello ! I have just got " + score + " points in mygame for Android !!!!";
Uri uri = Uri.parse(tweetUrl);
startActivity(new Intent(Intent.ACTION_VIEW, uri));
}
This function launch navigator to post a tweet. Called from Java works fine.
In my C++ InterfaceJNI.h I have:
#ifndef __INTERFACE_JNI_H__
#define __INTERFACE_JNI_H__
#include "cocos2d.h"
class InterfaceJNI
{
public:
static void postMessageToFB();
static void postMessageToTweet();
protected:
};
#endif // __INTERFACE_JNI_H__
And in InterfaceJNI.cpp:
#include "InterfaceJNI.h"
#include "platform/android/jni/JniHelper.h"
#include jni.h >
#include android/log.h >
using namespace cocos2d;
void InterfaceJNI::postMessageToTweet()
{
int status;
JNIEnv *env;
JavaVM *jvm;
jmethodID mid;
jclass mClass;
bool isAttached = false;
CCLog("Static postMessageToTweet");
// Get Status
status = jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
CCLog("Status: %d", status);
if(status AttachCurrentThread(&env, NULL);
CCLog("Status 2: %d", status);
if(status GetStaticMethodID(mClass, "tweet", "()V");
CCLog("mID: %d", mid);
if (mid!=0)
env->CallStaticVoidMethod(mClass, mid);
//-----------------------------------------------------------
CCLog("Finish");
if(isAttached)
jvm->DetachCurrentThread();
return;
}
This interface is called from a part of the code using:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
InterfaceJNI::postMessageToTweet();
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
ObjCCalls::trySendATweet();
#endif
What is happening to return a null pointer on jvm->GetEnv((void **) &env, JNI_VERSION_1_6); ?
It looks like your jvm variable is null or garbage. The version of Cocos2D-x I use has a class called JniHelper with a static ::getJavaVM(); method that you might want to use.
JavaVM* vm = JniHelper::getJavaVM();
JNIEnv* env;
vm->GetEnv((void**)&env,JNI_VERSION_1_4); // mine uses JNI_VERSION_1_4
Also, remember to "refresh" your eclipse project every time you build with NDK. You probably do already, but it's worth checking.
While working on a C++ project, I was looking for a third party library for something that is not my core business. I found a really good library, doing exactly what's needed, but it is written in Python. I decided to experiment with embedding Python code in C++, using the Boost.Python library.
The C++ code looks something like this:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module((handle<>(borrowed(PyImport_AddModule("__main__")))));
object name_space = module.attr("__dict__");
object ignored = exec("from myModule import MyFunc\n"
"MyFunc(\"some_arg\")\n",
name_space);
std::string res = extract<std::string>(name_space["result"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
A (very) simplified version of the Python code looks like this:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
print result
Now the problem is this:
'MyFunc' executes fine, i can see the print of 'result'.
What i cannot do is read 'result' back from the C++ code. The extract command never finds 'result' in any namespace.
I tried defining 'result' as a global, i even tried returning a tuple, but i cannot get it to work.
First of all, change your function to return the value. printing it will complicate things since you want to get the value back. Suppose your MyModule.py looks like this:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
Now, to do what you want, you have to go beyond basic embedding, as the documentation says. Here is the full code to run your function:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pArg, *pResult;
int i;
Py_Initialize();
pName = PyString_FromString("MyModule.py");
/* Error checking of pName left out as exercise */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "MyFunc");
/* pFunc is a new reference */
if (pFunc) {
pArgs = PyTuple_New(0);
pArg = PyString_FromString("some parameter")
/* pArg reference stolen here: */
PyTuple_SetItem(pArgs, 0, pArg);
pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pResult != NULL) {
printf("Result of call: %s\n", PyString_AsString(pResult));
Py_DECREF(pResult);
}
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");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load module");
return 1;
}
Py_Finalize();
return 0;
}
Based on ΤΖΩΤΖΙΟΥ, Josh and Nosklo's answers i finally got it work using boost.python:
Python:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
C++:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module = import("__main__");
object name_space = module.attr("__dict__");
exec_file("MyModule.py", name_space, name_space);
object MyFunc = name_space["MyFunc"];
object result = MyFunc("some_args");
// result is a dictionary
std::string val = extract<std::string>(result["val"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
Some important points:
I changed 'exec' to 'exec_file' out of
convenience, it also works with
plain 'exec'.
The main reason it failed is that i
did not pass a "local" name_sapce to
'exec' or 'exec_file' - this is now
fixed by passing name_space twice.
If the python function returns
unicode strings, they are not
convertible to 'std::string', so i
had to suffix all python strings
with '.encode('ASCII', 'ignore')'.
I think what you need is either PyObject_CallObject(<py function>, <args>), which returns the return value of the function you call as a PyObject, or PyRun_String(<expression>, Py_eval_input, <globals>, <locals>) which evaluates a single expression and returns its result.
You should be able to return the result from MyFunc, which would then end up in the variable you are currently calling "ignored". This eliminates the need to access it in any other way.