プライベート部分を匿名の名前空間にラップすると、 std::abs
もありません private_function
でもありません 記号表で見ることができます:
namespace{
#include<cmath>
float private_function(float f)
{
return std::abs(f);
}
}
extern "C" float public_function(float f)
{
return private_function(f);
}
コンパイル中 (g++ 4.3.3):
g++ -shared -o libtest.so test.cpp -s
検査:
# 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
Ulrich Drepper が、Linux/Unix の共有ライブラリを作成する際の (すべての?) 側面に関するエッセイを書いたことに注意してください。このエッセイでは、他の多くのトピックの中でも、エクスポートされたシンボルの制御について説明しています。
これは、共有ライブラリからホワイトリストの関数のみをエクスポートする方法を明確にするのに非常に便利でした.
デフォルトの表示属性と -fvisibility=hidden の使用は、-fvisibility-inlines-hidden で強化する必要があります。
また、stdlib エクスポートを非表示にしようとすることも忘れてください。理由については、この GCC バグを参照してください。
また、特定のヘッダーにすべてのパブリック シンボルがある場合は、それらを #pragma GCC visibility push(default)
でラップできます。 と #pragma GCC visibility pop
属性を使用する代わりに。ただし、クロス プラットフォーム ライブラリを作成している場合は、Windows DLL と Linux DSO のエクスポート戦略を統合する手法について、共有ライブラリのエクスポートされたシンボルの制御を参照してください。
したがって、現時点での解決策は次のとおりです。
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:
*;
};
でコンパイル
g++ -shared test.cpp -o libtest.so -fvisibility=hidden -fvisibility-inlines-hidden -s -Wl,--version-script=exports.version
与える
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
これは、私たちが探しているものにかなり近いものです。ただし、いくつかの落とし穴があります:
- 内部コードで "exported" プレフィックス (この単純な例では "public" ですが、この場合は明らかにもっと便利なもの) を使用しないようにする必要があります。
- まだ多くのシンボル名が文字列テーブルに残っており、これは RTTI にかかっているようです。-fno-rtti を使用すると、私の簡単なテストではそれらがなくなりますが、核となる解決策です。
誰かが思いついたより良い解決策を喜んで受け入れます!