CERN’s (European Organization for Nuclear Research) Root Framework allows one to explore and play with C++ interactively through an interactive C++ interpreter where the user can type and evaluate expressions and commands in a similar way to Python’s REPL.
The Root interpreter, also known as CLING, currently can interpret C++14 and supports mostly U-nix like operating system like Linux or MacOSX and Windows support is still experimental.
Among other things, ROOT has the following features:
- Run C++ code as scripts
- Evaluate C++ code interactively
- Load C libraries such as OpenGL, GNU scientific libraries
- Load header only libraries such as Boost-Libraries
- Data analysis tools and statistical libraries
- Plotting tools
Possible Use-cases:
- Learn C++ faster.
- Exploratory design
- Fast C++ prototyping
- Explore and play with a wide range of C++ libraries
- Test new ideas faster.
- Learn about operating system APIs.
Note:
- CLING is the ROOT’s C++ interpreter distributed in a standalone way without ROOT’s additional plotting and statistical libraries.
GIT Repository:
ROOT Forum:
Download:
- https://root.cern.ch/downloading-root - ROOT framework.
- https://root.cern.ch/downloading-root - CLING - only the C++ interpreter without ROOT’s GUIs, plotting and statistical libraries. CLING can also be embedded on applications.
Demonstration Videos:
- Intro to ROOT Tutorial Lesson 0 - Getting Started
- Cling Interactive OpenGL Demo
- Cling — An Interactive C++ Interpreter - by Dmitri Nesteruk.
- Cling on Ubuntu on Windows - by Dmitri Nesteruk.
- cling C++ interpreter testdrive
Technical Explanations and talks:
- Boostcon: Vassil Vassilev: Interactive, Introspected C++ at CERN - YouTube
- “CERN is the world’s biggest particle physics laboratory. It has to process about 15 PB/year in order to make such scientific breakthroughs. The ROOT Framework’s unique abilities enable physicists to analyse that data with high efficiency, computationally and storage-wise. In the core of ROOT’s newest version is Cling – an interactive C++ interpreter, that targets support of C++11. Cling replaces a previous C++ interpreter that is traditionally the main user interface to ROOT. Cling is built on LLVM/Clang compiler infrastructure. The interpreter is not only used by ROOT to serialize, deserialize and manipulate the C++ OO representation of data, but to help novices learn and understand C++ faster.”
- GoogleTechTalks: Introducing cling, a C++ Interpreter Based on clang/LLVM - YouTube
- Presented by Axel Naumann, CERN. “At CERN, 50 million lines of C++ code are being used by about 10 thousand physicist. Many of them are not programming experts. To make writing C++ more accessible, ROOT (http://root.cern.ch), one of the core tools at CERN, has been using the CINT C++ interpreter for more than 15 years. CINT also opens up a whole new world of dynamic programming: plug-ins, signal/slot, runtime evaluation, reflection. In particular, the latter is fundamental to CERN and its petabytes of Large Hadron Collider data per year, which are created, serialized, and analyzed as C++ objects …”
Compilation Instructions:
# Clone the repository
$ git clone http://github.com/root-project/root.git
# Create build directory for compiling
$ mkdir -p root/build && cd root/build
# Install program at $HOME/opt/cern-root or ~/opt/cern-root
$ cmake .. -Dcxx=17 -Dgviz=OFF -Dhdfs=OFF -Dkrb5=OFF -Dladp=OFF -Dmysql=OFF -Dodbc=OFF \
-Doracle=OFF -Dpgsql=OFF -Dx11=OFF -Dpython=OFF -Dbounjour=OFF \
-DCMAKE_INSTALL_PREFIX=$HOME/opt/cern-root
# Compile with -jN where N is the number of processor cores.
$ make -j4 && make install
# Run ROOT REPL:
$ /home/archbox/opt/cern-root/bin/root.exe
------------------------------------------------------------
| Welcome to ROOT 6.14/04 http://root.cern.ch |
| (c) 1995-2018, The ROOT Team |
| Built for linuxx8664gcc |
| From tags/v6-14-04@v6-14-04, Aug 23 2018, 17:00:44 |
| Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
------------------------------------------------------------
Docker Image:
- DockerFile: https://github.com/mazurov/cern-root
- DockerHub: https://hub.docker.com/r/mazurov/cern-root
Pull docker Image:
$ docker pull mazurov/cern-root
Run Shell:
$ docker run -t -i -a stdout -a stdin mazurov/cern-root
[root@4b6810a8ca0b /]# ls /opt/root/bin/
genreflex rmkdepend rooteventselector setenvwrap.csh
hadd root rootls setxrd.csh
hist2workspace root-config rootmkdir setxrd.sh
memprobe root.exe rootmv ssh2rpd
pq2 rootbrowse rootn.exe thisroot.csh
prepareHistFactory rootcint rootnb.exe thisroot.sh
proofd rootcling rootprint xpdtest
proofexecv rootcp rootrm
proofserv rootd roots
proofserv.exe rootdrawtree roots.exe
[root@4b6810a8ca0b /]#
[root@4b6810a8ca0b /]#
Run ROOT REPL:
$ docker run -t -i -a stdout -a stdin --entrypoint "root.exe" mazurov/cern-root
Session:
------------------------------------------------------------
| Welcome to ROOT 6.09/02 http://root.cern.ch |
| (c) 1995-2016, The ROOT Team |
| Built for linuxx8664gcc |
| From tag v6-09-02, 8 March 2017 |
| Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
------------------------------------------------------------
root [0]
root [0] .q
(base)
root [0] std::cout << "Hello world C++11" << "\n";
Hello world C++11
root [1]
Mount disk directory on docker image
$ docker run -it --rm -w /user -v $(pwd):/user --entrypoint="root.exe" mazurov/cern-root
Commands:
- -w /user
- Set Docker current directory to user
- -v $(pwd):/user
- Mount current disk directory into the directory /user in the Docker image.
- –entrypoint=”/opt/root/bin/root.exe”
- Set entry point to ROOT REPL.
Session Example:
$ docker run -it --rm -w /user -v $(pwd):/user --entrypoint="root.exe" mazurov/cern-root
root [5] .! ls
arraysFun.cpp object-lifecycle.cpp
assert.cpp operator-overload1.bin
basic-io.cpp operator-overload1.cpp
boost operator-overload2.bin
cpp-functor.cpp operator-overload2.cpp
... ... ... ... ... ... ... ... ... ... ... ...
# Load File and run function main()
root [6] .L numeric-limits.cpp
root [7]
root [7] main()
Numeric limits for type: bool
------------------------------------------------------------
Type: bool
Is integer: true
Is signed: false
Number of digits 10: 0
Max Number of digits 10: 0
Min Abs: 0
Min: 0
Max: 1
Size in bytes: 1
Size in bits: 8
... ... ... ... ... ... ... ...
Bash Function for usage simplification:
function docker-run(){
DIMAGE="$1"
if [ -n "$2" ] ; then
ENTRYPOINT="$2"
else
ENTRYPOINT="/bin/sh"
fi
docker run -it --rm -w /user -v $(pwd):/user --entrypoint $ENTRYPOINT $DIMAGE
}
# Run shell (default entry-point)
$ docker-run mazurov/cern-root
# Run root.exe entry-point of Docker image (mazurov/cern-root)
$ docker-run mazurov/cern-root root.exe
Set environment variables:
- Add this piece of code to any of those configuration files:
~/.profile,
~/.bash_profile
or ~/.bashrc.
# Set root directory (ROOTSYS) to the path where it was installed
export ROOTSYS=$HOME/opt/root
# DO NOT change those variables below
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ROOTSYS/lib
export PATH=$PATH:$ROOTSYS/bin
alias cern-root="$ROOTSYS/bin/root -l"
Questions about configuration files:
- Basic ROOT start-up guide | Insectnation
- RootTalk: Re: ROOT .rootrc, etc.
- Setting .include path in .rootrc file? - ROOT - ROOT Forum
Current install:
$ which root
/home/archbox/opt/root/bin/root
$ pwd
/home/archbox/opt/root
archbox@localhost 16:10 ~/opt/root
$ tree -L 1 .
.
├── aclocal
├── bin
├── cmake
├── config
├── emacs
├── etc
├── fonts
├── geom
├── icons
├── include
├── lib
├── LICENSE
├── macros
├── man
├── README
├── test
├── tmva
└── tutorials
17 directories, 1 file
Show tools available:
$ tree -L 1 bin/
bin/
├── g2root
├── genreflex
├── h2root
├── hadd
├── hist2workspace
├── memprobe
├── pq2
├── prepareHistFactory
├── proofd
├── proofexecv
├── proofserv
├── proofserv.exe
├── rmkdepend
├── root
├── rootbrowse
├── rootcint
├── rootcling
├── root-config
├── rootcp
├── rootd
├── rootdrawtree
├── rooteventselector
├── root.exe
├── rootls
├── rootmkdir
├── rootmv
├── rootnb.exe
├── rootn.exe
├── rootprint
├── rootrm
├── roots
├── roots.exe
├── rootslimtree
├── setenvwrap.csh
├── setxrd.csh
├── setxrd.sh
├── ssh2rpd
├── thisroot.csh
├── thisroot.sh
├── xpdtest
└── xproofd
0 directories, 41 files
REPL Command | Description |
---|---|
.? | Show help |
.q | Exit ROOT shell |
.L file.cpp | Load file.cpp, so it loads all the file’s classes and functions |
.x script.cxx | Load and execute ROOT script or C++ ordinary source code. The entry point is void script() |
.include | Show include path |
.I <include path> | Add include path to search for header files (*.h), for instance .I usr/include/qt5 |
.! <shell command> | Run shell command such as ls on Unix. |
.class TFile | Show all methods and fields of the class TFile |
Documentation:
- Source Code Documentation: https://root.cern/doc/v612/files.html
GSystem object:
gSystem->AddLinkedLibs (...)
gSystem->AddIncludePath(...)
gROOT->GetListOfClasses()
gROOT->GetListOfColors()
gROOT->GetListOfTypes()
gROOT->GetListOfGlobals()
gROOT->GetListOfGlobalFunctions()
gROOT->GetListOfFiles()
gROOT->GetListOfMappedFiles()
gROOT->GetListOfSockets()
gROOT->GetListOfCanvases()
gROOT->GetListOfStyles()
gROOT->GetListOfFunctions()
gROOT->GetListOfSpecials()
gROOT->GetListOfGeometries()
gROOT->GetListOfBrowsers()
gROOT->GetListOfMessageHandlers()
Get Version:
root [20] gROOT->GetVersion()
(const char *) "6.14/04"
root [21]
Get and Set Prompt:
root [0] static_cast<TRint*>(gROOT->GetApplication())->GetPrompt()
(char *) "root [1] "
root [1]
root [1] static_cast<TRint*>(gROOT->GetApplication())->SetPrompt(">> ")
(const char *) "root [%d] "
>>
>>
Change and check current working directory.
root [30] gSystem->cd("/home/archbox")
(bool) true
root [31] gSystem->pwd()
(const char *) "/home/archbox"
root [32]
root [32]
Get environment variables:
root [32] gSystem->Getenv("HOME")
(const char *) "/home/archbox"
root [33] gSystem->Getenv("PATH")
(const char *) "/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:..."
Add Include Path:
– Ref: Setting .include path in .rootrc file? - ROOT - ROOT Forum
gSystem->SetIncludePath(" -Imyincludepath1 ");
gSystem->SetIncludePath(" -Imyincludepath2 ");
...
Eval String:
root [0] gROOT->ProcessLine("std::cout << \"Hello world\" << std::endl;");
Hello world
root [1]
root [2] gROOT->ProcessLine("cos(M_PI)");
(double) -1.0000000
root [3] gROOT->ProcessLine("cos(2 * M_PI)");
(double) 1.0000000
root [4]
Print configuration:
- Command: gEnv->Print()
Root [5] gEnv->Print()
Unix.*.Root.UseTTFonts: true [Global]
WinNT.UseNetAPI: true [Global]
Unix.*.Root.UseThreads: false [Global]
Root.CompressionAlgorithm: 0 [Global]
Root.ShowPath: false [Global]
Root.TMemStat: 0 [Global]
Root.TMemStat.buffersize: 100000 [Global]
Root.TMemStat.maxcalls: 5000000 [Global]
Root.TMemStat.system: [Global]
Root.MemStat: 0 [Global]
Root.MemStat.size: -1 [Global]
Root.MemStat.cnt: -1 [Global]
Root.ObjectStat: 0 [Global]
Root.MemCheck: 0 [Global]
$ $HOME/opt/root/bin/root
ERROR in cling::CIFactory::createCI(): cannot extract standard library include paths!
Invoking:
LC_ALL=C ccache -O3 -DNDEBUG -xc++ -E -v /dev/null 2>&1 >/dev/null | awk '/^#include </,/^End of search/{if (!/^#include </ && !/^End of search/){ print }}' | GREP_OPTIONS= grep -E "(c|g)\+\+"
Results was:
With exit code 256
------------------------------------------------------------
| Welcome to ROOT 6.14/04 http://root.cern.ch |
| (c) 1995-2018, The ROOT Team |
| Built for linuxx8664gcc |
| From tags/v6-14-04@v6-14-04, Aug 23 2018, 17:00:44 |
| Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
------------------------------------------------------------
root [0]
root [66] .! ls
a.out clang1.cpp clang-start.bin myclass.cpp testclang.bin
cashFlowApp.cpp clangcpp1.bin clang-start.cpp myclass.hpp testclang.cpp
cashflow.cpp clangcpp1.cpp diagnostics.bin numLimits.cpp testcl.bin
cashflow.h clanger.bin diagnostics.cpp printHeaders.cpp testcl.cpp
cashflow.so clanger.c dump-classes.cpp source-info.bin
clang1.bin clanger.cpp libcashflow.cpp source-info.cpp
root [67]
root [67] .! pwd
/home/archbox/shared/reflection-root
root [68]
root [5] M_PI
(double) 3.1415927
root [6] M_E
(double) 2.7182818
root [7]
root [7] // Predefined math constants in the header cmath
root [8] M_E
(double) 2.7182818
root [9] M_PI
(double) 3.1415927
root [10] M_LOG10E // Logarithm to base 2 of E
(double) 0.43429448
root [11] M_LN10 // Natural log of 10
(double) 2.3025851
root [12] M_PI_4 // PI divided by 4 or PI/4
(double) 0.78539816
root [13] M_2_PI // 2 * PI or 360 deg
(double) 0.63661977
root [14] M_SQRT2 // Square root of 2
(double) 1.4142136
root [15] M_SQRT1_2
(double) 0.70710678
root [16]
root [20] std::cout << "Hello world" << std::endl;
Hello world
root [21]
root [21] for(int i = 0 ; i < 10; i++){ std::cout << "i = " << i << std::endl; }
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
// To paste a multi line code, paste the code between brackets
// To paste a multi line code, paste the code between brackets
{
auto func = [](double x){
return x * x - 4 * x + 10;
};
}
root [38] func(4.0)
(double) 10.000000
root [39]
root [39] func(0)
(double) 10.000000
root [40] func(3)
(double) 7.0000000
root [41] func(5)
(double) 15.000000
root [42] func(10)
(double) 70.000000
root [43]
root [47] std::vector<double> ys {10.0, 3.0, 5.0, 6.0, 10.0, 20.0}
(std::vector<double> &) { 10.000000, 3.0000000, 5.0000000, 6.0000000, 10.000000, 20.000000 }
root [48]
root [48] ys.size()
(unsigned long) 6
root [49] ys.max_size()
(unsigned long) 2305843009213693951
root [50] ys[0]
(double) 10.000000
root [51] ys[1]
(double) 3.0000000
root [52] ys[2]
(double) 5.0000000
root [53] ys.at(0)
(double) 10.000000
root [54] ys.at(1)
(double) 3.0000000
root [55] ys.at(2)
(double) 5.0000000
root [56] ys.at(100)
Error in <TRint::HandleTermInput()>: std::out_of_range caught: vector::_M_range_check: __n (which is 100) >= this->size() (which is 6)
root [57]
root [58] ys.push_back(5)
root [59] ys
(std::vector<double> &) { 10.000000, 3.0000000, 5.0000000, 6.0000000, 10.000000, 20.000000, 5.0000000 }
root [60]
root [71] std::deque<double> d;
root [72] d
(std::deque<double> &) {}
root [73] d. // Type tab to complete
assign
at
back
begin
cbegin
cend
clear
crbegin
crend
... ...
root [73] d.push_back(10.0)
root [74] d.push_back(3.0)
root [75] d.push_back(5.0)
root [76] d
(std::deque<double> &) { 10.000000, 3.0000000, 5.0000000 }
root [77]
root [83] std::cout << std::fixed << std::setprecision(2)
(std::basic_ostream<char, std::char_traits<char> > &) @0x7fe94fd0ae20
root [84]
// C++ 11 For-range based loop
root [89] for(const auto& x: d){ std::cout << x << std::endl; }
10.00
6.00
10.00
3.00
5.00
root [90]
root [88] for(const auto& x: d){ std::cout << std::right << std::setw(10) << x << std::end
10.00
6.00
10.00
3.00
5.00
root [89]
// Clear
root [97] d.clear()
root [98] d
(std::deque<double> &) {}
root [99]
STL Map (dictionary, hash map) container:
// Create a map container with uniform initialization
root [1] std::map<std::string, double> constants {{"pi", 3.1415}, {"earth_gravity", 9.81},(std::map<std::string, double> &)
{ "earth_gravity" => 9.8100000, "pi" => 3.1415000, "sqrt_2" => 1.4170000 }
root [2]
root [2]
root [5] constants["earth_gravity"]
(double) 9.8100000
root [6]
root [6] constants.at("earth_gravity")
(double) 9.8100000
// Generate exception
root [7] constants.at("pi")
(double) 3.1415000
root [8] constants.at("pix")
Error in <TRint::HandleTermInput()>: std::out_of_range caught: map::at
root [9]
root [9] constants.size()
(unsigned long) 4
root [10]
root [10]
root [11] constants.clear()
root [12]
root [12] constants
(std::map<std::string, double> &) {}
root [13]
root [15] constants.insert(std::pair<std::string, double>("pi", 3.1415))
root [17] constants.insert(std::pair<std::string, double>("x", 10.0))
root [18] constants
(std::map<std::string, double> &) { "pi" => 3.1415000, "x" => 10.000000 }
root [19]
{
for(const auto& x: constants){
cout << "key = " << std::setw(4) << x.first << std::setw(10)
<< "value = " << x.second << endl;
}
}
// Output
key = pi value = 3.1415
key = x value = 10
ROOT Cling can also play with C++ classes as they were ordinary scripts.
File: CashFlow.cpp
#include <iostream>
#include <vector>
#include <initializer_list>
#include <iomanip> // setw, setpreicision ...
class CashFlow{
private:
std::vector<double> m_pmt;
public:
// Default constructor - doesn't
CashFlow(){}
// Overloaded contructor with vector
CashFlow(std::vector<double> pmt){
m_pmt.insert(m_pmt.begin(), pmt.begin(), pmt.end());
}
// Overloaded constructor with initializer list
CashFlow(std::initializer_list<double> pmt){
m_pmt.insert(m_pmt.begin(), pmt.begin(), pmt.end());
}
CashFlow& add(double x){
m_pmt.push_back(x);
return *this;
}
void show(){
int i = 0;
for(const auto& x: m_pmt){
std::cout << std::setw(10) << i
<< std::setw(10) << std::setprecision(3) << std::fixed << x
<< std::endl;
++i;
}
}
};
In the ROOT shell:
root [0] .L CashFlow.cpp
root [1] CashFlow clf;
root [2] clf.show()
root [3] clf.add(-30).add(20).add(4).add(5).add(25)
(CashFlow &) @0x7fa4df246010
root [4] clf.show()
0 -30.000
1 20.000
2 4.000
3 5.000
4 25.000
root [6]
root [6] CashFlow clf2 {-30.0, 20.0, 3.0, 5.0, 25.0} ;
root [7] clf2.show()
0 -30.000
1 20.000
2 3.000
3 5.000
4 25.000
root [8]
ROOT Session:
root [0] .L linfun.cpp
root [1]
root [1] LinearFunction lfun1(3.0, 4.0)
(LinearFunction &) @0x7fac4d729010
root [2] lfun1
(LinearFunction &) @0x7fac4d729010
root [3] std::cout << lfun1 << std::endl;
y(x) = 3.000 * x + 4.000
root [4]
root [4] lfun1(3.0)
(double) 13.000000
root [5] lfun1(0)
(double) 4.0000000
root [6] lfun1(5)
(double) 19.000000
root [7] lfun1(10)
(double) 34.000000
root [8] lfun1.setCoeffs(5.0, 10.0);
root [9]
root [9] std::cout << lfun1 << std::endl;
y(x) = 5.000 * x + 10.000
root [10]
root [10] std::vector<double> xs{3.0, 4.0, 5.0, 6.0, 5.0};
root [11]
root [11] xs
(std::vector<double> &) { 3.0000000, 4.0000000, 5.0000000, 6.0000000, 5.0000000 }
root [12]
root [12] lfun1(xs)
(std::vector<double>) { 25.000000, 30.000000, 35.000000, 40.000000, 35.000000 }
root [13]
root [13] auto lfun2 = LinearFunction::fromPoints(2, 9, 8 , 21);
root [14] std::cout << lfun2 << std::endl;
y(x) = 2.000 * x + 5.000
root [15]
root [15] lfun2(3.0)
(double) 11.000000
root [16] lfun2(4.0)
(double) 13.000000
root [17] lfun2(5.0)
(double) 15.000000
root [18]
File: linfun.cpp
class LinearFunction{
public:
LinearFunction(double a, double b): A(a), B(b) {}
/* Named constructor, aka static factory method*/
static LinearFunction fromCoeffs(double a, double b){
return LinearFunction(a, b);
}
/* Named constructor, aka static factory method*/
static LinearFunction fromPoints(double x1, double y1, double x2, double y2){
double a = (y2 - y1)/(x2 - x1);
double b = y1 - a * x1;
return LinearFunction(a, b);
}
double eval(double x){
return A * x + B;
}
// Function-call-operator overload
// Using the New C++11 return type
// It could also be:
// >> double operator()(double x){ ...
auto operator()(double x) -> double{
return A * x + B;
}
// Function-call-operator overload
std::vector<double> operator()(const std::vector<double>& xs){
std::vector<double> res;
for(auto& x: xs){
res.push_back(A * x + B);
}
return res;
}
void setCoeffs(double A, double B){
this->A = A;
this->B = B;
}
void setA(double a){
A = a;
}
void setB(double b){
B = b;
}
// The stream insertion operator (<<) is not a method
// (member function) of this class. It is a overload of
// the operator (<<) for the class std::ostream which is
// a generic output stream.
friend std::ostream& operator<<(std::ostream &os, const LinearFunction& lfun){
os.precision(3);
os.setf(std::ios::fixed);
os << "y(x) = " << lfun.A << " * x" << " + " << lfun.B;
return os;
}
private:
double A;
double B;
}; //---- End of object LinearFunction --- //
/** Makes the vector printable, similar to implementing vector.toString in Java */
std::ostream& operator << (std::ostream &os, const std::vector<double>& xs){
os << "[" << xs.size() << "](" ;
copy(xs.begin(), xs.end(), std::ostream_iterator<double>(os, " "));
os << ")";
return os;
}
To load the following code, just copy and then paste it in the ROOT REPL.
// Type synonym to avoid repeating it.
// Equivalent to typedef std::function<double (double)> MathFun
using MathFun = std::function<double (double)>;
/** Higher order function to tabulate ordinary function
* The first parameter can be a ordinary lambda function or
* a any function object implementing double operator()(double x)
* or operator()(double) => double Using Scala's notation.
*/
void tabulate(
std::function<double (double)> fn,
double start,
double stop,
double step,
std::ostream& os = std::cout
){
os.precision(3);
os.flags(std::ios::fixed);
os << std::setw(10) << "Input" << std::setw(10) << "Output" << std::endl;
double x = start;
while(x <= stop){
os << std::setw(10) << x << std::setw(10) << fn(x) << std::endl;
x = x + step;
}
}
Running:
root [40] tabulate([](double x){ return sqrt(x);}, -4.0, 9.0, 1.0)
Input Output
-4.000 -nan
-3.000 -nan
-2.000 -nan
-1.000 -nan
0.000 0.000
1.000 1.000
2.000 1.414
3.000 1.732
4.000 2.000
5.000 2.236
6.000 2.449
7.000 2.646
8.000 2.828
9.000 3.000
root [41]
MathFun makeLinFun(double a, double b) {
// [=] means -> capture a and b by value
return [=](double x){return a * x + b; };
}
root [70] tabulate(makeLinFun(10.0, 5.0), -5, 5, 1)
Input Output
-5.000 -45.000
-4.000 -35.000
-3.000 -25.000
-2.000 -15.000
-1.000 -5.000
0.000 5.000
1.000 15.000
2.000 25.000
3.000 35.000
4.000 45.000
5.000 55.000
root [71]
Required headers: <iostram> and <algorithm> (std::for_each
)
- C Arrays
root [0] double xs [] = {10.0, 5.0, 6.0, 3.0}
(double [4]) { 10.000000, 5.0000000, 6.0000000, 3.0000000 }
root [1]
root [1] std::for_each(xs, xs + 4, [](double x){ std::cout << sqrt(x) << " " << '\n' << std::flush;} );
3.16228
2.23607
2.44949
1.73205
root [2]
- C++ Vectors
root [0] std::vector<double> vec { 10.0, 3.0, 5.0, 2.0, -6.0} ;
root [1] xs
root [3] std::for_each(vec.begin(), vec.end(), [](double x){ std::cout << sqrt(x) << std::endl;})
3.16228
1.73205
2.23607
1.41421
-nan
((lambda)) @0x1a42030
root [4] std::for_each(vec.begin(), vec.end(), [](double x){ std::cout << sqrt(x) << std::endl;});
3.16228
1.73205
2.23607
1.41421
-nan
Paste the following code in the ROOT interpreter.
{
// Headers: <iostream>, <fstream>, <stdlib.h>
void showFile(const char* file){
std::ifstream fin;
std::string line;
fin.open(file);
if(fin.fail()){
std::cerr << "Error: file " << file << " cannot be opened.";
exit(-1);
}
while(!fin.eof()){
std::getline(fin, line);
std::cout << line << std::endl;
}
fin.close();
}
}
Run:
root [24] showFile("/etc/protocols")
# /etc/protocols:
# $Id: protocols,v 1.12 2016/07/08 12:27 ovasik Exp $
#
# Internet (IP) protocols
#
# from: @(#)protocols 5.1 (Berkeley) 4/17/89
#
# Updated for NetBSD based on RFC 1340, Assigned Numbers (July 1992).
# Last IANA update included dated 2011-05-03
#
# See also http://www.iana.org/assignments/protocol-numbers
ip 0 IP # internet protocol, pseudo protocol number
hopopt 0 HOPOPT # hop-by-hop options for ipv6
icmp 1 ICMP # internet control message protocol
igmp 2 IGMP # internet group management protocol
ggp 3 GGP # gateway-gateway protocol
ipv4 4 IPv4 # IPv4 encapsulation
... ... ... ... ... ... ... ... ... ... ... ...
It assumes that the boost libraries are already installed.
- Example: Using Boost special math functions
root [0] #include <boost/math/special_functions/erf.hpp>
root [1] boost::math::erf
root [2] boost::math::erf(0.1)
(double) 0.11246292
root [3]
root [3] boost::math::erf(2.0)
(double) 0.99532227
root [4] boost::math::erf(3.0)
(double) 0.99997791
root [9] using boost::math::erf;
root [10]
root [10] erf(1.2)
(double) 0.91031398
root [11] erf(4.5)
(double) 1.0000000
root [12]
Note: the command #pragma cling load(“/lib64/libgslcblas.so.0”) is used to load the symbols from the shared library libgslcblas.so.
root [1] #pragma cling load("/lib64/libgslcblas.so.0")
root [2]
root [2] #pragma cling load("/lib64/libgsl.so")
root [3]
root [3] #include <gsl/gsl_errno.h>
root [4] #include <gsl/gsl_sf_bessel.h>
root [5]
root [5] gsl_sf_bessel_J0(4.0)
(double) -0.39714981
root [6] gsl_sf_bessel_J0(5.0)
(double) -0.17759677
root [7]
{
double x = 5.0;
double expected = -0.17759677131433830434739701;
double y = gsl_sf_bessel_J0 (x);
printf ("J0(5.0) = %.18f\n", y);
printf ("exact = %.18f\n", expected);
}
// Output:
J0(5.0) = -0.177596771314338264
exact = -0.177596771314338292
root [14]
Complete script using (#prgram cling load) to load the shared libraries command:
#include <gsl/gsl_errno.h>
#include <gsl/gsl_sf_bessel.h>
#pragma cling load("/lib64/libgslcblas.so.0")
#pragma cling load("/lib64/libgsl.so")
gsl_sf_bessel_J0(4.0);
gsl_sf_bessel_J0(5.0);
double x = 5.0;
double expected = -0.17759677131433830434739701;
double y = gsl_sf_bessel_J0 (x);
printf ("J0(5.0) = %.18f\n", y);
printf ("exact = %.18f\n", expected);
Complete script using gSystem->Load to add load libraries:
#include <gsl/gsl_errno.h>
#include <gsl/gsl_sf_bessel.h>
gSystem->Load("/lib64/libgslcblas.so.0");
gSystem->Load("/lib64/libgsl.so");
gsl_sf_bessel_J0(4.0);
gsl_sf_bessel_J0(5.0);
double x = 5.0;
double expected = -0.17759677131433830434739701;
double y = gsl_sf_bessel_J0 (x);
printf ("J0(5.0) = %.18f\n", y);
printf ("exact = %.18f\n", expected);
Complete script using gSystem->AddLinkedLibs to load shared libraries:
#include <gsl/gsl_errno.h>
#include <gsl/gsl_sf_bessel.h>
gSystem->AddLinkedLibs("-lgsl -lgslcblas");
// gSystem->AddLinkedLibs("-lgsl");
// gSystem->AddLinkedLibs("-lgslcblas");
gsl_sf_bessel_J0(4.0);
gsl_sf_bessel_J0(5.0);
double x = 5.0;
double expected = -0.17759677131433830434739701;
double y = gsl_sf_bessel_J0 (x);
printf ("J0(5.0) = %.18f\n", y);
printf ("exact = %.18f\n", expected);
Get current working directory of current process:
#include <unistd.h>
root [10] getcwd(nullptr, 0)
(char *) "/home/archbox/shared/reflection-root"
root [11]
root [7] std::string current_dir = getcwd(nullptr, 0)
(std::string &) "/home/archbox/shared/reflection-root"
root [8] current_dir
(std::string &) "/home/archbox/shared/reflection-root"
root [9] std::cout << "Current directory = " << current_dir << std::endl;
Current directory = /home/archbox/shared/reflection-root
Set current working directory of current process:
oot [15]
root [15] getcwd(nullptr, 0)
(char *) "/etc"
root [16]
root [16] chdir("/usr/include")
(int) 0
root [17] getcwd(nullptr, 0)
(char *) "/usr/include"
root [18] chdir("/usr/includeError")
(int) -1
root [19] getcwd(nullptr, 0)
(char *) "/usr/include"
root [20]
Documentation:
root [9] #include <stdlib.h>
root [10] #include <limits.h>
root [11] #include <unistd.h>
root [12] #include <sys/stat.h>
root [13]
root [14] mkdir("/home/archbox/Desktop/mydir", 0777)
(int) 0
root [15]
root [15] mkdir("/home/archbox/Desktop/mydir", 0777)
(int) -1
root [16]
// #include <string>
#include <sys/types.h>
#include <dirent.h> // Get function opendir
#include <errno.h>
void listDirectory(const std::string& path){
DIR *dir;
struct dirent *dp;
dir = opendir(path.c_str()) ;
// To determine the cause of error - It is necessary to check the error code.
if (dir == NULL)
throw std::runtime_error("Error: Cannot read directory");
while ((dp = readdir(dir)) != NULL) {
std::cout << dp->d_name << std::endl ;
};
closedir(dir);
}
Running in root REPL:
root [37] listDirectory("/")
etc
tmp
sbin
sys
opt
media
.
boot
.local
.autorelabel
home
var
dev
.. ... ...
root [39] listDirectory("/boot/grub")
.
splash.xpm.gz
..
root [40]
root [40]
root [40] listDirectory("/boot/grub/dsafa")
Error in <TRint::HandleTermInput()>: std::runtime_error caught: Error: Cannot read directory
root [41]
root [41]
// Copy and paste this code in the ROOT REPL
{
FILE* fp = popen("ls -l /", "r");
char ch;
std::stringstream ss;
if(!fp)
std::cerr << "Error: could not open process output." << std::endl;
while((ch = fgetc(fp)) != EOF){
ss << ch;
}
pclose(fp);
std::cout << "Output = " << '\n' << ss.str() << std::flush;
}
// Ouptut:
Output:
Output =
total 64
lrwxrwxrwx. 1 root root 7 Feb 10 2017 bin -> usr/bin
dr-xr-xr-x. 7 root root 4096 Jul 15 15:58 boot
drwxr-xr-x 23 root root 4220 Sep 8 17:47 dev
drwxr-xr-x. 169 root root 12288 Sep 10 03:27 etc
drwxr-xr-x. 5 root root 4096 Mar 2 2018 home
lrwxrwxrwx. 1 root root 7 Feb 10 2017 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Feb 10 2017 lib64 -> usr/lib64
drwx------. 2 root root 16384 Sep 17 2017 lost+found
drwxr-xr-x. 2 root root 4096 Feb 10 2017 media
drwxr-xr-x. 2 root root 4096 Feb 10 2017 mnt
... .... ... .... ... .... ... .... ... ....
This unnamed script can be encapsulate into a function:
std::string getProcessOutput(std::string command){
FILE* fp = popen(command.c_str(), "r");
char ch;
std::stringstream ss;
if(!fp)
std::cerr << "Error: could not open process output." << std::endl;
while((ch = fgetc(fp)) != EOF){
ss << ch;
}
pclose(fp);
return ss.str();
}
root [14] getProcessOutput("date")
(std::string) "Mon Sep 10 16:46:06 -03 2018
"
root [15] getProcessOutput("uname -a")
(std::string) "Linux localhost.localdomain 4.16.11-100.fc26.x86_64 #1 SMP Tue May 22 20:02:12 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
"
root [16]
File: ublas.C
#include <iostream>
#include <string>
// Headers for vectors
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
// Headers for Matrix
#include <boost/numeric/ublas/matrix.hpp>
namespace ub = boost::numeric::ublas;
template<class T>
void printVal(const std::string &name, const T &value){
std::cout << name << " = " << value << std::endl;
}
void printSection(const std::string &descr){
std::cout << descr << std::endl;
for(int i = 0; i < descr.size(); i++){
std::cout << '-';
}
std::cout << std::endl;
}
void vecOperation1(){
ub::vector<double> vec1(5, 1.0);
printVal("vec1", vec1);
vec1[1] = 2.4;
vec1[2] = 3.5;
vec1[3] = -5.0;
printVal("vec1", vec1);
printVal("sum(vec1)", sum(vec1));
printVal("norm_1(vec1)", norm_1(vec1));
printVal("norm_2(vec1)", norm_2(vec1));
printVal("norm_inf(vec1)", norm_inf(vec1));
printVal("index_norm_inf(vec1)", index_norm_inf(vec1));
}
void vecOperation2(){
ub::vector<double> vec1(3, 2.2) ; vec1[2] = -5.1;
ub::vector<double> vec2(3, -1.2); vec2[2] = 1.1;
double factor = 2.5;
printVal("vec1", vec1);
printVal("vec1.size()", vec1.size());
printVal("vec2", vec2);
printVal("vec2.size()", vec2.size());
printVal("inner_prod(vec1, vec2)", inner_prod(vec1, vec2));
printVal("vec1 + vec2", vec1 + vec2);
printVal("vec1 - vec2", vec1 - vec2);
printVal("vec1 * factor", vec1 * factor);
printVal("vec1 / factor", vec1 / factor);
}
void matrixOperation1(){
ub::matrix<double> matrix1(3, 3, 2.5);
matrix1(0, 0) = matrix1(2, 2) = 1.0;
matrix1(0, 2) = -3.5; matrix1(2, 0) = 5.9;
printVal("matrix1 ", matrix1);
printVal("Num of rows ", matrix1.size1());
printVal("Num of cols ", matrix1.size2());
printVal("Transpose ", trans(matrix1));
printVal("Real part ", real(matrix1));
matrix1.resize(4, 4);
printVal("Matrix resized = matrix1.resize(4, 4)", matrix1);
printVal("identity_matrix<double>(3)", ub::identity_matrix<double>(3));
printVal("zero_matrix<double>(3)", ub::zero_matrix<double>(3));
}
// SCRIPT Entry-point - must have the same name as the file.
void ublas(){
printSection("Running vecOperation1");
vecOperation1();
std::cout << std::endl;
printSection("Running vecOperation2");
vecOperation2();
std::cout << std::endl;
printSection("Running matrixOperation1");
matrixOperation1();
}
Running in batch mode:
$ $HOME/opt/root/bin/root -l -q ublas.C
ERROR in cling::CIFactory::createCI(): cannot extract standard library include paths!
Invoking:
LC_ALL=C ccache -O3 -DNDEBUG -xc++ -E -v /dev/null 2>&1 >/dev/null | awk '/^#include </,/^End of search/{if (!/^#include </ && !/^End of search/){ print }}' | GREP_OPTIONS= grep -E "(c|g)\+\+"
Results was:
With exit code 256
Processing ublas.C...
Running vecOperation1
---------------------
vec1 = [5](1,1,1,1,1)
vec1 = [5](1,2.4,3.5,-5,1)
sum(vec1) = 2.9
norm_1(vec1) = 12.9
norm_2(vec1) = 6.70895
norm_inf(vec1) = 5
index_norm_inf(vec1) = 3
Running vecOperation2
---------------------
vec1 = [3](2.2,2.2,-5.1)
vec1.size() = 3
vec2 = [3](-1.2,-1.2,1.1)
vec2.size() = 3
inner_prod(vec1, vec2) = -10.89
vec1 + vec2 = [3](1,1,-4)
vec1 - vec2 = [3](3.4,3.4,-6.2)
vec1 * factor = [3](5.5,5.5,-12.75)
vec1 / factor = [3](0.88,0.88,-2.04)
Running matrixOperation1
------------------------
matrix1 = [3,3]((1,2.5,-3.5),(2.5,2.5,2.5),(5.9,2.5,1))
Num of rows = 3
Num of cols = 3
Transpose = [3,3]((1,2.5,5.9),(2.5,2.5,2.5),(-3.5,2.5,1))
Real part = [3,3]((1,2.5,-3.5),(2.5,2.5,2.5),(5.9,2.5,1))
Matrix resized = matrix1.resize(4, 4) = [4,4]((1,2.5,-3.5,2.93415e+59),(2.5,2.5,2.5,1.10542e+161),(5.9,2.5,1,9.83212e-72),(1.41746e+190,5.16752e+25,6.32283e+233,6.94321e-307))
identity_matrix<double>(3) = [3,3]((1,0,0),(0,1,0),(0,0,1))
zero_matrix<double>(3) = [3,3]((0,0,0),(0,0,0),(0,0,0))
File: script1.C
/**
* Reference:
* + https://root-forum.cern.ch/t/loading-a-library-from-a-script/24306
**/
#include <iostream>
#include <iomanip>
#include <functional>
#include <cmath>
#include <ostream>
// Install GNU Scientific Library on Fedora with:
// $ sudo dnf install gsl-devel.x86_64
#include <gsl/gsl_sf_bessel.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_roots.h>
// Load Shared libraries needed by the script
#ifdef __CLING__
R__LOAD_LIBRARY(/lib64/libgslcblas.so.0);
R__LOAD_LIBRARY(/lib64/libgsl.so);
#endif
namespace GSL{
using MFun = std::function<double (double)>;
double wrapLambda(double x, void* param){
auto fp = static_cast<MFun*>(param);
return fp->operator()(x);
}
/**
* Note: In order to to not throw the error: <ERROR: endpoints do not straddle y=0>
* mf(xa) * mf(xb) < 0 the function must have opposite signals at the interval bounds.
*/
double rootSolverBracket(
// gsl_root_fsolver_type* solvertype,
MFun mf,
double xa,
double xb,
int maxIteratiosn = 100,
double tol = 1e-5
){
gsl_function fnt;
fnt.function = wrapLambda;
fnt.params = &mf;
gsl_root_fsolver *solver;
solver = gsl_root_fsolver_alloc(gsl_root_fsolver_bisection);
//solver = gsl_root_fsolver_alloc(solvertype);
// dbgtrace("Setting solver");
gsl_root_fsolver_set(solver, &fnt, xa, xb);
// dbgtrace("Solver set OK");
// gsl_root_fsolver_iterate(solver);
// dbgtrace("Solver initial iteration OK");
int status = GSL_CONTINUE;
int i = 0;
double root;
double xlo, xhi;
// dbgtrace("In the solver loop");
while(i <= maxIteratiosn && status == GSL_CONTINUE){
// dbgtrace("Iterating solver");
status = gsl_root_fsolver_iterate(solver);
// disp(status);
if(status != GSL_SUCCESS)
break;
root = gsl_root_fsolver_root(solver);
// disp(root);
xlo = gsl_root_fsolver_x_lower(solver);
xhi = gsl_root_fsolver_x_upper(solver);
status = gsl_root_test_interval(xlo, xhi, 0, tol);
// if(status == GSL_SUCCESS)
// std::cerr << "Converged" << std::endl;
i++;
}
gsl_root_fsolver_free(solver);
if(status == GSL_SUCCESS)
return root;
else
return std::numeric_limits<double>::signaling_NaN();;
return 0;
}
}
/** Equation "functor" - function-object */
struct EquationTest{
double A;
double B;
EquationTest(double a, double b): A(a), B(b) {};
/* Computes: A * x^2 - B * sin(x) */
double operator()(double x){
return A * x * x * x - B * sin(x);
}
};
/** Script entry-point should have the same name as the file. */
void script1(){
if(__cplusplus >= 201703L)
std::cout << "Running C++17" << "\n";
else if(__cplusplus >= 201402L)
std::cout << "Running C++14" << "\n";
else if(__cplusplus >= 201103L)
std::cout << "Running C++11" << "\n";
std::cout << "Running a C++ script in the ROOT REPL. " << "\n";
std::cout << " gsl_sf_bessel_J0(4.0) = "
<< gsl_sf_bessel_J0(4.0) << "\n";
double root = GSL::rootSolverBracket(
// gsl_root_fsolver_bisection,
[](double x){ return x * x - 25.0 ;}
, -4, +10, 200
);
std::cout << "Root of equation x^2 - 25.0 = " << root << "\n";
auto eqn = EquationTest(1.0, 4.0);
double root2 = GSL::rootSolverBracket(eqn, -10, +5, 200);
std::cout << "Root of equation x^3 - 4 * sin(x) = " << root2 << "\n";
} //--- End of script1 ---//
/** Main was added to allow compiling the script */
int main(){
script1();
return 0;
}
To run the script in the ROOT/CLING REPL use:
$ root
>> .x script1.C
Running C++11
Running a C++ script in the ROOT REPL.
gsl_sf_bessel_J0(4.0) = -0.39715
Root of equation x^2 - 25.0 = 5.00001
Root of equation x^3 - 4 * sin(x) = 1.58732
>>
Load the script, play and prototype with it.
>> .L script1.C
>>
>> script1()
Running C++11
Running a C++ script in the ROOT REPL.
gsl_sf_bessel_J0(4.0) = -0.39715
Root of equation x^2 - 25.0 = 5.00001
Root of equation x^3 - 4 * sin(x) = 1.58732
>>
>> GSL::
rootSolverBracket
wrapLambda
>>
>> double x = 1.58732
(double) 1.5873200
>> pow(x, 3) - 4 * sin(x)
(double) -6.6632073e-05
>>
>> GSL::rootSolverBracket([](double x){ return x * x * x - 4 * sin(x);}, -10, 5, 200)
(double) 1.5873218
>>
Run the script in batch mode:
- $ root -l -q script1.C
$ time cern-root -l -q script1.C
Processing script1.C...
Running C++11
Running a C++ script in the ROOT REPL.
gsl_sf_bessel_J0(4.0) = -0.39715
Root of equation x^2 - 25.0 = 5.00001
Root of equation x^3 - 4 * sin(x) = 1.58732
real 0m0.469s
user 0m0.335s
sys 0m0.096s
Compile the script:
$ clang++ -std=c++1z script1.C -o script1.bin -Wall -Wextra -g -lgsl -lgslcblas
$ ./script1.bin
Running C++17
Running a C++ script in the ROOT REPL.
gsl_sf_bessel_J0(4.0) = -0.39715
Root of equation x^2 - 25.0 = 5.00001
Root of equation x^3 - 4 * sin(x) = 1.58732
How to extract the shared libraries needed to run the program?
$ ldd script1.bin
linux-vdso.so.1 (0x00007ffe0f5b8000)
libgsl.so.23 => /lib64/libgsl.so.23 (0x00007fcae26ca000)
libgslcblas.so.0 => /lib64/libgslcblas.so.0 (0x00007fcae248b000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fcae20f9000)
libm.so.6 => /lib64/libm.so.6 (0x00007fcae1d65000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fcae1b4d000)
libc.so.6 => /lib64/libc.so.6 (0x00007fcae178e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcae2b39000)
Install Python 3 development libraries: (Fedora Linux)
$ sudo dnf install python3-devel.x86_64
Locate where is Python3 shared library:
$ ldd $(which python3)
linux-vdso.so.1 (0x00007fff82b64000)
libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007fd1eb4a5000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd1eb286000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fd1eb082000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007fd1eae7f000)
libm.so.6 => /lib64/libm.so.6 (0x00007fd1eaaeb000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd1ea72c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd1ebc04000)
$ ldd $(which python3) | grep python
libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007ff0015ee000)
Locate Python 3 header files:
$ find /usr/include/ -name "Python.h"
/usr/include/python3.6m/Python.h
Start ROOT REPL:
$ cern-root
==> Starting root configuration from: /home/archbox/.rootalias.C
Current dir = /home/archbox/Documents/projects/cpp-programming.cpp/src
(std::basic_ostream<char, std::char_traits<char> >::__ostream_type &) @0x7fb42fc7eec0
Load the Python3 shared library and its header file:
>> #include "python3.6m/Python.h"
>> #pragma cling load("/lib64/libpython3.6m.so.1.0")
Initialize Python3:
>> Py_Initialize();
Python C-API Py_GetPath():
>> Py_GetPath()
(wchar_t *) @0x7fff9a144968
>> std::wcout << "path = " << Py_GetPath() << L"\n";
path = /usr/lib64/python36.zip:/usr/lib64/python3.6:/usr/lib64/python3.6:/usr/lib64/python3.6/lib-dynload
>>
Get Version:
>> Py_GetVersion()
(const char *) "3.6.7 (default, Nov 23 2018, 12:11:28)
[GCC 8.2.1 20181105 (Red Hat 8.2.1-5)]"
Get Platform:
>> Py_GetPlatform()
(const char *) "linux"
Information about Python interpreter:
>> Py_GetPrefix()
(wchar_t *) @0x7fff9a144968
>> std::wcout << L" => Py_GetPrefix() = " << Py_GetPrefix() << L"\n";
=> Py_GetPrefix() = /usr
>> Py_GetProgramFullPath()
(wchar_t *) @0x7fff9a144968
>> std::wcout << L" => Py_GetProgramFullPath() = " << Py_GetProgramFullPath() << L"\n";
=> Py_GetProgramFullPath() = /usr/bin/python3
Get copyright banner:
>> Py_GetCopyright()
(const char *) "Copyright (c) 2001-2018 Python Software Foundation.
All Rights Reserved.
Copyright (c) 2000 BeOpen.com.
All Rights Reserved.
Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.
Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved."
>>
Python C-API PyRun_SimpleString:
>> PyRun_SimpleString("print(' ==>> Hello world Python3')")
==>> Hello world Python3
(int) 0
>>
>> PyRun_SimpleString("print(m.sin(m.pi))")
1.2246467991473532e-16
(int) 0
>> PyRun_SimpleString("print(m.cos(m.pi))")
-1.0
(int) 0
>> PyRun_SimpleString("print(m.exp(2.5))")
12.182493960703473
(int) 0
>> PyRun_SimpleString("print(wrong(2.5))")
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'wrong' is not defined
(int) -1
Creating primitive python float point object:
>> PyObject* value = Py_BuildValue("f", 5.136);
>> value
(PyObject *) 0x7fb43059f240
>> PyObject_Print(value, stdout, 0), std::cout << std::endl;
5.136
Creating primitive python string object:
>> PyObject* pystring = Py_BuildValue("s", " Python3-C++-REPL");
>> PyObject_Print(pystring, stdout, 0), std::cout << std::endl;
' Python3-C++-REPL'
Importing module sys:
>> PyObject* msys = PyImport_ImportModule("sys")
(PyObject *) 0x7fb430593ef8
>> PyObject* pyver = PyObject_GetAttrString(msys, "version")
(PyObject *) 0x7fb4305970b0
>>
>> PyObject_Print(pyver, stdout, 0), std::cout << std::endl;
'3.6.7 (default, Nov 23 2018, 12:11:28) \n[GCC 8.2.1 20181105 (Red Hat 8.2.1-5)]'
>>
Importing module math:
// Equivalen to: import math
>> PyObject* m = PyImport_ImportModule("math");
>> m
(PyObject *) 0x7fb41b1b79f8
>>
>> PyObject_Print(m, stdout, 0), std::cout << std::endl;
<module 'math' from '/usr/lib64/python3.6/lib-dynload/math.cpython-36m-x86_64-linux-gnu.so'>
Get function sin from module math:
// Get function sin from module math
>> PyObject* py_sin = PyObject_GetAttrString(m, "sin")
(PyObject *) 0x7fb41b1401f8
// Print string representation of function 'sin'
>> PyObject_Print(py_sin, stdout, 0), std::cout << std::endl;
<built-in function sin>
>>
Call funciton ‘sin’:
>> PyObject* args = Py_BuildValue("(f)", M_PI_2);
>> PyObject_Print(args, stdout, 0), std::cout << std::endl;
(1.5707963267948966,)
>> PyObject* result = PyEval_CallObject(py_sin, args)
(PyObject *) 0x7fb43059f1e0
>> PyObject_Print(result, stdout, 0), std::cout << std::endl;
1.0
Creating a dictionary object or hash table object:
>> PyObject* dc = PyDict_New();
// Heal-allocated object.
>> dc
(PyObject *) 0x7fb41b234558
>>
// Print the string representation of the dictionary object
>> PyObject_Print(dc, stdout, 0), std::cout << std::endl;
{}
>>
Exit Python and quit REPL:
>> Py_Finalize()
>> .q
Python C-API Objects:
- Note: The C-function “constructors” return a pointer to PyObject or PyObject* pointer.
C-API Object | C-function Constructor | Python Object |
---|---|---|
PyObject | Python ROOT object, all Python objects are an instance of PyObject | |
PyIntObject | ||
PyLongObject | ||
PyFloatObject | ||
PyStringObject | ||
PyDictObject | PyDict_New | Python dictionary {} |
PyTupleObject | PyTuple_New | Python tuple, example: (100, 200, “Location”) |
PyListObject | PyList_New | Python list object, example: [100, 2000, ‘x’] |
PyVarObject | ||
PyTypeObject | ||
PyByteArrayObject | ||
PyBytesObject | ||
PySetObject | ||
PyUnicodeObject | ||
References:
- Extending and Embedding the Python Interpreter — Python 3.7.2 documentation
- Common Object Structures — Python 3.7.2 documentation
- Python Types and C-Structures — NumPy v1.15 Manual
- 7.3.1 String Objects
- Code Objects — Python 2.7.15 documentation
- The Very High Level Layer — Python 2.7.15 documentation
- Create and call python function from string via C API - Stack Overflow
- Embed Python scripting in C applications
- Python C API: PyEval_CallFunction? - Stack Overflow
- How do I call an object’s method from C?
Creating a native Python module:
- Write C++ extensions for Python - Visual Studio | Microsoft Docs
- Calling C functions from Python - part 2 - writing CPython extensions using Python/C API | yizhang82’s blog
Python (CPython) debugging with GDB:
- 22. gdb Support — Python Developer’s Guide
- Mixed-mode debugging for Python - Visual Studio | Microsoft Docs
Reverse engineering:
- Command: .?
Root [3] .?
Cling (C/C++ interpreter) meta commands usage
All commands must be preceded by a '.', except
for the evaluation statement { }
==============================================================================
Syntax: .Command [arg0 arg1 ... argN]
.L <filename> - Load the given file or library
.(x|X) <filename>[args] - Same as .L and runs a function with
signature: ret_type filename(args)
.> <filename> - Redirect command to a given file
'>' or '1>' - Redirects the stdout stream only
'2>' - Redirects the stderr stream only
'&>' (or '2>&1') - Redirects both stdout and stderr
'>>' - Appends to the given file
.undo [n] - Unloads the last 'n' inputs lines
.U <filename> - Unloads the given file
.I [path] - Shows the include path. If a path is given -
adds the path to the include paths
.O <level> - Sets the optimization level (0-3)
(not yet implemented)
.class <name> - Prints out class <name> in a CINT-like style
.files - Prints out some CINT-like file statistics
.fileEx - Prints out some file statistics
.g - Prints out information about global variable
'name' - if no name is given, print them all
.@ - Cancels and ignores the multiline input
.rawInput [0|1] - Toggle wrapping and printing the
execution results of the input
.dynamicExtensions [0|1] - Toggles the use of the dynamic scopes and the
late binding
.printDebug [0|1] - Toggles the printing of input's corresponding
state changes
.storeState <filename> - Store the interpreter's state to a given file
.compareState <filename> - Compare the interpreter's state with the one
saved in a given file
.stats [name] - Show stats for internal data structures
'ast' abstract syntax tree stats
'asttree [filter]' abstract syntax tree layout
'decl' dump ast declarations
'undo' show undo stack
.help - Shows this information
.q - Exit the program
Download:
Documentation:
- CINT | ROOT a Data analysis Framework
- ROOT Tutorial Stanford
- Chapter: GettingStarted
- AnalysisTutorial < UCSDTier2 < TWiki
- The C++ Interpreter Cling
Root Reflection Documentation:
Questions:
Files:
- Scripting in the ROOT analysis Framework
- Introduction to ROOT Practical Session
- A Root Guide for Beginners - Root Data Analysis Framework