Incomplete documentation for signal/slot communication

I am trying to follow the documentation at Signal/Slot Communication - ROOT to understand why a ROOT application I am porting from ROOT v5 to v6 works on MacOS but does not work on Linux.

I would like to report that while the documentation is correct and works for scripted classes, it is incomplete and it is missing two critical steps for compiled classes.

I start with the example class A, put the code in signal_slot.C, run .L signal_slot.C, run the example commands and get the correct result, SetValue() signal sets b’s value to 79. So far so good.

I copy the code to signal_slot.cxx, provide the missing #include statements and the missing main() function, compile the code, run it, and see an error message from Connect(), it does not know about SetValue(). This is as expected, we did not create any ROOT dictionaries.

daq00:root_signal_slot$ ./signal_slot.exe 
Error in <TQObject::CheckConnectArgs>: for signal/slot consistency
checking need to specify class name as argument to RQ_OBJECT macro
GetValue is 11
daq00:root_signal_slot$ 

This is the first piece of missing documentation: it should spell out that we must use rootcint to create a ROOT dictionary for class A and link to the documentation that explains how to do it.

Luckily I have been using ROOT since v3 and I know how to go about it. I separate the code in into .h and .cxx files, create LinkDef.h, run rootcint on the .h file, create, compile and link the dictionary, run the code and see it bomb out:

daq00:root_signal_slot$ ./signal_slot_cxx.exe 
IncrementalExecutor::executeFunction: symbol '_ZN1A8SetValueEi' unresolved while linking symbol '__cf_0'!
You are probably missing the definition of A::SetValue(int)
Maybe you need to load the corresponding shared library?
Error in <TClingCallFunc::make_wrapper>: Failed to compile
  ==== SOURCE BEGIN ====
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
__attribute__((used)) __attribute__((annotate("__cling__ptrcheck(off)")))
extern "C" void __cf_0(void* obj, int nargs, void** args, void* ret)
{
   ((A*)obj)->SetValue(*(int*)args[0]);
   return;
}
#pragma clang diagnostic pop
  ==== SOURCE END ====
Error in <TClingCallFunc::Exec(address, interpVal)>: Called with no wrapper, not implemented!
GetValue is 11
daq00:root_signal_slot$ 

I see this same error in the ROOT app I am porting. It works on MacOS, but bombs out with this error on Linux. There is no documentation or explanation of what is happening. (except for suggesting that I should be using a shared library).

Googling this error message produces only one useful hit: Root_generate_dictionary - #4 by William_Koch

Since my project happens to not use CMAKE, I traced down “PROPERTY ENABLE_EXPORTS”, it seems to add a linker command line switch “-rdynamic”.

I relink my program with “-rdynamic” and the problem is fixed:

daqstore:root_signal_slot$ ./signal_slot_cxx.exe 
GetValue is 79
daqstore:root_signal_slot$ 

This is the second missing piece of documentation: example code should come with an example Makefile (or equivalent) that shows the correct way to build it. In my case -rdynamic is missing because my Makefile did not use “root-config --libs” (I only needed to link -lCore).

The third missing piece is the error message. In addition to “Maybe you need to load the corresponding shared library?” it should say “or link your executable with -rdynamic”.

I hope others who run into this problem find this explanation useful and I trust the ROOT documentation will be updated to include the missing info.

P.S. Back to the original ROOT application, Makefile uses “root-config --noauxlibs --glibs” (for reasons unknown, put there by persons unknown) and this combination of flags omits “-rdynamic”. I replaced it with “root-config --libs” and my ROOT application now runs on Linux same as on MacOS.

K.O.

Thanks for reporting your experience in porting your app from v5 to v6.
Between the last 5.34 patch release and the latest stable, about 12 years of development went in the repository - were these the only issues you encountered?

Best,
Danilo

Thanks a lot for the feedback!

Would you mind adding the missing info for compiled classes directly here: web/manual/signal_slot/index.md at main · root-project/web · GitHub as a Pull Request?
The new example you suggest could come with the CMake modern way rather than (or in addition to) the Makefile, see ROOT — Modern CMake