GCC 中使用 -O3 的共享库编译不会导出与 -O0 中一样多的符号
Shared library compilation in GCC with -O3 don't export as much symbols as in -O0
我会征求你的意见。
我在gcc下编译共享库有问题
有几个模板class和方法。通过 -o0 优化,每个都按预期导出,在 -o3 中,其中一些将 hidden/not compiled/not 导出(nm 输出清楚地显示了这一点)。看起来这些方法正在内联并且存在错误。我看不出有什么不同的原因。
问题:如何导出-o3优化中的所有符号。为什么-o0 产生的比-o3 多。
对于共享库中的模板,也许我需要一些特殊处理?例如,我应该进行明确的模板特化吗?
如果需要,我会准备一个尽可能小的问题示例。
编辑:
git 集线器上的代码和详细 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,请注释掉 main CmakeLists.txt:
中的行
string( REPLACE "-O3" "-O0" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
你必须告诉编译器它应该总是导出符号,即使它们可以在优化的情况下被删除,比如:
template class __attribute__((visibility ("default"))) IterateProcess<UCHAR>;
在您的 class 定义之后添加它,您应该可以导出符号。
添加后我得到:
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 文件中真的很少我建议你避免这种情况。
我会征求你的意见。 我在gcc下编译共享库有问题
有几个模板class和方法。通过 -o0 优化,每个都按预期导出,在 -o3 中,其中一些将 hidden/not compiled/not 导出(nm 输出清楚地显示了这一点)。看起来这些方法正在内联并且存在错误。我看不出有什么不同的原因。
问题:如何导出-o3优化中的所有符号。为什么-o0 产生的比-o3 多。
对于共享库中的模板,也许我需要一些特殊处理?例如,我应该进行明确的模板特化吗?
如果需要,我会准备一个尽可能小的问题示例。
编辑:
git 集线器上的代码和详细 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,请注释掉 main CmakeLists.txt:
中的行string( REPLACE "-O3" "-O0" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
你必须告诉编译器它应该总是导出符号,即使它们可以在优化的情况下被删除,比如:
template class __attribute__((visibility ("default"))) IterateProcess<UCHAR>;
在您的 class 定义之后添加它,您应该可以导出符号。
添加后我得到:
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 文件中真的很少我建议你避免这种情况。