Re: [ROOT] Rootcint again: Linker errors

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Fri Aug 23 2002 - 20:45:36 MEST


Hi Ole, 

On Fri, 23 Aug 2002 18:38:10 +0200
Ole Streicher <ole@ifh.de> wrote
concerning "Re: [ROOT] Rootcint again: Linker errors":
> Hi Rene!
> 
> Rene Brun writes:
>  > You must be consistent if you use namespaces.
> 
> Thank you. Now it compiles, but it still doesn't run. It get the message
> 
> Warning in <TClass::TClass>: no dictionary for class myexperiment::EventHeader is available
> Error in <TTree::Bronch>: Cannot find dictionary for class: myexperiment::EventHeader

You need to tell CINT to enable use of `nested' classes: 

   #pragma link off all functions;
   #pragma link off all globals;
   #pragma link off all classes;

   #pragma link C++ nestedclass;
   #pragma link C++ nestedtypedef;

   #pragma link C++ namespace YOUR_NS_NAME;
   #pragma link C++ class YOUR_NS_NAME::YOUR_CLASS_NAME;
   #pragma link off function YOUR_NS_NAME::YOUR_FUNC_NAME;
   #pragma link C++ function YOUR_NS_NAME::YOUR_FUNC_NAME;

See also [1,2] (the manual actully explaines this :-) 


Here's an example: 

  //__________________________________________________________________
  // 
  // File Foo.hh
  // 
  #ifndef Foo_hh
  #define Foo_hh 
  #ifndef ROOT_TObject
  #include "TObject.h"
  #endif

  namespace Bar
  {
    class Foo : public TObject
    {
    private:
      int _foo;
    public:
      Foo(int foo);
      void Print(Option_t* option) const;      
      ClassDef(Foo,1) 
    };
  }
  #endif
  //  
  // EOF
  //

  //__________________________________________________________________
  // 
  // File Foo.cc
  // 
  #ifndef Foo_hh
  #include "Foo.hh"
  #endif
  #ifndef __IOSTREAM__
  #include <iostream>
  #endif

  ClassImp(Bar::Foo);

  Bar::Foo::Foo(int foo) : _foo(foo) {}

  void Bar::Foo::Print(Option_t* option) const 
  {
    cout << "Foo is " << _foo << endl;
  }
  //  
  // EOF
  //

  //__________________________________________________________________
  // 
  // File FooLinkDef.hh
  // 
  // -*- mode: c++ -*-
  //____________________________________________________________________ 
  //  
  #ifndef __CINT__
  #error Not for compilation
  #endif
  #pragma link off all functions;
  #pragma link off all globals;
  #pragma link off all classes;
  #pragma link C++ nestedclass;
  #pragma link C++ namespace Bar;
  #pragma link C++ class Bar::Foo+;  
  //  
  // EOF
  //

compile and try with (assuming you're using GCC and GNU ld): 

  rootcint -f FooDict.cc -c Foo.hh FooLinkDef.hh 
  g++ -shared -o Foo.so -Wl,-soname,Foo.so Foo.cc FooDict.cc

and try it in a ROOT session: 

  root [0] gSystem->Load("Foo.so");
  root [1] Bar::Foo* foo = new Bar::Foo(10);
  root [2] foo->Print()
  Foo is 10
  root [3] TTree* tree = new TTree("t", "T")
  root [4] tree->Branch("foo", "Bar::Foo", &foo)
  (class TBranch*)0x87dd328

The same rules applies for nested classes BTW.  Search roottalk, and
you'll find a number of posts concerning this (some of them from me
:-) 

Hope that helps.  

a question for Masa, and the ROOT team:  Why isn't this enabled per
default?  Is there a performance penalty to pay?  Will ROOT at some
point put all their classes into a `Root' (or `ROOT') namespace,
instead of the `T' prefix?  I think that would be a good idea (for
ROOT 4 or something) - most compilers should be able to handle
namespaces by now, as it's such an intergral part of the ISO/IEC C++
standard.  Perhaps one could so something like 

  #ifndef COMPATIBILITY 
  #define NS(x) Root:: x
  #define NSDECL(x) x
  #define NSCTOR(x) x
  namespace Root { 
  #else 
  #define NS(x) T ## x
  #define NSDECL(x) T ## x
  #define NSCTOR(x) T ## x
  #endif 
    
    class NSDECL(Object) { 
    private:
    public:
      NSCTOR(Object)(); 
      ~NSCTOR(Object)();
    };
    
    NS(Object)::NSCTOR(Object) () 
    {}
  
    NS(Object)::~NSCTOR(Object) () 
    {}
    
  #ifndef COMPATIBILITY 
  }
  #endif 

or what ever works.  Ofcourse you'd have to different binary version
of ROOT: One using namespaces and one not.  Another option would be to
leave the `T' in, and just do 

  #ifdef USE_NAMESPACES 
  namespace Root { 
  #endif 

    class TObject 
    ...
 
  #ifdef USE_NAMESPACES 
  }
  #endif 

Or one could forget about compatibility between ROOT 3 and 4 (or have
some layer or something). 

Yours, 

 ____ |  Christian Holm Christensen 
  |_| |	 -------------------------------------------------------------
    | |	 Address: Sankt Hansgade 23, 1. th.  Phone:  (+45) 35 35 96 91
     _|	          DK-2200 Copenhagen N       Cell:   (+45) 24 61 85 91
    _|	          Denmark                    Office: (+45) 353  25 305
 ____|	 Email:   cholm@nbi.dk               Web:    www.nbi.dk/~cholm
 | |

[1] http://root.cern.ch/root/Cint.phtml?faq
[2] http://root.cern.ch/root/Cint.phtml?ref



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:51:05 MET