CPP / C++ Review
Table of Contents
- 1. C++ CPP CERN - Root Cling Interpreter and tools
- 1.1. Overview
- 1.2. Installation and configuration
- 1.3. Command Sumamry
- 1.4. Playing with Root REPL
- 1.4.1. Start root interpreter
- 1.4.2. Run shell command:
- 1.4.3. Show Math constants
- 1.4.4. Print to stdout
- 1.4.5. Paste multiline
- 1.4.6. Playing with STL Vectors
- 1.4.7. Playing with Deque - Double Ended Queue STL Container
- 1.4.8. Playing with STL Maps
- 1.4.9. Playing with classes
- 1.4.10. Playing with higher order functions and C++11 lambdas
- 1.4.11. Playing with STL algorithms
- 1.4.12. Show a file
- 1.4.13. Using boost libraries
- 1.4.14. Playing with GNU Scientific library shared library
- 1.4.15. Testing Unix System-Calls and APIs
- 1.4.16. Run a script with shared library
- 1.5. C++ Script Examples
- 1.6. Load Python3 (CPython) C-API in the REPL
- 1.7. Basic Commands
- 1.8. References and Bookmarks
1 C++ CPP CERN - Root Cling Interpreter and tools
1.1 Overview
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 …"
1.2 Installation and configuration
1.2.1 Install from source
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' | ------------------------------------------------------------
1.2.2 Install from Docker
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
1.2.3 Configuration
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
1.3 Command Sumamry
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]
1.4 Playing with Root REPL
1.4.1 Start root interpreter
$ $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]
1.4.2 Run shell command:
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]
1.4.3 Show Math constants
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]
1.4.4 Print to stdout
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
1.4.5 Paste multiline
// 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]
1.4.6 Playing with STL Vectors
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]
1.4.7 Playing with Deque - Double Ended Queue STL Container
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]
1.4.8 Playing with STL Maps
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
1.4.9 Playing with classes
- CashFlow class
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]
- Linear function class
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; }
1.4.10 Playing with higher order functions and C++11 lambdas
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]
1.4.11 Playing with STL algorithms
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
1.4.12 Show a file
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 ... ... ... ... ... ... ... ... ... ... ... ...
1.4.13 Using boost libraries
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]
1.4.14 Playing with GNU Scientific library shared library
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);
1.4.15 Testing Unix System-Calls and APIs
- Get current directory - getcwd()
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]
- Create a directory - mkdir
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]
- List directory - opendir
// #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]
- Read process output with popen
// 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]
1.4.16 Run a script with shared library
1.5 C++ Script Examples
1.5.1 Example: Run a Ublas - Boost Library Linear Algebra C++ script
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))
1.5.2 Example: GNU Scientific Library C++ Wrapper Script
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)
1.6 Load Python3 (CPython) C-API in the REPL
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:
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 | ||
- Note: The C-function "constructors" return a pointer to PyObject or PyObject* pointer.
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:
1.7 Basic Commands
1.7.1 Show Help
- 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
1.8 References and Bookmarks
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