[DEV][GENERAL] What is the purpose of `DeclFileName`?


ROOT Version: 6.14.02
Platform: Archlinux x86_64
Compiler: GCC 8.2


The ClassDef macro (as well as ClassImp) uses __FILE__ (predefined) macro to fill the body of DeclFileName function. In most cases (especially if ROOT is build out off source directory) it expands to full path (to a file). After the build, depending on type of installation (“standalone” or “gnuinstall”), the installation procedure places files in a location different than build directory. This raises the question: what the purpose of DeclFileName function? Should it print only name of a file (like file in Filename) or full path to actual location of a file?

AFAIK, it is possible to redefine __FILE__ macro at compile time (it is possible either using cmake configuration as, for example, in FreeRDP project or using compile time function execution, that is possible beginning with C++11/C++14 or even to use the value of CMAKE_INSTALL_PREFIX to prepare full path to installation location). So, there are ways to get rid of the useless information in header file (that uses these macro, see also P.S.) but I still don’t understand in first place what the purpose of this function?

P.S. I made a patch for CMakeLists.txt files and was able to build ROOT which has links to build directory in pcm files.

@pcanal, can you please help here?

Cheers,
Oksana.

The information ClassImp was used for ‘external tools’ (mostly just THtml in the end) to be able find the source file corresponding to a class. THtml is deprecated/no-longer used and the current recommendation is to not use ClassImp (well unless you are still using THtml of course).

In the ClassDef, the information can be used to find the header file. The challenge is recording anything but the full pathname is that one can not know (from that ‘location’) how much of the path to keep. For example newer ROOT header files are installed in $ROOTSYS/include/ROOT and the ‘correct’ short path to record is ‘ROOT/RHeaderName.hxx’ but from arbitrary user code we can not know what is the heureustic to use.

Cheers,
Philippe.

2 Likes

Hello Philippe.

I mentioned ClassImp only as another example that uses __FILE__ macro, I more concerned with ClassDef.

And I don’t understand that. For what reason one may need that information at runtime? AFAIK, the call of DeclFileName method is only possible at runtime (I’m including here the ROOT interactive sessions too) but why one needs that information at runtime? To open a file in an editor? As for interactive session, IMHO, it should know where header files are.

Yes, this is fragile, so I think why one would provide function for such thing at all.

IMHO, there are other ways to store information about installed files (what about actual DB or something like ls-R that do TeX Live?).

Let’s consider one example: I compiled the ROOT source with --save-temps with both GCC (8.2.0) and CLANG (6.0.1) to keep intermediate file and see to which location points DeclFileName. I took as example two files in math/mathcore/: for TMath.ii

root-build $ grep '\*DeclFileName' TMath.ii
   private: virtual Bool_t CheckTObjectHashConsistency() const { static std::atomic<UChar_t> recurseBlocker(0); if (__builtin_expect(!!(recurseBlocker >= 2), 1)) { return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } else if (recurseBlocker == 1) { return false; } else if (recurseBlocker++ == 0) { ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency = ::ROOT::Internal::HasConsistentHashMember("TString") || ::ROOT::Internal::HasConsistentHashMember(*IsA()); ++recurseBlocker; return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } return false; } public: static Version_t Class_Version() { return 2; } virtual TClass *IsA() const { return TString::Class(); } virtual void ShowMembers(TMemberInspector &insp) const { ::ROOT::Class_ShowMembers(TString::Class(), this, insp); } void StreamerNVirtual(TBuffer &ClassDef_StreamerNVirtual_b) { TString::Streamer(ClassDef_StreamerNVirtual_b); } static const char *DeclFileName() { return "/home/vladimir/pkgs/root-extra/src/build-gcc/include/TString.h"; } private: static atomic_TClass_ptr fgIsA; public: static int ImplFileLine(); static const char *ImplFileName(); static const char *Class_Name(); static TClass *Dictionary(); static TClass *Class(); virtual void Streamer(TBuffer&) ; static int DeclFileLine() { return 460; }

(this is for class TString) and for TComplex.ii:

root-build $ grep '\*DeclFileName' TComplex.ii
   private: virtual Bool_t CheckTObjectHashConsistency() const { static std::atomic<UChar_t> recurseBlocker(0); if (__builtin_expect(!!(recurseBlocker >= 2), 1)) { return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } else if (recurseBlocker == 1) { return false; } else if (recurseBlocker++ == 0) { ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency = ::ROOT::Internal::HasConsistentHashMember("TComplex") || ::ROOT::Internal::HasConsistentHashMember(*IsA()); ++recurseBlocker; return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } return false; } public: static Version_t Class_Version() { return 1; } virtual TClass *IsA() const { return TComplex::Class(); } virtual void ShowMembers(TMemberInspector &insp) const { ::ROOT::Class_ShowMembers(TComplex::Class(), this, insp); } void StreamerNVirtual(TBuffer &ClassDef_StreamerNVirtual_b) { TComplex::Streamer(ClassDef_StreamerNVirtual_b); } static const char *DeclFileName() { return "/home/vladimir/pkgs/root-extra/src/build-gcc/include/TComplex.h"; } private: static atomic_TClass_ptr fgIsA; public: static int ImplFileLine(); static const char *ImplFileName(); static const char *Class_Name(); static TClass *Dictionary(); static TClass *Class(); virtual void Streamer(TBuffer&) ; static int DeclFileLine() { return 184; }

(this is for class TComplex).

And this is after I applied my patch for CMakeLists.txt: for TMath.ii

root-build $ grep '\*DeclFileName' TMath.ii
   private: virtual Bool_t CheckTObjectHashConsistency() const { static std::atomic<UChar_t> recurseBlocker(0); if (__builtin_expect(!!(recurseBlocker >= 2), 1)) { return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } else if (recurseBlocker == 1) { return false; } else if (recurseBlocker++ == 0) { ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency = ::ROOT::Internal::HasConsistentHashMember("TString") || ::ROOT::Internal::HasConsistentHashMember(*IsA()); ++recurseBlocker; return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } return false; } public: static Version_t Class_Version() { return 2; } virtual TClass *IsA() const { return TString::Class(); } virtual void ShowMembers(TMemberInspector &insp) const { ::ROOT::Class_ShowMembers(TString::Class(), this, insp); } void StreamerNVirtual(TBuffer &ClassDef_StreamerNVirtual_b) { TString::Streamer(ClassDef_StreamerNVirtual_b); } static const char *DeclFileName() { return "math/mathcore/src/TMath.cxx"; } private: static atomic_TClass_ptr fgIsA; public: static int ImplFileLine(); static const char *ImplFileName(); static const char *Class_Name(); static TClass *Dictionary(); static TClass *Class(); virtual void Streamer(TBuffer&) ; static int DeclFileLine() { return 460; }

(this is the same class TString and obviously this is wrong value for DeclFileName) and for TComplex.ii

root-build $ grep '\*DeclFileName' TComplex.ii
   private: virtual Bool_t CheckTObjectHashConsistency() const { static std::atomic<UChar_t> recurseBlocker(0); if (__builtin_expect(!!(recurseBlocker >= 2), 1)) { return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } else if (recurseBlocker == 1) { return false; } else if (recurseBlocker++ == 0) { ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency = ::ROOT::Internal::HasConsistentHashMember("TComplex") || ::ROOT::Internal::HasConsistentHashMember(*IsA()); ++recurseBlocker; return ::ROOT::Internal::THashConsistencyHolder<decltype(*this)>::fgHashConsistency; } return false; } public: static Version_t Class_Version() { return 1; } virtual TClass *IsA() const { return TComplex::Class(); } virtual void ShowMembers(TMemberInspector &insp) const { ::ROOT::Class_ShowMembers(TComplex::Class(), this, insp); } void StreamerNVirtual(TBuffer &ClassDef_StreamerNVirtual_b) { TComplex::Streamer(ClassDef_StreamerNVirtual_b); } static const char *DeclFileName() { return "math/mathcore/src/TComplex.cxx"; } private: static atomic_TClass_ptr fgIsA; public: static int ImplFileLine(); static const char *ImplFileName(); static const char *Class_Name(); static TClass *Dictionary(); static TClass *Class(); virtual void Streamer(TBuffer&) ; static int DeclFileLine() { return 184; }

(this is for class TComplex and again it is wrong, it refers cxx instead of h file).

This is a 20 years old attempt to provide online documentation. These days the information is mostly vestigial, however we should not remove the interface unless we have a very good reason for backward compatibility reason (i.e. some framework somewhere might be using this information as is and be ‘happy’ with its currently value; removing it would require us to provide an alternative way of getting at the information and they would have to change their code … all in all quite costly).

IMHO, there are other ways to store information about installed files (what about actual DB or something like ls-R that do TeX Live?).

Sure, the information is now (also) in the pcm produced by rootlcing and in the dictionary.

So stepping back for one moment, what is the original problem that lead you to look at this?

Thanks,
Philippe.

Good task for ROOT7?

And about PCM I have another question.

The so-called “reproducible” builds. This has several applications (I’m not ready to point out right now what exactly aspects I’m interested in).

Thank you Philippe for answers, but I still don’t understand how it should work, may be because I looking at things as package maintainer (I’m packaging ROOT for Archlinux, unofficially of course,this is for our students, so having a Archlinux package helps with ROOT installation and also could help us to debug different things). I just don’t get how it must work if after installation all paths will be wrong.

P.S. May be it is time to get rid of them, say in ROOT7?

P.P.S. If there is no plan to remove this “feature” in future ROOT version, then just close this thread.


WBR, Vladimir Lomov

Yes, those are very unlikely to be there.

The so-called “reproducible” builds. This has several applications (I’m not ready to point out right now what exactly aspects I’m interested in).

:slight_smile: well makes it harder to understand how to adapt.

I can think of ways they can be used/interesting on the other hand having the forensic information available has also been useful for use in practical cases [Sometimes users get confused and are sure they are using a downloaded version that fails in weird ways and then we could discover (be sure that) it was actually a local broken build]

Good.

IMHO, the initial idea was vague.

I agree, the ROOT is too complex software so having forensic information is necessary to debug any difficult case. But this information is embedded into .so files, for example

$ strings /usr/lib/root/libMathCore.so.6.14.02 | grep /home
/home/vladimir/pkgs/root-extra/src/build/include/TCollectionProxyInfo.h
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TComplex.cxx
/home/vladimir/pkgs/root-extra/src/build/include/TKDTree.h
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TKDTree.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TKDTreeBinning.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TMath.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TRandom.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TRandom1.cxx
A/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TRandom2.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TRandom3.cxx
/home/vladimir/pkgs/root-extra/src/root-6.14.02/math/mathcore/src/TStatistic.cxx

IMHO, it is rather unusual for ordinary user to figure out where that file was build this way. In fact, I don’t get how this information sneaked into the shared library, though I found how it might to get TMath.cxx but it is not related with DeclFileName but with SetImplFile. According to Rtypes.h the SetImplFile is related with __FILE__, sigh…, again strange function and its vague purpose. All these __FILE__s.


WBR, Vladimir Lomov

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