Linking problems with shared library _BACKWARD_BACKWARD_WARNING_H

Hi,

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.

Can you share your A.h file as well as how you generate the library?

Of course, A.h contains

#ifndef _A
#define _A
#include <iostream>

class A {
public:
	A(int arg) {
		std::cout << "init A with arg=" << arg << std::endl;
	}
	void funcA();
};
#endif

And the library is generated with a Makefile containing

LD              =g++

CXXFLAGS        =-fPIC -g -O -Wall -Wextra
INCROOT         =$(shell root-config --incdir)
LIBSLIN			=$(shell root-config --glibs)
CPPFLAGS        =-I $(INCROOT)/ -I $(INCDIR)/

DICTB           =ADictUX
DICTH           =${DICTB}.h
DICT            =${DICTB}.cc
DICTO           =${DICTB}.o

HDRS            =A.h B.h LinkDef.h
DICTHDRS        =$(HDRS) 
OBJS            =A.o B.o $(DICTO)
SLL             =A.sl

#__________________________________________________________

all:		${OBJS} ${DICTO}
		${LD} -shared ${CXXFLAGS} -o ${SLL} ${OBJS} ${LIBSLIN}	
		
${DICT}:        ${DICTHDRS}
		rootcint -f ${DICT} -c ${DICTHDRS}
		
%.o             : %.cc
		${LD} ${CPPFLAGS} ${CXXFLAGS} -c $< -o $@

I have also attached the full example with a C++ and a Python macro.
linker_example.zip (1.8 KB)

I can reproduce the problem … You can work around it by using macro.cc:

//#include "A.h"
#include "B.h"

void macro() {
        A a(0);
        a.funcA();
        B b(0);
        b.funcA();
}

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:

#include "A.h"
//#include "B.h"

void macro() {
        A a(0);
        a.funcA();
        //B b(0);
        //b.funcA();
}

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?

I don’t know yet. I am still investigating.

1 Like