We\'ve recently been asked to ship a Linux version of one of our libraries, previously we\'ve developed under Linux and shipped for Windows where deploying libraries is gene
In general, across multiple Linux and Unix systems, the answer here is that there is no answer here at link time. it's fairly fundamental to how ld.so works.
This leads to some rather labor-intensive alternatives. For example, we rename STL to live in _STL instead of std
to avoid conflicts over STL, and we use namespaces high, low, and in-between to keep our symbols away from possible conflicts with other people's symbols.
Here's a solution you won't love:
So long as you don't use RTLD_GLOBAL, you now have complete insulation if not particular secrecy .. -Bsymbolic might also be desirable.
Actually, in the ELF structure there are 2 symbol tables: "symtab" and "dynsym" -> see this: Hiding symbol names in library
If you wrap up your private part in an anonymous namespace then neither std::abs
nor private_function
can be seen in the symbol table:
namespace{
#include<cmath>
float private_function(float f)
{
return std::abs(f);
}
}
extern "C" float public_function(float f)
{
return private_function(f);
}
compiling (g++ 4.3.3):
g++ -shared -o libtest.so test.cpp -s
inspecting:
# nm -DC libtest.so
w _Jv_RegisterClasses
0000200c A __bss_start
w __cxa_finalize
w __gmon_start__
0000200c A _edata
00002014 A _end
000004a8 T _fini
000002f4 T _init
00000445 T public_function
Just to note that Ulrich Drepper wrote an essay regarding (all?) aspects of writing shared libraries for Linux/Unix, which covers control of exported symbols amongst many other topics.
This was very handy in making it clear how to export only functions on a whitelist from a shared lib.
Your use of the default visibility attribute and -fvisibility=hidden should be augmented with -fvisibility-inlines-hidden.
You should also forget about trying to hide stdlib exports, see this GCC bug for why.
Also, if you have all of your public symbols in a specific headers you can wrap them in #pragma GCC visibility push(default)
and #pragma GCC visibility pop
instead of using attributes. Though if you are creating a cross platform library, take a look at Controlling Exported Symbols of Shared Libraries for a technique to unify your windows DLL and Linux DSO export strategy.
So the solution we have for now is as follows:
test.cpp
#include <cmath>
#include <vector>
#include <typeinfo>
struct private_struct
{
float f;
};
float private_function(float f)
{
return std::abs(f);
}
void other_private_function()
{
std::vector<private_struct> f(1);
}
extern "C" void __attribute__ ((visibility ("default"))) public_function2()
{
other_private_function();
}
extern "C" float __attribute__ ((visibility ("default"))) public_function1(float f)
{
return private_function(f);
}
exports.version
LIBTEST
{
global:
public*;
local:
*;
};
compiled with
g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
gives
00000000 A LIBTEST
w _Jv_RegisterClasses
U _Unwind_Resume
U std::__throw_bad_alloc()
U operator delete(void*)
U operator new(unsigned int)
w __cxa_finalize
w __gmon_start__
U __gxx_personality_v0
000005db T public_function1
00000676 T public_function2
Which is fairly close to what we're looking for. There are a few gotchas though:
I'm happy to accept any better solutions anyone comes up with!