[cfe-users] clang and C++: exporting member function template from library using attribute visibility("default")

Alexis Murzeau via cfe-users cfe-users at lists.llvm.org
Mon Mar 30 14:18:12 PDT 2020


Hi,

When using clang, I discovered that it errors out where other compilers 
doesn't (GCC and MSVC).

I'm trying to do this:
 - Have a library compiled with -fvisibility=hidden and adding __attribute__((visibility("default")))
   only for stuff that must be exported from the library .so.

 - Have an exported class (with __attribute__((visibility("default")))) that
   declares a member function template

 - A cpp file in the library does does instantiation of that member function
   template for all applicable types that would ever be usable by that member function template.

When compiling that library, the member function template instantiations are
not being exported from the library (they are hidden).

The error comes then when an executable try to use that function, but
compilation fails because of undefined reference to `void NetworkPacketLogger::logType<T1>(T1 const*)'.


In a lib.h:
```
// An enum defining the network packet
enum class Opcode {
	T1,
	T2
};

// Base class
struct NetworkPacket {
	NetworkPacket(enum Opcode t) : type(t) {}
	
	enum Opcode type;
};

// Sample of possible network packets
struct T1 : public NetworkPacket {
	T1() : NetworkPacket(Opcode::T1) {}
	int value;
};

struct T2 : public NetworkPacket {
	T2() : NetworkPacket(Opcode::T2) {}
	float value;
};

// Class to log a network packet
class __attribute__((visibility("default"))) NetworkPacketLogger {
public:
	// "Slow" function that find the correct packet opcode and log it's content
	// vvv this function is exported just because of the attribute on the NetworkPacketLogger, OK
	static void logAbstractType(struct NetworkPacket* abstractData); 
	
	// Fast function that doesn't have to find the packet opcode
	// It does just a log of data->value
	// T can only be either T1 or T2

	// vvv this is the hidden function that should be exported from the lib
	template<class T> static void logType(const T* data) __attribute__((visibility("default")));
};
```

In a lib.cpp:
```
template<class T>
void NetworkPacketLogger::logType(const T* data) {
	std::cout << data->value;
}

void NetworkPacketLogger::logAbstractType(struct NetworkPacket* abstractData) {
	// Possibly generated code is there are many possible network packets
	// This will implicitely instanciate all possible combination of NetworkPacketLogger::logType<T>
	// I want these instanciations to be available by user of the library
	switch(abstractData->type) {
		case Opcode::T1:
			logType(static_cast<T1*>(abstractData));
			break;
		case Opcode::T2:
			logType(static_cast<T2*>(abstractData));
			break;
	}
}
```


I found by tweaking the code that, if I add a __attribute__((visibility("default")))
on struct T1 and struct T2, then logAbstractType<T1> and logAbstractType<T2> are exported.

But why is this required for clang ?
It seems to be like this old bug: https://bugs.llvm.org/show_bug.cgi?id=8457

Is this expected ?
Shouldn't a warning be emitted when a function that should be "visibility("default")"
is not because of one of the arguments use a struct with visibility("hidden") ?


I'm attaching a test case.
Can be compiled with something like this:
```
mkdir build && cd build
CC=clang-9 CXX=clang++-9 cmake ..
make
nm -CD liblib.so  | grep logType
```

nm will print only this (no NetworkPacketLogger::logType<T1>):
00000000000011b0 T NetworkPacketLogger::logAbstractType(NetworkPacket*)
0000000000001260 W void NetworkPacketLogger::logType<T2>(T2 const*)
0000000000001290 W void NetworkPacketLogger::logType<T3>(T3 const*)


Thanks for your hindsight :)

-- 
Alexis Murzeau
PGP: B7E6 0EBB 9293 7B06 BDBC  2787 E7BD 1904 F480 937F
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cmake-test-case.zip
Type: application/octet-stream
Size: 1619 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-users/attachments/20200330/4dc7f72e/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.llvm.org/pipermail/cfe-users/attachments/20200330/4dc7f72e/attachment.sig>


More information about the cfe-users mailing list