I have a file that contains the following:
#include <map>
class A {};
void doSomething() {
std::map<int, A> m;
}
When compiled into a shared library with g++, the library contains dynamic symbols for all the methods of std::map<int, A>. Since A is private to this file, there is no possibility that std::map will be instantiated in any other shared library with the same parameters, so I’d like to make the template instantiation hidden (for some of the reasons described in this document).
I thought I should be able to do this by adding an explicit instantiation of the template class and marking it as hidden, like so:
#include <map>
class A {};
template class __attribute__((visibility ("hidden"))) std::map<int, A>;
void doSomething() {
std::map<int, A> m;
}
However, this has no effect: the symbols are still all exported. I also tried surrounding the entire file with:
#pragma GCC visibility push(hidden)
...
#pragma GCC visibility pop
but this also has no effect on the visibility of the methods of std::map<int, A> (although it does hide doSomething). Similarly, compiling with -fvisibility=hidden has no effect on the visibility of the methods of std::map<int, A>.
The document I linked to above describes the use of export maps to restrict visibility, but that seems very tedious.
Is there a way to do what I want in g++ (other than using export maps)? If so, what is it? If not, is there a good reason why these symbols must always be exported, or is this just a omission in g++?
From GCC bug report #36022, which was marked INVALID, Benjamin Kosnik remarked:
Also, looking through the libstdc++ source for
std::map(mine is in/usr/include/c++/4.4.4/bits/stl_map.h), it appears that the way libstdc++ enforces default visibility is with the_GLIBCXX_BEGIN_NESTED_NAMESPACEmacro that is used at the top ofstl_map.h:Therefore your STL implementation is explicitly overriding
-fvisibility=hiddenand#pragma GCC visibility push(hidden)/#pragma GCC visibility pop.If you really wanted to force the
std::mapmembers to have hidden visibility then I think you could use something like:Then, the following series of commands will verify that the
std::map<int, A>members can be stripped from a shared object:g++ -c -fPIC -fvisibility=hidden test.cppg++ -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0 test.ostrip -x libtest.so.1.0readelf -s libtest.so.1.0Note that before step 3,
readelf -s libtest.so.1.0printed (for me):And afterward:
See also: