c++ - 使用 -O3 在 GCC 中编译共享库不会导出与 -O0 一样多的符号

标签 c++ linux templates gcc shared

我想征求你的意见。 我在 gcc 下编译共享库时遇到问题。

有几个模板类和方法。通过 -o0 优化,每个都按预期导出,在 -o3 中,其中一些将被隐藏/不编译/不导出(nm 输出清楚地显示了这一点)。看起来这些方法正在内联,并且存在一个错误。我看不出不同的原因。

问题:如何导出-o3优化中的所有符号。为什么 -o0 产生的结果比 -o3 多。

对于共享库中的模板,也许我需要一些特殊处理?例如,我应该进行显式模板特化?

如果需要,我将准备一个尽可能小的示例来解决该问题。

编辑:

git hub 上的代码和详细 gcc 日志(o0.log 和 o3.log):https://github.com/MOJNICK/shadow/tree/stack_debug/libcomparator

nm output in -O0 (among other not worth to mention symbols):

./lib/libcomparator.so:00000000000008e0 T instantiate()
./lib/libcomparator.so:000000000000098c W IterateProcess<unsigned char>::color_distance(unsigned char*, unsigned char*)
./lib/libcomparator.so:0000000000000950 W IterateProcess<unsigned char>::iterate_H(unsigned char*, unsigned char*)
./lib/libcomparator.so:0000000000000946 W IterateProcess<unsigned char>::IterateProcess()
./lib/libcomparator.so:0000000000000946 W IterateProcess<unsigned char>::IterateProcess()
./lib/libcomparator.so:0000000000000919 W std::pow(double, int)

nm output in -O3 (among other not worth to mention symbols): ./lib/libcomparator.so:00000000000006a0 T instantiate()

libcomparator.hpp

#ifndef COMPARATOR_HPP
    #define COMPARATOR_HPP
    #include <cmath>

    typedef char unsigned UCHAR;

    template <class TYPE>
    class IterateProcess
    {
    public:
        IterateProcess();
        double iterate_H(TYPE* pix0, TYPE* pix1);
        double color_distance(TYPE* pix0, TYPE* pix1);
    private:        
    };
#endif

libcomparator.cpp:

#include "libcomparator.hpp"

template <class TYPE> IterateProcess<TYPE>::IterateProcess(){}

template <class TYPE> double IterateProcess<TYPE>::iterate_H(TYPE* pix0, TYPE* pix1)
{
    return color_distance(pix0, pix1);
}

template <class TYPE> double IterateProcess<TYPE>::color_distance(TYPE* pix0, TYPE* pix1)
{
    double var = -(pix1[0] / static_cast<double>(pix0[0]) + pix1[1] / static_cast<double>(pix0[1]) + pix1[2] / static_cast<double>(pix0[2]));//for minimize color_distance
    return std::pow(pix1[0] / static_cast<double>(pix0[0]) + var, 2) + std::pow(pix1[1] / static_cast<double>(pix0[1]) + var, 2) + std::pow(pix1[2] / static_cast<double>(pix0[2]) + var, 2);
}

void instantiate()
{
    UCHAR pix [] = {10,10,10};
    IterateProcess<UCHAR> specifyIT;
    specifyIT.iterate_H(pix, pix);
}

如果需要构建,请在Release中进行。 要将 -O3 切换到 -O0 注释掉主 CmakeLists.txt 中的行:

字符串(REPLACE "-O3""-O0"CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})

最佳答案

您必须告诉编译器它应该始终导出符号,即使它们可以在优化时被删除,例如:

 template class __attribute__((visibility ("default"))) IterateProcess<UCHAR>;

在类定义之后添加此内容,您应该导出符号。

添加此后我得到:

0000000000000910 W _ZN14IterateProcessIhE14color_distanceEPhS1_
0000000000000880 W _ZN14IterateProcessIhE9iterate_HEPhS1_
0000000000000870 W _ZN14IterateProcessIhEC1Ev
0000000000000870 W _ZN14IterateProcessIhEC2Ev

我编译的是:

 g++ -shared main.cpp -O3 -o x.so -fPIC

编辑:为什么默认情况下看不到优化的代码:

只是因为它没有生成!如果您从 instantiate 进行的调用是完全内联的,则任何对象文件中都不会留下任何代码,因为不再需要它。为了创建共享库,您必须告诉编译器您确实想要获取当前未使用的实例。但这是一个非常晦涩的用例!在 C++ 中,您应该在头文件中尽可能多地呈现,以使编译器能够尽可能优化!因此,很少将 .h/.cpp 中的代码拆分并将模板代码放入 cpp 文件中,我建议您避免这种情况。

关于c++ - 使用 -O3 在 GCC 中编译共享库不会导出与 -O0 一样多的符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50401125/

相关文章:

c++ - cv::findContours 正在修改源图像 OpenCV 2.3

c++ - C/C++ - 牛顿法的迭代计数器

linux - 读取并删除名称中包含空格的文件

linux - 为什么不带 "not stripped, with debug_info"选项的可执行文件file命令在编译时报 "-g"?

C++模板类继承和运算符使用

c++ - 保持从一个函数到另一个函数的流打开

c++ - 使用c++静态类成员控制所有类实例的 "mode"

linux - 在 Linux 中删除文件所需的最小文件权限

c++ - 区分STL容器

c++ - 模板参数模棱两可/推导了参数的冲突类型