{ "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 }