Lazy dynamic loading of static variables in ROOT6

I’ve just run into a strange issue with ROOT 6 failing to load some of my defined variables (especially enums) when loading libraries into an interpreter session. In many cases, it appears to be unable to read a static variable name until after it has read a related class. This breaks a bunch of my scripts.

I’ve written trivial test library, which is attached.

The critical file looks like this:

namespace myns { static const int myvar = 123; class Test { public: Test(){}; }; };

After loading the library built from this file, it should be possible for the interpreter to access myns::myvar, but it can’t immediately. However, as soon as instantiate one of the Test class, I am able to do so.

Output from a terminal:

[code]/tmp/test_project$ root-config --version
/tmp/test_project$ root -l
root [0] gSystem->Load(“”)
(int) 0
root [1] myns::myvar
ROOT_prompt_1:1:7: error: no member named ‘myvar’ in namespace 'myns’

root [2] myns::Test t
(myns::Test &) @0x7fd978cf8028
root [3] myns::myvar
(const int) 123[/code]

The equivalent log on ROOT5 looks like:
[code]/tmp/test_project$ root -l
root [0] gSystem->Load("")
root [1] myns::myvar
(const int)123[/code]

The two ROOT builds I'm using are on CVMFS if it helps to reproduce the issue, eg 
[code]source /cvmfs/
setup root v6_06_08 -q e10:nu:prof[/code]

Do you have any idea why this is happening, and how I can force my variables to load properly without requiring related classes to be instantiated (or even to exist at all)?

<a class='attachment' href='/uploads/default/original/2X/7/7d4079e2155a4f837468d34b03230a839a7ea196.gz'>test_project.tar.gz</a> (2.72 KB)

Hi Steve,

the way in which ROOT6 invokes functions and classes methods is very different from the one of ROOT5. To make a long story short, the reason is the radical difference between Cling, the ROOT6 Clang based C++ interpreter, and CINT, the good old (augmented) C parser.
For example, the latter relied on stubs of explicitly selected functions and methods, while cling counts merely on ABI compatibility. Upon library loading, CINT was injecting in the ROOT typesystem all the information necessary for the function calls. In cling, loading a library… well… just loads a library (and executes all static initialisers in it) :slight_smile: . This, among the many, leads to a tremendous advantage with respect to the old solution: interactivity without dictionaries. In ROOT6 it is enough to load a library, also not containing any dictionary, including a header, and all C++ entities can be used interactively, also complex things such as templates.

I’ll be happy to go through even more details but let me come to your case. The code as it is now does not work in ROOT6 yet: the technical reason behind this is that the header(s) where myns::myvar is defined cannot be automatically parsed by the system (in ROOT jargon, autoparsing cannot happen upon variable usage but class usage - this is the reason why after instantiating a class, which I imagine you selected in the selection file, you are able to use your variable).
Now, I see two solutions:

  1. Include the header (by hand: #include “myheader.h”) and load the library. This will allow you to take advantage of interactivity without dictionaries.
  2. Slightly modify your code into

namespace myns { struct myvar { static int getVal() {return 123;} }; class Test { public: Test(){}; }; };

selecting the struct myns::myvar in the Linkdef/selection xml file.