#!/usr/bin/env python
# coding: utf-8
# # Invoke C++ from Python without bindings thanks to ROOT
#
# 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.
# Let's dive into an example.
#
# The following sources include a class, a function and a template.
#
# ## Header File
# In[1]:
get_ipython().run_cell_magic('python', '', 'code=\'\'\'\n#include \n#include \n\n/// A trivial class\nclass A {\npublic:\n A();\n ~A();\n};\n\n/// A trivial function\nint CountCharacters(const std::string s);\n\n/// A trivial template\ntemplate\nclass B {\npublic:\n B()\n {\n std::cout << "The typeid name of the template argument is " << typeid(T).name() << std::endl;\n }\n};\n\'\'\'\nwith open(\'myLibrary.h\',\'w\') as f_out:\n f_out.write(code)\n')
# ## Implementation
# In[2]:
get_ipython().run_cell_magic('python', '', 'code=\'\'\'\n#include "myLibrary.h" \nA::A()\n{\n std::cout << "This is the constructor of A" << std::endl;\n}\n\nA::~A()\n{\n std::cout << "This is the destructor of A" << std::endl;\n}\n\nint CountCharacters(const std::string s)\n{\n return s.size();\n}\n\'\'\'\nwith open(\'myLibrary.cc\',\'w\') as f_out:\n f_out.write(code)\n')
# ## Creation of the Library
# It's trivial to create a shared object starting from the sources above:
# In[3]:
get_ipython().run_cell_magic('bash', '', 'g++ -o libmyLibrary.so -shared -fPIC myLibrary.cc \n')
# In[4]:
get_ipython().run_cell_magic('bash', '', 'ls *so\n')
# 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).
# ## Interactivity without bindings
# In order to interact with the C++ entities contained in the library, we need to carry out to tasks:
# 1. We need to make known to the interpreter the *interfaces*. Concretely this means including one or more headers.
# 2. We need to make accessible to the interpreter the implementations of such C++ entities. Concretely this means loading the library.
#
# In code:
# In[5]:
import ROOT
ROOT.gInterpreter.ProcessLine('#include "myLibrary.h"')
ROOT.gSystem.Load("./libmyLibrary.so")
# 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!
# In[6]:
a = ROOT.A()
# In[7]:
del a
# In[8]:
b_doublePtr = ROOT.B("double*")()
# 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.
# In[9]:
ROOT.CountCharacters("This interactivity without bindings is really impressive.")
# ## Interactivity within C++
# 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:
# In[10]:
get_ipython().run_cell_magic('cpp', '', 'A a;\n')