How to call CERNLIB routines from the interpreter
It is possible to invoke routines from the CERNLIB libraries in an interactive
Root session. However, because the CERNLIB libraries have not been compiled
with the compiler option Position Independent Code, it is not possible
to call these routines from a shared library. One must build a main program
with explicit references to the list of routines that one intend to call
from the interpreter. This can be done in three ways.
In the first method one directly links to the FORTRAN function.
The procedure to follow is the following:
1. Create files to be processed by rootcint
The file CERNfunctions.h below must include the list of prototypes
for the functions to be called. In this example, the function denlan
is declared. Add as many such lines than you have functions.
CERNfunctions.h
#ifndef CERNfunctions_H
#define CERNfunctions_H
#if !defined (__CINT__) || defined (__MAKECINT__)
#include "Rtypes.h"
#endif
extern "C" Float_t denlan_(Float_t *x);
#endif
The file CERNLinkDef.h below includes the directives for rootcint.
It declares the list of functions callable from the interpreter.
CERNLinkDef.h
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C function denlan_;
#endif
We are now ready to generate the dictionary and interface function for
the interpreter (here called CERN.cxx). Execute the following shell script
command:
rootcint -f CERN.cxx -c CERNfunctions.h CERNLinkDef.h
2. Make your own main program
As an example of main program, you can copy the standard Root main program
and add to it the references to the CERNLIB functions as illustrated in
the example below:
/////////////////////////////////////////////////////////////////////////
//
// Main program rootCERN.cxx to call CERNLIB functions
//
/////////////////////////////////////////////////////////////////////////
#include "TROOT.h"
#include "TRint.h"
#include "CERNfunctions.h"
TROOT root("Rint","The ROOT Interactive Interface");
//______________________________________________________________________________
int main(int argc, char **argv)
{
// dummy block to force the CERNLIB functions to be linked by C++
if (0) {
float x = 2.3;
printf("denlan(x)=%g\n",denlan_(&x));
}
TRint *theApp = new TRint("Rint", &argc, argv, 0, 0);
// Init Intrinsics, build all windows, and enter event loop
theApp->Run();
delete theApp;
return(0);
}
3. Compile and link
Modify your Makefile to include the files above and reference the libraries.
Below is an example valid on HPUX with the CC compiler. Examples of
linking a Root application are given for your platform in ${ROOTSYS}/test/Makefile.
CC +a1 +z -I$(ROOTSYS)/include rootCERN.cxx CERN.cxx -o rootCERN \
/cern/pro/lib/libmathlib.a \
-L$(ROOTSYS)/lib -lCore -lCint \
-lGraf -lGraf3d -lHist -lHtml -lMatrix -lMinuit \
-lPostscript -lProof -lTree \
-lGpad -lGui -lGX11 -lRint \
-L/usr/lib/X11R5 -lXpm -lX11 -lm -ldld
This command invokes the C++ compiler and creates an executable module
called rootCERN. We are now ready to execute this interactive module.
The example below shows a few commands typed in an interactive session.
A TF1 object is created.
This object invokes an interpreted function fitlan listed below.
fitlan in turns invokes the compiled function denlan from
the CERNLIB library libmathlib.
rootCERN
Root > .L fitlan.C
Root > TF1* func = new TF1("fitlan",fitlan,0,2000,3);
Root > func->SetParameters(1000.,200.,50.) ;
Root > func->SetParNames("Sum","Maximum of Probability","Width");
Root > func->Draw() ;
The interpreted function fitlan in file fitlan.C is shown below:
Double_t fitlan(Double_t *x,Double_t *par)
{
Float_t val = (x[0] - TMath::Abs(par[1])) / TMath::Abs(par[2]);
Double_t result = par[0] * denlan_(&val);
return result;
}
Some remarks about linking
Depending if you link using the f77 compiler or the C++ compiler, you may
have to specify some linking options. For example on a Solaris system,
when linking with f77, the link instruction should be something like:
f77 $(ROOTFLAGS) CERN.o rootCERN.o $(LIBS2) $(GLIBS) -lC -o rootCERN.exe
Linking this example on aix
rootcint -f CERN.cxx -c CERNfunctions.h CERNLinkDef.h
xlC -g -I$(ROOTSYS)/include rootCERN.cxx CERN.cxx -o rootCERN \
-L$(ROOTSYS)/lib -lRoot -lCint /cern/pro/lib/libmathlib.a \
-lXpm -lX11 -lm -lPW -lld -lcurses
In the second method one creates a global C++ glue function to the FORTRAN
function.
The procedure to follow is the following:
1. Create the glue implementation and files to be processed by rootcint
The file CERNfunctions.cxx below must define the body of all glue
functions to be called. In this example, the function DENLAN
is defined. Add as many such definitions as you have functions.
CERNfunctions.cxx
#include "CERNfunctions.hxx"
// The interface to CERNLIB FORTRAN function(s).
extern "C" {
#ifdef extname
#define denlan denlan_
#endif
extern Float_t denlan(Float_t &x);
}
// The glue function(s) implementation
Float_t DENLAN(Float_t &x)
{
return denlan(x); // calls the CERNLIB FORTRAN function
}
The file CERNfunctions.hxx below must include the list of prototypes
for the functions to be called. In this example, the function DENLAN
is declared. Add as many such lines as you have functions.
CERNfunctions.hxx
#ifndef CERNfunctions_HXX
#define CERNfunctions_HXX
#if !defined (__CINT__) || defined (__MAKECINT__)
#include "Rtypes.h"
#endif
extern Float_t DENLAN(Float_t &x);
#endif
The file CERNfunctionsLinkDef.h below includes the directives for rootcint.
It declares the list of functions callable from the interpreter.
CERNfunctionsLinkDef.h
#ifdef __CINT__
#pragma link off all typedefs;
#pragma link off all globals;
#pragma link off all functions;
#pragma link off all classes;
#pragma link C++ function DENLAN;
#endif
We are now ready to generate the dictionary and interface function for
the interpreter (here called CERN.cxx). Execute the following shell script
command:
rootcint -f CERN.cxx -c CERNfunctions.hxx CERNfunctionsLinkDef.h
2. Make your own main program
As an example of main program, you can directly take the standard Root
main program ${ROOTSYS}/include/rmain.cxx (there is no need to modify
it, adding any references to CERNLIB functions, as in the first method
described above). The newly created executable can simply replace the
${ROOTSYS}/bin/root.exe executable.
3. Compile and link
Modify your Makefile to include the files above and reference the libraries.
Below is an example valid on HPUX with the CC compiler. Examples of
linking a Root application are given for your platform in ${ROOTSYS}/test/Makefile.
CC +a1 +z -I$(ROOTSYS)/include -Dextname \
$(ROOTSYS)/include/rmain.cxx CERNfunctions.cxx CERN.cxx -o rootCERN \
/cern/pro/lib/libmathlib.a \
-L$(ROOTSYS)/lib -lCore -lCint \
-lGraf -lGraf3d -lHist -lHtml -lMatrix -lMinuit \
-lPostscript -lProof -lTree \
-lGpad -lGui -lGX11 -lRint \
-L/usr/lib/X11R5 -lXpm -lX11 -lm -ldld
This command invokes the C++ compiler and creates an executable module
called rootCERN. We are now ready to execute this interactive module.
The example below shows a few commands typed in an interactive session.
A TF1 object is created.
This object invokes an interpreted function fitlan listed below.
fitlan in turns invokes the compiled function denlan from
the CERNLIB library libmathlib.
rootCERN
Root > .L fitlan.C
Root > TF1* func = new TF1("fitlan",fitlan,0,2000,3);
Root > func->SetParameters(1000.,200.,50.) ;
Root > func->SetParNames("Sum","Maximum of Probability","Width");
Root > func->Draw() ;
The interpreted function fitlan in file fitlan.C is shown below:
Double_t fitlan(Double_t *x,Double_t *par)
{
Float_t val = (x[0] - TMath::Abs(par[1])) / TMath::Abs(par[2]);
Double_t result = par[0] * DENLAN(val);
return result;
}
Some remarks about linking
Depending if you link using the f77 compiler or the C++ compiler, you may
have to specify some linking options. For example on a Solaris system,
when linking with f77, the link instruction should be something like:
f77 $(ROOTFLAGS) CERN.o CERNfunctions.o $(ROOTSYS)/include/rmain.o \
$(LIBS2) $(GLIBS) -lC -o rootCERN.exe
Linking this example on aix
rootcint -f CERN.cxx -c CERNfunctions.hxx CERNfunctionsLinkDef.h
xlC -g -I$(ROOTSYS)/include -Dextname \
$(ROOTSYS)/include/rmain.cxx CERNfunctions.cxx CERN.cxx -o rootCERN \
-L$(ROOTSYS)/lib -lRoot -lCint /cern/pro/lib/libmathlib.a \
-lXpm -lX11 -lm -lPW -lld -lcurses
In the third method one creates a new C++ class which encapsulates the
C++ glue function (in form of a static class member) to the FORTRAN
function.
The procedure to follow is the following:
1. Create the glue implementation and files to be processed by rootcint
The file TF77.cxx below must define the body of the TF77 class
including all glue functions (static class members) to be called. In
this example, the function denlan is defined (note that the
original FORTRAN function is declared as an external "C"-type symbol
inside of the F77 namespace, note also the appended underscore in the
original function's name and the difference between the F77
"namespace" and the TF77 "class"). Add as many such class members as
you have functions.
TF77.cxx
#include "TF77.hxx"
ClassImp(TF77)
namespace F77 {
extern "C" {
// The interface to CERNLIB FORTRAN function(s).
#ifndef WIN32
#define type_of_call
#else /* WIN32 */
#define type_of_call _stdcall
#define denlan_ DENLAN
#endif /* WIN32 */
extern Float_t type_of_call denlan_(Float_t &x);
} /* end of extern "C" */
} /* end of namespace F77 */
// The glue function(s) implementation
Float_t TF77::denlan(Float_t &x)
{
return F77::denlan_(x); // calls the CERNLIB FORTRAN function
}
The file TF77.hxx below must include the interface to the TF77
class including the list of prototypes for the functions to be called
(as public static members of this class). In this example, the
function denlan is declared. Add as many such lines as you have
functions.
TF77.hxx
#ifndef TF77_HXX
#define TF77_HXX
#if !defined (__CINT__) || defined (__MAKECINT__)
#include "Rtypes.h"
#endif
class TF77 {
public:
static Float_t denlan(Float_t &x);
ClassDef(TF77,0) // C++ glue code for CERNLIB FORTRAN functions
};
#endif /* TF77_HXX */
The file TF77LinkDef.h below includes the directives for rootcint.
It declares the TF77 class to be visible from the interpreter.
TF77LinkDef.h
#ifdef __CINT__
#pragma link off all typedefs;
#pragma link off all globals;
#pragma link off all functions;
#pragma link off all classes;
#pragma link C++ class TF77;
#endif
We are now ready to generate the dictionary and interface function for
the interpreter (here called CERN.cxx). Execute the following shell script
command:
rootcint -f CERN.cxx -c TF77.hxx TF77LinkDef.h
2. Make your own main program
As an example of main program, you can directly take the standard Root
main program ${ROOTSYS}/include/rmain.cxx (there is no need to modify
it, adding any references to CERNLIB functions, as in the first method
described above). The newly created executable can simply replace the
${ROOTSYS}/bin/root.exe executable.
3. Compile and link
Modify your Makefile to include the files above and reference the libraries.
Below is an example valid on HPUX with the CC compiler. Examples of
linking a Root application are given for your platform in ${ROOTSYS}/test/Makefile.
CC +a1 +z -I$(ROOTSYS)/include \
$(ROOTSYS)/include/rmain.cxx TF77.cxx CERN.cxx -o rootCERN \
/cern/pro/lib/libmathlib.a \
-L$(ROOTSYS)/lib -lCore -lCint \
-lGraf -lGraf3d -lHist -lHtml -lMatrix -lMinuit \
-lPostscript -lProof -lTree \
-lGpad -lGui -lGX11 -lRint \
-L/usr/lib/X11R5 -lXpm -lX11 -lm -ldld
This command invokes the C++ compiler and creates an executable module
called rootCERN. We are now ready to execute this interactive module.
The example below shows a few commands typed in an interactive session.
A TF1 object is created.
This object invokes an interpreted function fitlan listed below.
fitlan in turns invokes the compiled function denlan from
the CERNLIB library libmathlib.
rootCERN
Root > .L fitlan.C
Root > TF1* func = new TF1("fitlan",fitlan,0,2000,3);
Root > func->SetParameters(1000.,200.,50.) ;
Root > func->SetParNames("Sum","Maximum of Probability","Width");
Root > func->Draw() ;
The interpreted function fitlan in file fitlan.C is shown below:
Double_t fitlan(Double_t *x,Double_t *par)
{
Float_t val = (x[0] - TMath::Abs(par[1])) / TMath::Abs(par[2]);
Double_t result = par[0] * TF77::denlan(val);
return result;
}
Some remarks about linking
Depending if you link using the f77 compiler or the C++ compiler, you may
have to specify some linking options. For example on a Solaris system,
when linking with f77, the link instruction should be something like:
f77 $(ROOTFLAGS) CERN.o TF77.o $(ROOTSYS)/include/rmain.o \
$(LIBS2) $(GLIBS) -lC -o rootCERN.exe
Linking this example on aix
rootcint -f CERN.cxx -c TF77.hxx TF77LinkDef.h
xlC -g -I$(ROOTSYS)/include \
$(ROOTSYS)/include/rmain.cxx TF77.cxx CERN.cxx -o rootCERN \
-L$(ROOTSYS)/lib -lRoot -lCint /cern/pro/lib/libmathlib.a \
-lXpm -lX11 -lm -lPW -lld -lcurses
A more advanced example is available
It can be found in the
TF77.tar.gz
file.
This example shows how one can glue to ROOT/CINT some MATHLIB
functions used to solve first-order differential equations (D200
RKSTP, D201 DEQBS, D202 DEQMR). Note that, what is especially
interesting in this example, these functions are supposed
to call user supplied subroutines (a way to achieve it is
demonstrated, including calling interpreted, byte-compiled and
true-compiled user supplied functions).
The provided Makefile, although prepared for many platforms, was
tested on linuxegcs only (you need to set the ROOTSYS, CERNLIBDIR,
LD_LIBRARY_PATH environment variables and choose the proper ARCH in
the beginning of the Makefile in order to "make" it). The created
executables are called root.exe and rootn.exe and are supposed to
directly replace the standard ${ROOTSYS}/bin/root.exe and
${ROOTSYS}/bin/rootn.exe files (if you do this, do not forget to copy
also the TF77.hxx file into the ${ROOTSYS}/include subdirectory).
Rene Brun,
Last update 2001.03.20 by Jacek M. Holeczek