内联模板功能的可见性

phl*_*psy 9 c++ gcc templates visibility elf

编译事实背后的理性是什么?

namespace ns __attribute__((visibility("default"))) {

template<typename T>
inline int func1(const T& x) {
    return x;
}

inline int func2(int x) {
    return x;
}

struct test {
    template<typename T>
    int func3(const T &x) { return x; }

    int func4(int x) { return x; }
};

}

int __attribute__((visibility("default"))) client(int x) {
    ns::test t;
    const int y1 = ns::func1(x);
    const int y2 = ns::func2(x);
    const int y3 = t.func3(x);
    const int y4 = t.func4(x);
    return y1 + y2 + y3 + y4;
}
Run Code Online (Sandbox Code Playgroud)

g++ -Wall -fPIC \
    -fvisibility=hidden -fvisibility-inlines-hidden \
    -shared -o libtest.so test.cpp
Run Code Online (Sandbox Code Playgroud)

产生一个库中导出ns::test::func1<int>()ns::test::func3<int>(),但不ns::func2()ns::test::func4()?两个模板函数都被定义inline-fvisibility-inlines-hidden告诉编译器隐藏它们 - 或者至少它们的实例化也希望它们也是内联的.

隐藏函数模板func1func3明确的,即用

 template<typename T>
 int __attribute__((visibility("hidden"))) func(const T &x) { return x; }
Run Code Online (Sandbox Code Playgroud)

导致预期的行为.省略命名空间定义中的默认可见性会隐藏两个实例.

背景:我们尝试最小化库中可见符号的数量.因此,我们使用上面提到的编译器标志和属性.当然,这对于所有静态第三方库也是必需的.但遗憾的是,包含头文件的内联模板函数完全不受我们的控制.例如,每个实例化

namespace std {

template<typename _CharT, typename _Traits, typename _Alloc>
inline bool
operator==(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
    const _CharT* __rhs)
{ return __lhs.compare(__rhs) == 0; }

}
Run Code Online (Sandbox Code Playgroud)

来自#include <string>将愉快地在我的图书馆内生成一个公开可见的符号.而最烦人的部分,它将放在我的库中没有任何版本信息,所以没有GLIBCXX_3.x.z区别.

奖金问题:使用链接器脚本的总体影响是什么

{
    global:
        _Z6clienti;
    local:
        *;
};
Run Code Online (Sandbox Code Playgroud)

据我所知,如果我不在我的库的边界使用任何异常处理或动态类型转换,这只是真的可行.但是这些内联函数会发生什么?感觉这整个隐藏的可见性事物无论如何违反了一个定义规则,因此它并不是什么大问题.

amo*_*kov 2

GCC 不尊重-fvisibility-inlines-hidden模板函数;这是一个从 gcc-10 开始修复的错误

在 GCC 10 中,所有四个函数都具有隐藏可见性(命令行标志优先于封闭命名空间中指定的可见性属性)。