How to import external libraries to CINT

  Because of Cint limitation, special technique is needed to import 
 arbitrary C/C++ libraries into Cint. Assuming you already have basic
 knowledge about cint/makecint, this document describes how to import 
 external libraries using makecint.

  Rootcint is a version of makecint which is specialized for ROOT framework.
 This document does not focus on use of rootcint. But basic technique 
 explained here will be applicable to rootcint too.  Rootcint is different
 from makecint in following aspects.
   - Rootcint knows classes and environments of ROOT framework. 
   - provides object persistence by automatically generated Streamer()


############################################################################
# Assumptions
############################################################################
  Here are assumptions in this document.

  - A user have useful C/C++ library which he/she wants to use in the
    interpreter.

  - The library is provided by either source code, object file, static 
    library or shared library. Let's call it 'extlib.cxx' , 'extlib.o' 
    , 'extlib.a' or 'extlib.so'.

  - The library provides header file. Let's call it 'extlib.h'.

  - The user knows interface to the library he/she wants to use. 


############################################################################
# First, you could try this...
############################################################################
  If you the header file extlib.h is simple enough, you could simply feed
 extlib.h to makecint.

 If extlib.cxx is provided,
   $  makecint -mk makefile -dl extlib.dll -H extlib.h -C++ extlib.cxx
   $  make -f makefile

 If extlib.o , extlib.a or extlib.so is provided.
   $  makecint -mk makefile -dl extlib.dll -H extlib.h -l extlib.a
   $  make -f makefile


  If macro function is used in extlib.h, you will find problems.
 You can try using preprocessor by adding '-p' option.

 If extlib.cxx is provided,
   $  makecint -mk makefile -dl extlib.dll -p -H extlib.h -C++ extlib.cxx
   $  make -f makefile

 If extlib.o , extlib.a or extlib.so is provided.
   $  makecint -mk makefile -dl extlib.dll -p -H extlib.h -l extlib.a
   $  make -f makefile


############################################################################
# Using preprocessor might help...
############################################################################
  Unfortunately, above works only if you are very lucky. Many of the library 
 headers include something cint can not understand. Typical reasons are

   - Parsing limitation of Cint
      Cint is improved over the years. This case is decreasing, however,
      still not perfect. You can request improvements to the author.

   - Non-standard symbols are used in the library
      For portability reason, Cint only supports what is defined in 
      ANSI C and ANSI/ISO C++, or at least subset of it.  Anything out 
      of this standard may not be understood by Cint. 

 Please proceed to following sections if you find many errors. According 
 to your situation, you can select Workaround 1 or 2.

 Workaround 1: Creating dummy header
   - You can not or do not want to modify the original header file.
   - Library is not under your control. It may be modified by other person
     without notice.
   - There are too many errors and it looks unrealistic to start from
     the original header file.

 Workaround 2: Modifying library header file
   - You can modify the original header file.
   - You are the originator of the library. You have 100% control of it.
   - You find simple errors only.


############################################################################
# Workaround 1: Creating dummy header
############################################################################
  In many cases, original header file includes things that cint can not 
 understand. This is not only because of cint limitation, but also by
 compiler specific keywords and non-standard symbols. There is very 
 little hope to modify the original header. Besides, you want to keep
 the original library unchanged for maintenance reason.
  As a workaround, you need to create a dummy header which describes 
 interface of the external library. Let's name it 'extlibdmy.h' in this 
 document.

 1. Dummy header overview

  A dummy header must consists of 2 parts. 

   (1) Part where C/C++ compiler reads
   (2) Part where cint/makecint compiler reads

  These are segmented by '#ifdef __MAKECINT__'


          ////////////////////////////////////////////////////
          // extlibdmy.h
          ////////////////////////////////////////////////////
          #ifndef EXTLIB
          #define EXTLIB
      
          #ifndef __MAKECINT__
     ^
     |    // Include extlib's original header file here.
 (1) |    // This part is only read by C++ compiler.
     |    #include "extlib.h"
     v
          #else  // __MAKECINT__
     ^
     |    // Declare interface to the external library.
     |    // This part is read by cint/makecint only and 
 (2) |    // must be described within cint limitation.
     |    // #pragma link statements can be added as option.
     |    class ExtLib { ... };
     |    #pragma link C++ class ExtLib;
     v   
          #endif  // __MAKECINT__
      
          #endif // EXTLIB
          ////////////////////////////////////////////////////


  Then do

   $  makecint -mk makefile -dl extlib.dll -H extlibdmy.h -C++ extlib.cxx
   $  make -f makefile

    or

   $  makecint -mk makefile -dl extlib.dll -H extlibdmy.h -l extlib.a
   $  make -f makefile


NOTE:
  If the library defines many symbols, creation of part (2) may require 
 significant amount of work. There will be criticism for recommending this
 method. But in my past experience, this is the best practice. Many of the
 library headers refer to non-standard symbols. Even if we remove cint 
 limitations, having one such non-standard symbol becomes a bottleneck.
 Creating dummy header is an inevitable choice in order to avoid it.


# How to describe dummy header

  This section explains how to describe the dummy header.

 - class
    You only need to describe public interface of the class and only what you
   want to access from the interpreter.  For example, if original header 
   extlib.h looks like below.

          ////////////////////////////////////////////////////
          // extlib.h 
          ////////////////////////////////////////////////////
          class  _DLLEXPORT  ExtLib : _PUBLIC _BASEPROPRIETARY {
           public:
            // public interface 
            typedef int ExtLibLocalType;
            ExtLib() ;
            ExtLib(const ExtLib& x);
            ~ExtLib() ;
      
            void publicMethod1();
            int publicMethod2(const ExtLib& x);
            const ExtLib& publicMethod3() const;
    
            // public but suppose you do not need to use following 
            // methods from the interpreter
            void publicMethod5();
            int publicMethod6(const ExtLib& x);
            const ExtLib& publicMethod7() const;
    
           private:
            void privateMethod5();
            const char* privateMethod6(const char* x);
            double privateMethod7() const;
    
            char* x;
          };
          //////////////////////////////////////////////////////////


  In extlibdmy.h , you only describe as follows.

          ////////////////////////////////////////////////////
          // extlibdmy.h
          ////////////////////////////////////////////////////
          #ifndef EXTLIB
          #define EXTLIB
      
          #ifndef __MAKECINT__
     ^
     |    // Include extlib's original header file here.
 (1) |    // This part is only read by C++ compiler.
     |    #include "extlib.h"
     v
          #else  // __MAKECINT__
     ^
     |    // Declare interface to the external library.
     |    // This part is read by cint/makecint only and 
 (2) |    // must be described within cint limitation.
     |    // #pragma link statements can be added as option.
     |    class ExtLib {
     |     public:
     |      // describe only things that you want to use from the 
     |      // interpreter
     |      typedef int ExtLibLocalType;
     |      ExtLib() ;
     |      ExtLib(const ExtLib& x);
     |      ~ExtLib() ;
     |
     |      void publicMethod1();
     |      int publicMethod2(const ExtLib& x);
     |      const ExtLib& publicMethod3() const;
     |    };
     v   
          #endif  // __MAKECINT__
      
          #endif // EXTLIB
          ////////////////////////////////////////////////////

 - macro defined as scalar or string constant 
    Macro that represents scalar or string constant can be described as is. 
   For example. 

          ////////////////////////////////////////////////////
          // extlibdmy.h
          ////////////////////////////////////////////////////
          #ifndef EXTLIB
          #define EXTLIB

          #ifndef __MAKECINT__
     ^
     |    // Include extlib's original header file here.
 (1) |    // This part is only read by C++ compiler.
     |    #include "extlib.h"
     v
          #else  // __MAKECINT__
     ^
     |    // Declare interface to the external library.
     |    // This part is read by cint/makecint only and 
 (2) |    // must be described within cint limitation.
     |    // #pragma link statements can be added as option.
     |    #define  PI          3.141592
     |    #define  LIBVERSION  20000214
     |    #define  LIBNAME     "My External Lib"
     v   
          #endif  // __MAKECINT__
      
          #endif // EXTLIB
          ////////////////////////////////////////////////////

 - macro function
     Macro function needs special care.  Cint can not pass arguments to
    macro function becuase there is no type information. You have to 
    translate it to ANSI C style header. You also need to provide #pragma
    link information that it is a macro not a true function. Otherwise, 
    Cint tries to get pointer to the function which causes compilation 
    error.

          ////////////////////////////////////////////////////
          // extlib.h 
          ////////////////////////////////////////////////////
          #define MAX(a,b)  (a>b?a:b)
          #define MIX(a,b)  (a>b?a:b)
          //////////////////////////////////////////////////////////


  In extlibdmy.h , you describe as follows.

          ////////////////////////////////////////////////////
          // extlibdmy.h
          ////////////////////////////////////////////////////
          #ifndef EXTLIB
          #define EXTLIB
      
          #ifndef __MAKECINT__
     ^
     |    // Include extlib's original header file here.
 (1) |    // This part is only read by C++ compiler.
     |    #include "extlib.h"
     v
          #else  // __MAKECINT__
     ^
     |    // Declare interface to the external library.
     |    // This part is read by cint/makecint only and 
 (2) |    // must be described within cint limitation.
     |    // #pragma link statements can be added as option.
     |    double MAX(double a,double b);
     |    double MIN(double a,double b);
     |    int MAX(int a,int b);
     |    int MIN(int a,int b);
     |
     |    #pragma link MACRO MAX;
     |    #pragma link MACRO MIN;
     v   
          #endif  // __MAKECINT__
      
          #endif // EXTLIB
          ////////////////////////////////////////////////////

 - pointer to function
     It is recommended to use typedef for pointer to function. Cint can
    process basic pointer to function syntax, however, there can be bugs.
    Typedef will prevent such bug.

 - template
     Cint/makecint can not precompile template itself. It can only precompile
    instantiated template class or function. Cint can not process partial
    template specialization. Such description must be avoided in the dummy
    header.

          ////////////////////////////////////////////////////
          // extlibdmy.h
          ////////////////////////////////////////////////////
          #ifndef EXTLIB
          #define EXTLIB
      
          #ifndef __MAKECINT__
     ^
     |    // Include extlib's original header file here.
 (1) |    // This part is only read by C++ compiler.
     |    #include "extlib.h"
     v
          #else  // __MAKECINT__
     ^
     |    // Declare interface to the external library.
     |    // This part is read by cint/makecint only and 
 (2) |    // must be described within cint limitation.
     |    // #pragma link statements can be added as option.
     |    template<class T> ExtLibArray {
     |       ...
     |    };
     |    // instantiate template class
     |    #pragma link C++ class ExtLibArray<int>;
     |    #pragma link C++ class ExtLibArray<TExtLiba>;
     |
     |    template<class T> void ExtLibTmpltFunc(T a) { ... }
     |    // instantiate template function
     |    void ExtLibTmpltFunc(int a);
     |    void ExtLibTmpltFunc(TExtLibA a);
     |    #pragma link C++ function ExtLibTmpltFunc; // optional
     v   
          #endif  // __MAKECINT__
      
          #endif // EXTLIB
          ////////////////////////////////////////////////////

 - STL
     STL is a template library. So basically you need to follow above
    rule. On top of it, you need to give '-cint -M0x10' option to makecint.
    STL allocator overrides operator new/delete. This conflicts with Cint's
    operator new/delete. You need to give '-cint -M0x10' option to avoid 
    this.  HP-UX needs '-cint -M0x1c'.

   $  makecint -mk makefile -dl extlib.dll -H extlibdmy.h -C++ extlib.cxx 
     -cint -M0x10
   $  make -f makefile

    or

   $  makecint -mk makefile -dl extlib.dll -H extlibdmy.h -l extlib.a 
     -cint -M0x10
   $  make -f makefile

 - exception
     Cint can parse exception syntax and ignores it.  It should be fine
    to leave exception specification in the dummy header. If you find
    problem , please eliminate exception specification from the dummy 
    header.

 - global function, global variable, typedef, etc...
     Most of the other C++ language constructs can be processed by 
    cint/makecint. You can copy the original description in original
    header file as it is.

 - other tips,
     For other cint limitations, please refer to doc/limitati.txt


############################################################################
# Workaround 2: Modifying the original header
############################################################################
  Basic rule is the same as Workaround 1. You will do it for the original
 header file instead of dummy header. This method is recommended only if
 you have 100% control of the library.