For a general explanation: I am trying to minimize which symbols my shared library exports. To that end I make judicious use of hidden symbol visibility, marking entire classes as hidden, and not making template implementations publicly visible as well; instantiating entire templates with hidden visibility; as well as not making the template implementations, only declarations.
I should also mention that I understand the reason for the following link failure, and I am trying to figure out the best way to fix it, but I'm running into a brick wall, that I'll explain after the minimal code dump. The following results in this link failure:
/usr/bin/ld: prog.o:(.data.rel.ro._ZTV4impl[_ZTV4impl]+0x20): undefined reference to `intermediate<base, aux>::initialize()'
############################################################### ## ## Makefile LTOFLAGS = all: prog prog: prog.o lib.so g++ -o prog $(LTOFLAGS) prog.o lib.so prog.o: prog.cpp header.H Makefile g++ $(LTOFLAGS) -c -fpic -DPIC -o prog.o prog.cpp lib.so: lib.o g++ -shared $(LTOFLAGS) -o lib.so lib.o lib.o: lib.cpp header.H Makefile g++ $(LTOFLAGS) -c -fpic -DPIC -o lib.o lib.cpp ############################################################### ## ## header.H struct base { base(); virtual ~base(); /////////////////////////////////////////////////// // // REMOVE VIRTUAL TO FIX THE LINK ERROR: virtual void initialize(); }; /////////////////////////////////////////////////////////////// // // REMOVE THE HIDDEN ATTRIBUTE TO FIX THE LINK ERROR: struct __attribute__((visibility("hidden"))) aux {}; template<typename T, typename A> struct intermediate : public T { intermediate(); void initialize(); ~intermediate(); }; struct __attribute__((visibility("default"))) child; struct child : intermediate<base, aux> { child(); ~child(); }; ############################################################### ## ## lib.cpp #include "header.H" template<typename T, typename A> intermediate<T, A>::intermediate()=default; template<typename T, typename A> intermediate<T, A>::~intermediate()=default; template<typename T, typename A> void intermediate<T, A>::initialize() { } /////////////////////////////////////////////////////////////////////// // // UNCOMMENT TO FIX THE LINK ERROR // // template void __attribute__((visibility("default"))) // intermediate<base, aux>::initialize(); // base::base()=default; base::~base()=default; void base::initialize() { } child::child()=default; child::~child()=default; ############################################################### ## ## prog.cpp #include "header.H" struct impl : public child { }; int main() { impl i; return 0; } ############################################################### ## ## End of exampleThe problem is that prog.cpp needs a reference to intermediate<base, aux>::initialize in order to compile the vtable for the impl class.
aux has hidden visibility, and gcc 10 instantiates intermediate<base, aux> with all of its symbols having hidden visibility.
The link failure goes away if I do not define base::initialize as virtual, so that class method is not needed for the vtable, or I do not declare the "aux" class as having hidden visibility. The aux class is not needed, and only triggers the hidden visibility of any instance of the intermediate template.
The link failure also goes away if I explicitly instantiate intermediate<base, aux>::initialize with default visibility in lib.cpp. prog.cpp does not need the actual definition of this method, it doesn't invoke it, and only needs its symbol.
I am trying to figure out if there's any way to fix this linking failure while:
1) having "aux" keep its hidden visibility 2) and without having to explicitly instantiate every instance of intermediate::initialize() with default visibilityAdding __attribute__((visibility("default"))) to the declaration of the template class method still results in the link failure:
void initialize() __attribute((visibility("default")));Explicitly declaring default visibility for the template still results in a link failure:
template<typename T, typename A> struct __attribute((visibility("default"))) intermediate : public T {Sprinkling push/pop visibility pragmas also makes no difference. That's all I could think of. Any other options I overlooked?
Attachment:
pgpnHbJIb3Umw.pgp
Description: PGP signature