在使用 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&lt;int, A&gt; 的所有方法的动态符号。由于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&lt;int, A&gt; 的方法的可见性也没有影响(尽管它确实隐藏了doSomething)。同样,使用-fvisibility=hidden 编译对std::map&lt;int, A&gt; 的方法的可见性没有影响。

我上面链接的文档描述了使用导出地图来限制可见性,但这似乎很乏味。

有没有办法在 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&lt;int, A&gt; 成员是否可以从共享对象中剥离:

    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&lt;k, v&gt; 类的整个源代码将在两个文件中复制。

我认为您对此的关注确实超出了应有的水平。导出是 C++ 中的一个实现细节。在 C 中,不导出内部函数是有意义的,这样客户就不会依赖它们。但在 C++ 中,导出的函数永远不必与源代码有任何关系。 GCC 的std::map&lt;k, v&gt; 的一个版本可能与另一个版本完全不同,因此这两个二进制文件将不兼容链接。

如果您绝对需要可移植性,请导出 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++ 创建的共享库中隐藏实例化模板的主要内容,如果未能解决你的问题,请参考以下文章

无法强制实例化专用模板

带有非类型参数的奇怪模板实例化错误

创建实例后向 Vue 实例添加组件

关于模板

如何用 swig 实例化模板类的模板方法?

用于实例化模板代码的显式习惯用法 - 不包括其源代码