Hacked together C++ to show how to embed and extend Python 3
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

161 lines
4.8 KiB

#include <iostream>
#include <Python.h> // Note that I use -I in compile args to specify version, which isn't great
#include <string>
/* Hacked together C++ code to show how to both embed and extend
* Python 3 in C++ (albeit, this code is basically C because I use very
* few C++ features).
*
* Note that this is basically cut-and-paste from several
* sources, usually not verbatim but close. See References to get an idea of
* where I got this this stuff from
*
* --------------
* = TODO =
* --------------
*
* - Arguments to / from C++ functions
* - Returning stuff to Python from C++
* - Returning stuff from Python to C++
* - Calling Python class methods
* - Calling C++ class methods (probably impossible - need to wrap and use global class singletons or something)
* */
///////////////////////////////////////////////////////////
// Compiling + linking (assuming g++) //
///////////////////////////////////////////////////////////
/*
compile:
g++ -c -Wall -Wno-unused-result -Werror=declaration-after-statement -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -DNDEBUG -fwrapv --std=c++11 -pedantic -I/usr/include/python3.4dm "%f"
link:
g++ -o "%e" "%e.o" -L/usr/lib -lpthread -ldl -lutil -lm -lpython3.4dm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
To get official python build/link args, use:
python3.4-config --cflags
and
python3.4-config --ldflags
*/
///////////////////////////////////////////////////////////
// References (look here when you see [n]) //
///////////////////////////////////////////////////////////
/*
https: docs.python.org/3/extending/embedding.html
(great overview for Python 3) [1]
https: docs.python.org/2/extending/embedding.html
(overview for 2.7) [2]
http: rhodesmill.org/brandon/2008/porting-a-c-extension-module-to-python-30/
(string to pystring) [3]
https: docs.python.org/3/c-api/intro.html#embedding-python
(details about programname stuff) [4]
http: www.cplusplus.com/forum/beginner/49000/
(wchar_t conversion) [5]
http: markmail.org/message/qwex6rhhqd43jg2o
(Setting python import path (important when having private dir for python modules)) [6]
*/
///////////////////////////////////////////////////////////
// C++ API module (Python extension) //
///////////////////////////////////////////////////////////
void helloWorld(void)
{
std::cout << "Hello Python, it's C++!\n";
}
static PyObject* emb_helloWorld(PyObject* self, PyObject *args)
{
helloWorld();
return Py_BuildValue("");
}
static PyMethodDef EmbMethods[] = {
{"helloFromC", emb_helloWorld, METH_VARARGS,
"have c++ say hello"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef testCAPI = {
PyModuleDef_HEAD_INIT,
"testCAPI",
NULL,
-1,
EmbMethods
};
static PyObject* PyInit_testCAPI(void)
{
return PyModule_Create(&testCAPI);
}
///////////////////////////////////////////////////////////
// Main //
///////////////////////////////////////////////////////////
// Test python embedding and extending
// Follow [1] to get what's going on
int main()
{
PyObject *pModule;
PyObject *pModuleName;
PyObject *pModuleFunc;
// See [5]
const wchar_t c_s[] = L"/home/macoy/projects/pythonTesting/main";
wchar_t *s = new wchar_t[sizeof(c_s) / sizeof(c_s[0])];
wcscpy(s, c_s);
const wchar_t p_s[] = L":.";
wchar_t *ps = new wchar_t[sizeof(p_s) / sizeof(p_s[0])];
wcscpy(ps, p_s);
Py_SetProgramName(s); // see [4]
// Add C++ API to modules (supposed to call before Py_Initialize!). See [1]
PyImport_AppendInittab("testCAPI", &PyInit_testCAPI);
Py_Initialize();
delete[] s;
// See [6]; The below code makes it so we can import from the current directory
wchar_t *path, *newpath;
path=Py_GetPath();
newpath=new wchar_t[wcslen(path)+4];
wcscpy(newpath, path);
wcscat(newpath, ps); // ":." for unix, or ";." for windows
PySys_SetPath(newpath);
delete[] newpath;
// See [3]
pModuleName = PyUnicode_FromString("helloModule");
pModule = PyImport_Import(pModuleName);
Py_DECREF(pModuleName);
// Follow [1] to get what's going on
if (pModule != NULL)
{
pModuleFunc = PyObject_GetAttrString(pModule, "helloWorld");
if (pModuleFunc && PyCallable_Check(pModuleFunc))
{
PyObject* pArgs = NULL;
PyObject *pReturnVal = PyObject_CallObject(pModuleFunc, pArgs);
}
else
std::cout << "error: no func\n";
Py_XDECREF(pModuleFunc);
Py_DECREF(pModule);
}
else
std::cout << "error: no module\n";
// cleanup (probably missing some Py_DECREFs but oh well)
Py_Finalize();
return 0;
}