I’m trying to use a shared library containing classes with inheritance. Unfortunately, I am running into some compatibility problems and in the current state can’t use the library both with the interpreter and the compiler at the same time. Help would be appreciated.
For example, I have class A and a shared library A.sl as well as a class B which inherits from class A:
#ifndef _B
#define _B
#include "A.h"
class B : public A {
public:
B(int arg) : A(arg) {}
void funcB();
};
#endif
Now, when I compile this macro:
#include "A.h"
#include "B.h"
void macro() {
A a(0);
a.funcA();
B b(0);
b.funcA();
}
Everything works nicely.
However, when I load the library with gSystem->Load("A.sl"); and then execute the macro without compiling it I get the errors:
error: base class has incomplete type
class B : public A {
~~~~~~~^
A.h:5:7: note: definition of 'A' is not complete until the closing '}'
class A {
^
In file included from ADictUX dictionary payload:6:
B.h:7:15: error: type 'A' is not a direct or virtual base of 'B'
B(int arg) : A(arg) {}
^
Error in <TInterpreter::AutoParse>: Error parsing payload code for class A with content:
#line 1 "ADictUX dictionary payload"
#define _BACKWARD_BACKWARD_WARNING_H
// Inline headers
#include "A.h"
#include "B.h"
#undef _BACKWARD_BACKWARD_WARNING_H
Error in <TInterpreter::AutoParse>: Error parsing payload code for class B with content:
#line 1 "ADictUX dictionary payload"
#define _BACKWARD_BACKWARD_WARNING_H
// Inline headers
#include "A.h"
#include "B.h"
#undef _BACKWARD_BACKWARD_WARNING_H
Now, I can avoid the these errors by including only #pragma link off all classes; in the LinkDef.h. Unfortunately, this is not really an option since it makes the library unusable for example with ROOT.gSystem.Load('A.sl').
Is there a way to make all three options work at the same time? If needed I can also attach the full example.
Thank you for having a look! Unfortunately, the proposed workaround does not really help since it would lead to user error and it does not fix the underlying problem. For example, this macro.cc still fails:
It seems the shared library does not catch the header guard in A.h when executed in Cling. For _B the header guard is caught by the shared library (try moving #include "A.h" outside of the header guard).
Any other ideas how to fix this or is it a bug in Cling?
It seems like the error is not directly related to inheritance but it happens when a class is initialized in the constructor of another class. This will produce the same error:
#ifndef _B
#define _B
#include "A.h"
class B {
public:
B(int arg) {
A a(arg);
}
void funcB();
};
#endif
However, there is no error if A is initialized only in funcB().
Is there a way to define a child class that works with Cling?
Cling does support inherited constructors. The issue is that the script triggers loading of a shared library in the middle of parsing, and recursively defines the same thing.
The script can use R__LOAD_LIBRARY(YourLibName) at the top of the script, to trigger loading before entering the recursive class definition.
Or you can outline the constructor - that should work, too.
Or you can generate a C++ dictionary module, see the command line flags for rootcling.
Short answer yes, of course, we have many working examples. … Long answer … sorry for the delay I am investigating why this works in a lot of other cases but not your specific setup and testing the proper workaround for you.
To work-around the issue you just have to generate a rootmap file (to be kept in the same directory as the library). In the following the name of the rootmap file is A.rootmap (to match with the library name).