在使用 g++ 创建的共享库中隐藏实例化模板
Posted
技术标签:
【中文标题】在使用 g++ 创建的共享库中隐藏实例化模板【英文标题】:Hiding instantiated templates in shared library created with g++ 【发布时间】:2011-02-24 14:30:10 【问题描述】:我有一个包含以下内容的文件:
#include <map>
class A ;
void doSomething()
std::map<int, A> m;
当使用 g++ 编译成共享库时,该库包含 std::map<int, A>
的所有方法的动态符号。由于A
对该文件是私有的,因此std::map
不可能在具有相同参数的任何其他共享库中被实例化,所以我想隐藏模板实例化(出于某些原因在this document)。
我认为我应该能够通过添加模板类的显式实例并将其标记为隐藏来做到这一点,如下所示:
#include <map>
class A ;
template class __attribute__((visibility ("hidden"))) std::map<int, A>;
void doSomething()
std::map<int, A> m;
但是,这没有任何效果:符号仍然全部导出。我还尝试使用以下命令包围整个文件:
#pragma GCC visibility push(hidden)
...
#pragma GCC visibility pop
但这对std::map<int, A>
的方法的可见性也没有影响(尽管它确实隐藏了doSomething
)。同样,使用-fvisibility=hidden
编译对std::map<int, A>
的方法的可见性没有影响。
我上面链接的文档描述了使用导出地图来限制可见性,但这似乎很乏味。
有没有办法在 g++ 中做我想做的事情(除了使用导出映射)?如果是这样,它是什么?如果没有,是否有充分的理由为什么必须始终导出这些符号,或者这只是 g++ 中的一个遗漏?
【问题讨论】:
您如何看待这些符号?nm -g your_lib.so
?我的意思是我做了同样的实验,看到doSomething
要么有T
标签,要么在我说fvisibility=hidden
时隐藏,但std::map 符号总是有W
标签。文件说:Weak definitions only play role in static linking
。您以何种方式使用您的图书馆?
我一直在使用readelf -p .dynstr foo.so
。感谢您指出这些是弱符号。谷歌搜索“弱符号模板”产生了一些有趣的结果,比如这个:gcc.gnu.org/bugzilla/show_bug.cgi?id=36022,我不完全理解,但听起来可能密切相关。
我对文档中文字的理解是,弱符号仅与静态链接有关,而不是弱符号仅用于静态链接。
是的,我认为是密切相关的。
我不确定您的最后评论。但是我认为 gcc 文档中的要点是 thisL The std:: namespace is supposed to be exposed and is marked as such in the libstdc++ headers.
【参考方案1】:
来自 GCC 错误报告 #36022,标记为 INVALID,Benjamin Kosnik 评论道:
[A]n 将在 DSO 之间抛出的异常类必须是 用默认可见性显式标记,以便 `type_info' 节点将 DSO 之间的统一。 因此,libstdc++ 具有命名空间 std 的基本原理具有可见性 “默认。”
此外,查看 std::map
的 libstdc++ 源代码(我的在 /usr/include/c++/4.4.4/bits/stl_map.h
中),似乎 libstdc++ 强制默认可见性的方式是使用 _GLIBCXX_BEGIN_NESTED_NAMESPACE
顶部使用的 stl_map.h
宏:
# define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ (#V)))
# define _GLIBCXX_BEGIN_NESTED_NAMESPACE(X, Y) _GLIBCXX_BEGIN_NAMESPACE(X)
# define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X _GLIBCXX_VISIBILITY_ATTR(default)
因此,您的 STL 实现明确覆盖 -fvisibility=hidden
和 #pragma GCC visibility push(hidden)
/#pragma GCC visibility pop
。
如果你真的想强制 std::map
成员隐藏可见性,那么我认为你可以使用类似的东西:
// ensure that default visibility is used with any class that is used as an exception type
#include <memory>
#include <new>
#include <stdexcept>
// now include the definition of `std::map` using hidden visibility
#include <bits/c++config.h>
#undef _GLIBCXX_VISIBILITY_ATTR
#define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ ("hidden")))
#include <map>
#undef _GLIBCXX_VISIBILITY_ATTR
#define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ (#V))) // restore `_GLIBCXX_VISIBILITY_ATTR`
然后,以下一系列命令将验证 std::map<int, A>
成员是否可以从共享对象中剥离:
g++ -c -fPIC -fvisibility=hidden test.cpp
g++ -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0 test.o
strip -x libtest.so.1.0
readelf -s libtest.so.1.0
请注意,在第 3 步之前,readelf -s libtest.so.1.0
已打印(对我而言):
Symbol table '.dynsym' contains 23 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
3: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv@GLIBCXX_3.4 (2)
4: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 (3)
5: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 (4)
6: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (5)
7: 00000d02 5 FUNC WEAK DEFAULT 12 _ZNSt4pairIKi1AED1Ev
8: 00000d6c 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEEC1ISt
9: 00000d96 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
10: 000023bc 0 NOTYPE GLOBAL DEFAULT ABS _end
11: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS _edata
12: 00000d5e 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
13: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
14: 00000bac 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
15: 00000d08 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
16: 000007f4 0 FUNC GLOBAL DEFAULT 10 _init
17: 00000c4a 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
18: 00000df8 0 FUNC GLOBAL DEFAULT 13 _fini
19: 00000dba 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
20: 00000cde 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEED1Ev
21: 00000d90 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
22: 00000ac6 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
Symbol table '.symtab' contains 84 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 000000f4 0 SECTION LOCAL DEFAULT 1
2: 00000118 0 SECTION LOCAL DEFAULT 2
3: 000001c0 0 SECTION LOCAL DEFAULT 3
4: 0000022c 0 SECTION LOCAL DEFAULT 4
5: 0000039c 0 SECTION LOCAL DEFAULT 5
6: 000006b6 0 SECTION LOCAL DEFAULT 6
7: 000006e4 0 SECTION LOCAL DEFAULT 7
8: 00000754 0 SECTION LOCAL DEFAULT 8
9: 0000077c 0 SECTION LOCAL DEFAULT 9
10: 000007f4 0 SECTION LOCAL DEFAULT 10
11: 00000824 0 SECTION LOCAL DEFAULT 11
12: 00000930 0 SECTION LOCAL DEFAULT 12
13: 00000df8 0 SECTION LOCAL DEFAULT 13
14: 00000e14 0 SECTION LOCAL DEFAULT 14
15: 00000ef8 0 SECTION LOCAL DEFAULT 15
16: 00001240 0 SECTION LOCAL DEFAULT 16
17: 0000225c 0 SECTION LOCAL DEFAULT 17
18: 00002264 0 SECTION LOCAL DEFAULT 18
19: 0000226c 0 SECTION LOCAL DEFAULT 19
20: 00002270 0 SECTION LOCAL DEFAULT 20
21: 00002358 0 SECTION LOCAL DEFAULT 21
22: 00002364 0 SECTION LOCAL DEFAULT 22
23: 000023ac 0 SECTION LOCAL DEFAULT 23
24: 000023b4 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 0000225c 0 OBJECT LOCAL DEFAULT 17 __CTOR_LIST__
28: 00002264 0 OBJECT LOCAL DEFAULT 18 __DTOR_LIST__
29: 0000226c 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__
30: 00000930 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
31: 000023b4 1 OBJECT LOCAL DEFAULT 24 completed.5942
32: 000023b8 4 OBJECT LOCAL DEFAULT 24 dtor_idx.5944
33: 000009b0 0 FUNC LOCAL DEFAULT 12 frame_dummy
34: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
35: 00002260 0 OBJECT LOCAL DEFAULT 17 __CTOR_END__
36: 0000123c 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__
37: 0000226c 0 OBJECT LOCAL DEFAULT 19 __JCR_END__
38: 00000dc0 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
39: 00000000 0 FILE LOCAL DEFAULT ABS test.cpp
40: 00000d64 8 FUNC LOCAL HIDDEN 12 _ZNKSt8_Rb_treeIiSt4pairI
41: 000023b0 4 OBJECT LOCAL HIDDEN 23 DW.ref.__gxx_personality_
42: 00000b40 11 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
43: 00000bc8 129 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
44: 00000bb1 11 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
45: 00000b4c 96 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
46: 00000ca0 62 FUNC LOCAL HIDDEN 12 _ZNKSt8_Rb_treeIiSt4pairI
47: 00000ab2 19 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
48: 00002364 0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
49: 00000a56 92 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
50: 000009ec 30 FUNC LOCAL HIDDEN 12 _Z11doSomethingv
51: 00000c6e 49 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
52: 00000a32 35 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
53: 000023ac 0 OBJECT LOCAL HIDDEN 23 __dso_handle
54: 00000a0a 19 FUNC LOCAL HIDDEN 12 _ZNSt3mapIi1ASt4lessIiESa
55: 00002268 0 OBJECT LOCAL HIDDEN 18 __DTOR_END__
56: 00000bbc 11 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
57: 00000a1e 19 FUNC LOCAL HIDDEN 12 _ZNSt3mapIi1ASt4lessIiESa
58: 00000d2c 50 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
59: 00000aea 85 FUNC LOCAL HIDDEN 12 _ZNSt8_Rb_treeIiSt4pairIK
60: 000009e7 0 FUNC LOCAL HIDDEN 12 __i686.get_pc_thunk.bx
61: 00002270 0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
62: 00000d02 5 FUNC WEAK DEFAULT 12 _ZNSt4pairIKi1AED1Ev
63: 00000c4a 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
64: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
65: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
66: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv@@GLIBCXX_3.4
67: 00000df8 0 FUNC GLOBAL DEFAULT 13 _fini
68: 00000d6c 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEEC1ISt
69: 00000dba 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
70: 00000cde 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEED1Ev
71: 00000d5e 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
72: 00000d90 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
73: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
74: 00000d96 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
75: 00000bac 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
76: 000023bc 0 NOTYPE GLOBAL DEFAULT ABS _end
77: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS _edata
78: 00000ac6 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
79: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@@CXX
80: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@@GCC_3.0
81: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1
82: 00000d08 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
83: 000007f4 0 FUNC GLOBAL DEFAULT 10 _init
然后:
Symbol table '.dynsym' contains 23 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
3: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv@GLIBCXX_3.4 (2)
4: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@CXXABI_1.3 (3)
5: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@GCC_3.0 (4)
6: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (5)
7: 00000d02 5 FUNC WEAK DEFAULT 12 _ZNSt4pairIKi1AED1Ev
8: 00000d6c 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEEC1ISt
9: 00000d96 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
10: 000023bc 0 NOTYPE GLOBAL DEFAULT ABS _end
11: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS _edata
12: 00000d5e 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
13: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
14: 00000bac 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
15: 00000d08 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
16: 000007f4 0 FUNC GLOBAL DEFAULT 10 _init
17: 00000c4a 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
18: 00000df8 0 FUNC GLOBAL DEFAULT 13 _fini
19: 00000dba 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
20: 00000cde 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEED1Ev
21: 00000d90 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
22: 00000ac6 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
Symbol table '.symtab' contains 51 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 000000f4 0 SECTION LOCAL DEFAULT 1
2: 00000118 0 SECTION LOCAL DEFAULT 2
3: 000001c0 0 SECTION LOCAL DEFAULT 3
4: 0000022c 0 SECTION LOCAL DEFAULT 4
5: 0000039c 0 SECTION LOCAL DEFAULT 5
6: 000006b6 0 SECTION LOCAL DEFAULT 6
7: 000006e4 0 SECTION LOCAL DEFAULT 7
8: 00000754 0 SECTION LOCAL DEFAULT 8
9: 0000077c 0 SECTION LOCAL DEFAULT 9
10: 000007f4 0 SECTION LOCAL DEFAULT 10
11: 00000824 0 SECTION LOCAL DEFAULT 11
12: 00000930 0 SECTION LOCAL DEFAULT 12
13: 00000df8 0 SECTION LOCAL DEFAULT 13
14: 00000e14 0 SECTION LOCAL DEFAULT 14
15: 00000ef8 0 SECTION LOCAL DEFAULT 15
16: 00001240 0 SECTION LOCAL DEFAULT 16
17: 0000225c 0 SECTION LOCAL DEFAULT 17
18: 00002264 0 SECTION LOCAL DEFAULT 18
19: 0000226c 0 SECTION LOCAL DEFAULT 19
20: 00002270 0 SECTION LOCAL DEFAULT 20
21: 00002358 0 SECTION LOCAL DEFAULT 21
22: 00002364 0 SECTION LOCAL DEFAULT 22
23: 000023ac 0 SECTION LOCAL DEFAULT 23
24: 000023b4 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
27: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 00000000 0 FILE LOCAL DEFAULT ABS test.cpp
29: 00000d02 5 FUNC WEAK DEFAULT 12 _ZNSt4pairIKi1AED1Ev
30: 00000c4a 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
31: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
32: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
33: 00000000 0 FUNC GLOBAL DEFAULT UND _ZdlPv@@GLIBCXX_3.4
34: 00000df8 0 FUNC GLOBAL DEFAULT 13 _fini
35: 00000d6c 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEEC1ISt
36: 00000dba 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
37: 00000cde 35 FUNC WEAK DEFAULT 12 _ZNSaISt4pairIKi1AEED1Ev
38: 00000d5e 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
39: 00000d90 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
40: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
41: 00000d96 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
42: 00000bac 5 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
43: 000023bc 0 NOTYPE GLOBAL DEFAULT ABS _end
44: 000023b4 0 NOTYPE GLOBAL DEFAULT ABS _edata
45: 00000ac6 35 FUNC WEAK DEFAULT 12 _ZNSaISt13_Rb_tree_nodeIS
46: 00000000 0 FUNC GLOBAL DEFAULT UND __gxx_personality_v0@@CXX
47: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume@@GCC_3.0
48: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1
49: 00000d08 35 FUNC WEAK DEFAULT 12 _ZN9__gnu_cxx13new_alloca
50: 000007f4 0 FUNC GLOBAL DEFAULT 10 _init
另见:
Visibility - GCC Wiki Controlling Symbol Visibility【讨论】:
我已经找到了那个错误报告,并且刚刚查看了 c++ 头文件,但是我没有想到重新定义 _GLIBCXX_VISIBILITY_ATTR 的想法。这很邪恶,但我可以试一试。谢谢。 我的 GCC 是 4.6,我发现宏 _GLIBXX_VISIBILITY_ATTR 被重命名为 _GLIBXX_VISIBILITY。并且这个宏应该重新定义为#define _GLIBCXX_VISIBILITY(V)
而不是#define _GLIBCXX_VISIBILITY(V) __attribute__((__visibility__("hidden")))
,否则可能会出现undefined reference to 'std::__throw_bad_alloc()'之类的链接错误。【参考方案2】:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36022:
The std::namespace is supposed to be exposed and is marked as such in the libstdc++ headers.
至于
#undef _GLIBCXX_VISIBILITY_ATTR
这是另一个引用:
If you were to hack in support for allowing namespace std to have
hidden visibility, and run the testsuite with -fvisibility=hidden (see attached
patch) you would notice the breakdown in testresults, with mass failures.
【讨论】:
【参考方案3】:免责声明:我不是 GCC 开发人员,因此这是一个完整的 WAG(疯狂猜测):
我的猜测是 GCC 总是导出模板定义,以允许链接器删除模板的重复副本。如果它没有被导出并且不止一次源文件使用该模板,std::map<k, v>
类的整个源代码将在两个文件中复制。
我认为您对此的关注确实超出了应有的水平。导出是 C++ 中的一个实现细节。在 C 中,不导出内部函数是有意义的,这样客户就不会依赖它们。但在 C++ 中,导出的函数永远不必与源代码有任何关系。 GCC 的std::map<k, v>
的一个版本可能与另一个版本完全不同,因此这两个二进制文件将不兼容链接。
如果您绝对需要可移植性,请导出 C 接口并忽略导出的 C++ 细节。任何试图调用此类导出或对它们进行任何操作的库客户端都应该因为调用明显的内部实现细节而崩溃和烧毁。
编辑:制作 CW 是因为我不是 100% 肯定的。
【讨论】:
我想隐藏这些符号的原因实际上并不是为了防止库的用户调用它们,而是为了减小.so文件的大小。我们使用代码生成器生成包含数千个此类导出符号的库,从而为动态符号表的大小增加了数百 kB。减少导出符号的数量将为我们节省大量磁盘空间和内存,同时缩短加载时间并允许编译器生成更高效的代码。 @jchl:您在这里进行了微优化。我不会担心,因为当生成可执行文件时,这些导出列表无论如何都会被删除。 我正在构建一个共享库,而不是一个可执行文件。在大多数环境中,这确实是不必要的微优化,但由于我们生成大量代码和大量使用模板,这种优化有可能为我们节省数 MB 的磁盘空间和 RAM,这两者都在优质的。此外,此时我只想知道为什么我不能让它工作。【参考方案4】:也许您可以将 objcopy 与 --strip-symbol 选项一起使用?
该选项在 objcopy 中描述man page
这可能会变得乏味......
【讨论】:
该选项听起来并不比使用导出地图更好。由于这是生成的代码,理想情况下,我想要一个只涉及修改源代码而不使用额外工具的解决方案。【参考方案5】:在 C++ 中,如果模板参数的可见性有限,则此限制会隐式传播到模板实例化。
#include <map>
class __attribute__((visibility ("hidden"))) A ;
void doSomething()
std::map<int, A> m;
应该做的工作。
-- 编辑-- 还有一件事,`#pragma GCC visibility' 只影响命名空间范围的声明。类成员和模板特化不受影响 (Visibility pragmas)
【讨论】:
我刚试了一下,遗憾的是它似乎对实例化模板的可见性没有任何影响。 你是对的。似乎强制执行了 stl 可见性。这可能会有所帮助gcc.gnu.org/bugzilla/show_bug.cgi?id=36022。以上是关于在使用 g++ 创建的共享库中隐藏实例化模板的主要内容,如果未能解决你的问题,请参考以下文章