public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Overriding visibility of template instances
@ 2021-02-16  3:41 Sam Varshavchik
  0 siblings, 0 replies; only message in thread
From: Sam Varshavchik @ 2021-02-16  3:41 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 4651 bytes --]

I ran into an issue, a link failure, while building with gcc 10 my shared  
library and a program that links with the shared library. I believe that  
older versions of gcc/binutils did not result in this link failure, this is  
somethink new.

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 example

The 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 visibility

Adding  __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 #2: Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-02-16  3:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-16  3:41 Overriding visibility of template instances Sam Varshavchik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).