{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Invoke C++ from Python without bindings thanks to ROOT\n",
"
\n",
"With [ROOT](http://root.cern.ch), it's possible to use interactively C++ libraries from Python without the need to write bindings. The C++ entities known to the interpreter are exposed to Python transparently.\n",
"Let's dive into an example. \n",
"\n",
"The following sources include a class, a function and a template.\n",
"\n",
"## Header File"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%python\n",
"code='''\n",
"#include \n",
"#include \n",
"\n",
"/// A trivial class\n",
"class A {\n",
"public:\n",
" A();\n",
" ~A();\n",
"};\n",
"\n",
"/// A trivial function\n",
"int CountCharacters(const std::string s);\n",
"\n",
"/// A trivial template\n",
"template\n",
"class B {\n",
"public:\n",
" B()\n",
" {\n",
" std::cout << \"The typeid name of the template argument is \" << typeid(T).name() << std::endl;\n",
" }\n",
"};\n",
"'''\n",
"with open('myLibrary.h','w') as f_out:\n",
" f_out.write(code)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementation"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%python\n",
"code='''\n",
"#include \"myLibrary.h\" \n",
"A::A()\n",
"{\n",
" std::cout << \"This is the constructor of A\" << std::endl;\n",
"}\n",
"\n",
"A::~A()\n",
"{\n",
" std::cout << \"This is the destructor of A\" << std::endl;\n",
"}\n",
"\n",
"int CountCharacters(const std::string s)\n",
"{\n",
" return s.size();\n",
"}\n",
"'''\n",
"with open('myLibrary.cc','w') as f_out:\n",
" f_out.write(code)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Creation of the Library\n",
"It's trivial to create a shared object starting from the sources above:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%bash\n",
"g++ -o libmyLibrary.so -shared -fPIC myLibrary.cc "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"libmyLibrary.so\n"
]
}
],
"source": [
"%%bash\n",
"ls *so"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So far, so good. Now we'll see how easy it is to use this library from within Python thanks to [ROOT](http://root.cern.ch).\n",
"## Interactivity without bindings\n",
"In order to interact with the C++ entities contained in the library, we need to carry out to tasks:\n",
"1. We need to make known to the interpreter the *interfaces*. Concretely this means including one or more headers.\n",
"2. We need to make accessible to the interpreter the implementations of such C++ entities. Concretely this means loading the library.\n",
"\n",
"In code:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"\n",
"require(['notebook'],\n",
" function() {\n",
" IPython.CodeCell.config_defaults.highlight_modes['magic_text/x-c++src'] = {'reg':[/^%%cpp/]};\n",
" console.log(\"JupyROOT - %%cpp magic configured\");\n",
" }\n",
");\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Welcome to JupyROOT 6.07/07\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import ROOT\n",
"ROOT.gInterpreter.ProcessLine('#include \"myLibrary.h\"')\n",
"ROOT.gSystem.Load(\"./libmyLibrary.so\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That's it! We can now start exploring the content of the library. If you are wondering what a return code equal to 0 means, ROOT is telling us that the loading of the library happened without problems!"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is the constructor of A\n"
]
}
],
"source": [
"a = ROOT.A()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is the destructor of A\n"
]
}
],
"source": [
"del a"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The typeid name of the template argument is Pd\n"
]
}
],
"source": [
"b_doublePtr = ROOT.B(\"double*\")()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice how the \"impedence mismatch\" generated by the concept of templates is ironed out in this case. The template parameter is specified as string in parentheses."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"57"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ROOT.CountCharacters(\"This interactivity without bindings is really impressive.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Interactivity within C++\n",
"Interactive usage of C++ libraries is possible also in C++ mode. In this case, no wrapper is interposed between the statement written by the user and the call - ABI compatibility is leveraged. For example:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"This is the constructor of A\n"
]
}
],
"source": [
"%%cpp\n",
"A a;"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}