ROOT6 cling dictionary generation bug or feature?


Please read tips for efficient and successful posting and posting code

11.5.6.1

ROOT Version: 6
Platform: Centos8
Compiler: gcc8


I’m porting very old code to ROOT6 that uses #pragma conversion directives as described in the Users Guide in section 11.5.6.1 . The underlying code unfortunately uses the word “Root” as a class name which causes Cling ( TSchemaHelper ) to complain that the name is ambiguous . It looks like namespace Root becomes namespace ROOT in the dictionary file.
Is this implicit capitilization a bug or a feature ? ROOT5 never had a problem with it . Changing the underlying code will cause a lot of pain.

peter

@vvassilev @pcanal Can you confirm or comment?

C++ being case sensitive, I have to ask :slight_smile: … Did mean the casing Root or the casing ROOT? (I don’t think we use Root in the dictionary).

How does the underlying code using the word “Root”? (I.e. for what purpose?)

What is the exact error message?

Philippe,
The code is very old and and most classes derive from a class called RAT::DS::Root . Not suere why that name was chosen but whatever. The problem with ROOT6 and cling happens with #pragma lines in the LinkDef file like :

#pragma read sourceClass="RAT::DS::QT" targetClass = "RAT::DS::QT" source = "Byte_t startBinRelOffset;  Byte_t endBinRelOffset; UShort_t chargeRel4096; UShort_t baselineIntRel3892; Byte_t baselineSamples" version= ="[6-]" target="integral" code="{ integral = RAT::QTUtil::CalcIntegralUtil(onfile.chargeRel4096,onfile.startBinRelOffset,onfile.endBinRelOffset,onfile.baselineIntRel3892,onfile.baselineSamples);}"

when compiling the dictionary file :

build/linuxx8664gcc/RAT_Dict.C:1321:7: error: reference to ‘ROOT’ is ambiguous
       ROOT::Internal::TSchemaHelper* rule;
       ^~~~
build/linuxx8664gcc/RAT_Dict.C:197:14: note: candidates are: ‘namespace RAT::ROOT { }’
    namespace ROOT {
              ^~~~
In file included from /usr/local/root_v6.22_00/include/TObject.h:17,
                 from /usr/local/root_v6.22_00/include/TNamed.h:25,
                 from /usr/local/root_v6.22_00/include/TDictionary.h:44,
                 from /usr/local/root_v6.22_00/include/TClass.h:23,
                 from build/linuxx8664gcc/RAT_Dict.C:14:
/usr/local/root_v6.22_00/include/Rtypes.h:103:11: note:                 ‘namespace ROOT { }’
 namespace ROOT {
           ^~~~
build/linuxx8664gcc/RAT_Dict.C:1321:38: error: ‘rule’ was not declared in this scope
       ROOT::Internal::TSchemaHelper* rule;
                                      ^~~~
.....

peter

Ok. So we need to figure what is changing RAT::Root into RAT::ROOT … a priori this does not come from our code. I suspect somewhere there is a #defined Root ROOT

To figure out you should be able to grab the command line that compiles RAT_Dict.C, replace the -o with a -E (and the RAT_Dict.o into RAT_Dict.E) and this should contains all the code that the compiler sees. From there we can find where namespace RAT::ROOT is declare directly or indirectly …

There is no #defined Root anywhere. And the only place where the namespace and Root occurs in the same line in the .E file is :
namespace RAT{namespace DS{class attribute((annotate("$clingAutoload$RAT/DS/Root.hh"))) Root;}}

There is a “fix” though - if I hack the generated .C file and change lines like ROOT::TSchemaHelper *rule into ::ROOT::TSchemaHelper *rule etc. everything compiles fine.

It is almost like g++ is case insensitive when it comes to namespaces.

What is the content of the file RAT/DS/Root.hh?

It is rather large so I’ve stripped out most of the stuff not related to Root or ROOT :

#ifndef __RAT_DS_Root__
#define __RAT_DS_Root__
#include <vector>
#include <string>
#include <utility>
#include <iostream>
#include <TObject.h>

namespace RAT {
  namespace DS {
    class Root : public TObject
    {
     public: 
      Root() : TObject() { Init(); }
      Root(const Root &rhs) : TObject() { Init(); CopyObj(rhs); }
      virtual ~Root() { Destroy(); }
      virtual Root &operator=(const Root &rhs) { CopyObj(rhs); return *this; }
      virtual TObject* Clone(const char* opt = "") const { (void)opt; return new Root(*this); }
      ClassDef(Root,21);
// lots of stuff deleted
    };
  } // namespace DS
} // namespace RAT
#endif

Nothing special except the use of the name “Root”. And everything is fine if I comment out the #prgma line in the LinkDef file.
peter

I thinks this is a red-herring … the 2 candidates are within ROOT generated code itself.

If you are really using v6.22/00, it is quite old and we might have fixed this bug already.

Could you try v6.22/08?

Exactly the same result :

build/linuxx8664gcc/RAT_Dict.C: In function ‘ROOT::TGenericClassInfo* ROOT::GenerateInitInstanceLocal(const RAT::DS::QT*)’:
build/linuxx8664gcc/RAT_Dict.C:966:7: error: reference to ‘ROOT’ is ambiguous
       ROOT::Internal::TSchemaHelper* rule;
       ^~~~
build/linuxx8664gcc/RAT_Dict.C:197:14: note: candidates are: ‘namespace RAT::ROOT { }’
    namespace ROOT {
              ^~~~
In file included from /usr/local/root_v6.22_08/include/TObject.h:17,
                 from /usr/local/root_v6.22_08/include/TNamed.h:25,
                 from /usr/local/root_v6.22_08/include/TDictionary.h:44,
                 from /usr/local/root_v6.22_08/include/TClass.h:23,
                 from build/linuxx8664gcc/RAT_Dict.C:14:
/usr/local/root_v6.22_08/include/Rtypes.h:103:11: note:                 ‘namespace ROOT { }’
 namespace ROOT {
           ^~~~
build/linuxx8664gcc/RAT_Dict.C:966:38: error: ‘rule’ was not declared in this scope
       ROOT::Internal::TSchemaHelper* rule;
                                      ^~~~
build/linuxx8664gcc/RAT_Dict.C:966:38: note: suggested alternative: ‘null’
       ROOT::Internal::TSchemaHelper* rule;
                                      ^~~~
                                      null
build/linuxx8664gcc/RAT_Dict.C:969:48: error: template argument 1 is invalid
       std::vector<ROOT::Internal::TSchemaHelper> readrules(1);
                                                ^
build/linuxx8664gcc/RAT_Dict.C:969:48: error: template argument 2 is invalid
build/linuxx8664gcc/RAT_Dict.C:970:26: error: invalid types ‘int[int]’ for array subscript
       rule = &readrules[0];
                          ^
build/linuxx8664gcc/RAT_Dict.C:977:40: error: no matching function for call to ‘ROOT::TGenericClassInfo::SetReadRules(int&)’
       instance.SetReadRules( readrules );
                                        ^
In file included from /usr/local/root_v6.22_08/include/Rtypes.h:189,
                 from /usr/local/root_v6.22_08/include/TObject.h:17,
                 from /usr/local/root_v6.22_08/include/TNamed.h:25,
                 from /usr/local/root_v6.22_08/include/TDictionary.h:44,
                 from /usr/local/root_v6.22_08/include/TClass.h:23,
                 from build/linuxx8664gcc/RAT_Dict.C:14:
/usr/local/root_v6.22_08/include/TGenericClassInfo.h:137:41: note: candidate: ‘void ROOT::TGenericClassInfo::SetReadRules(const std::vector<ROOT::Internal::TS
chemaHelper>&)’
       void                              SetReadRules( const std::vector<ROOT::Internal::TSchemaHelper>& rules );
                                         ^~~~~~~~~~~~
/usr/local/root_v6.22_08/include/TGenericClassInfo.h:137:41: note:   no known conversion for argument 1 from ‘int’ to ‘const std::vector<ROOT::Internal::TSche
maHelper>&’

  • and the offending code :
      //--- User's code ---
      integral = RAT::QTUtil::CalcIntegralUtil(onfile.chargeRel4096,onfile.startBinRelOffset,onfile.endBinRelOffset,onfile.baselineIntRel3892,onfile.baselineS
amples);
   }

   // Function generating the singleton type initializer
   static TGenericClassInfo *GenerateInitInstanceLocal(const ::RAT::DS::QT*)
   {
      ::RAT::DS::QT *ptr = 0;
      static ::TVirtualIsAProxy* isa_proxy = new ::TInstrumentedIsAProxy< ::RAT::DS::QT >(0);
      static ::ROOT::TGenericClassInfo
         instance("RAT::DS::QT", ::RAT::DS::QT::Class_Version(), "DS/QT.hh", 34,
                  typeid(::RAT::DS::QT), ::ROOT::Internal::DefineBehavior(ptr, ptr),
                  &::RAT::DS::QT::Dictionary, isa_proxy, 4,
                  sizeof(::RAT::DS::QT) );
      instance.SetNew(&new_RATcLcLDScLcLQT);
      instance.SetNewArray(&newArray_RATcLcLDScLcLQT);
      instance.SetDelete(&delete_RATcLcLDScLcLQT);
      instance.SetDeleteArray(&deleteArray_RATcLcLDScLcLQT);
      instance.SetDestructor(&destruct_RATcLcLDScLcLQT);

      ROOT::Internal::TSchemaHelper* rule;

      // the io read rules
      std::vector<ROOT::Internal::TSchemaHelper> readrules(1);
      rule = &readrules[0];
      rule->fSourceClass = "RAT::DS::QT";
      rule->fTarget      = "integral";
      rule->fSource      = "Byte_t startBinRelOffset;  Byte_t endBinRelOffset; UShort_t chargeRel4096; UShort_t baselineIntRel3892; Byte_t baselineSamples";
      rule->fFunctionPtr = (void *)TFunc2void( read_RATcLcLDScLcLQT_0);
      rule->fCode        = " integral = RAT::QTUtil::CalcIntegralUtil(onfile.chargeRel4096,onfile.startBinRelOffset,onfile.endBinRelOffset,onfile.baselineIntR
el3892,onfile.baselineSamples);";
      rule->fVersion     = "[6-]";
      instance.SetReadRules( readrules );
      return &instance;
   }
   TGenericClassInfo *GenerateInitInstance(const ::RAT::DS::QT*)
   {
      return GenerateInitInstanceLocal((::RAT::DS::QT*)0);
   }
   // Static variable to force the class initialization
   static ::ROOT::TGenericClassInfo *_R__UNIQUE_DICT_(Init) = GenerateInitInstanceLocal((const ::RAT::DS::QT*)0x0); R__UseDummy(_R__UNIQUE_DICT_(Init));
} // end of namespace ROOT

humm … to make progress can you send me enough of your header files to reproduce this problem (and/or complete instruction to download and build the full software)

That would be difficult and take a while. What triggers this is the #pragma statement in the LinkDef file. If I take it out evertyhing is fine . Adding it triggers the ROOT::Internal::TSchemaHe // Function generating the singleton type initializer

   static TGenericClassInfo *GenerateInitInstanceLocal(const ::RAT::DS::QT*)
   {
      ::RAT::DS::QT *ptr = 0;
      static ::TVirtualIsAProxy* isa_proxy = new ::TInstrumentedIsAProxy< ::RAT::DS::QT >(0);
      static ::ROOT::TGenericClassInfo
         instance("RAT::DS::QT", ::RAT::DS::QT::Class_Version(), "DS/QT.hh", 34,
                  typeid(::RAT::DS::QT), ::ROOT::Internal::DefineBehavior(ptr, ptr),
                  &::RAT::DS::QT::Dictionary, isa_proxy, 4,
                  sizeof(::RAT::DS::QT) );
      instance.SetNew(&new_RATcLcLDScLcLQT);
      instance.SetNewArray(&newArray_RATcLcLDScLcLQT);
      instance.SetDelete(&delete_RATcLcLDScLcLQT);
      instance.SetDeleteArray(&deleteArray_RATcLcLDScLcLQT);
      instance.SetDestructor(&destruct_RATcLcLDScLcLQT);

      ::ROOT::Internal::TSchemaHelper* rule;                                <<<<<<<<<<<<<<<<<<<<<<<

      // the io read rules
      std::vector<::ROOT::Internal::TSchemaHelper> readrules(15);     <<<<<<<<<<<<<<<<<<<
      rule = &readrules[0];
      rule->fSourceClass = "RAT::DS::QT";
      rule->fTarget      = "integral";
      rule->fSource      = "Byte_t startBinRelOffset;  Byte_t endBinRelOffset; UShort_t chargeRel4096; UShort_t baselineIntRel3892; Byte_t baselineSamples";
      rule->fFunctionPtr = (void *)TFunc2void( read_RATcLcLDScLcLQT_0);

code section in the dictionary .C file . And simply changing ROOT::InternalTSchemaHelper to ::ROOT::Internal:TSchemaHelper in the .C makes it compile.

That is a reasonable change and is necessary/consistent.

However, I would like to understand why this is happening in your case but not elsewhere, I am concerned that there is a more subtle issue … and at the very least I want to add a test representing your use case (or more exactly that leads it to trigger this issue) to avoid breaking it in future code changes.

After looking at the code, a few good news.

The casing ROOT vs Root was a fun but irrelevant sidetrack (both the compiler and ROOT are case sensitive :slight_smile: ).

The underlying problems (a namespace RAT::ROOT within the code generated by rootcling) is solved in the master. I will backport it this to v6.22. I will also, for good measure, apply your suggestion.

The trigger is the fact that one your headers (src/daq/SCBProc.hh) contains:

using namespace RAT;

triggering the confusion that we rarely see elsewhere.

And removing this line and making a couple or so minor related changes solve the problem with the version of ROOT you are using (see the updated code on falcon).

Cheers,
Philippe.

PS. Unless you are generating your documentation with THtml, the ClassImp macros can be removed.

Thanks for your help.

peter

The fixes are in:

Add missing use of ::ROOT to qualify name in dictionary by pcanal · Pull Request #7618 · root-project/root · GitHub for master.
v6-22: Add missing use of ::ROOT to qualify name in dictionnary by pcanal · Pull Request #7622 · root-project/root · GitHub for v6.22/10
Add missing use of ::ROOT to qualify name in dictionary by pcanal · Pull Request #7623 · root-project/root · GitHub for v6.24/00

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.