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"

// This line is no longer needed in the current root
// 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));
   }
   
   // Create an interactive ROOT application
   TRint *theApp = new TRint("Rint", &argc, argv);
   
   // and enter event loop ...
   theApp->Run(kTRUE);
   
   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 linux only (you need to set the ROOTSYS, CERNLIBDIR, LD_LIBRARY_PATH environment variables 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 2003.03.27 by Jacek M. Holeczek