问题描述
在定制tensorflow的过程中,进行bazel build的过程中莫名提示如下的undefined reference to `tensorflow::DataTypeToEnum<float>::value' 的错误,由于并没有修改过tensorflow的相关source code,所以感觉很困惑
问题分析
- 报错的DataTypeToEnum是一个template struct,它的定义在tensorflow/core/framework/types.h 中,并且紧跟着定义之后通过宏MATCH_TYPE_AND_ENUM(xxx, DT_xxx) 实例化了不同的DataTypeToEnum<xxx>类型,
- 照理在tensorflow/core/kernels/conv_ops_benchmark_test.cc的开头就include了头文件tensorflow/core/framework/types.h,那么根据上面对types.h的分析,MATCH_TYPE_AND_ENUM(float, DT_FLOAT);宏已经实例化了struct tensorflow::DataTypeToEnum<float> 类型,并且定义了tensorflow::DataTypeToEnum<float>::value 成员,不应该会发生build过程中undefined reference
- 仔细分析DataTypeToEnum中 static constexpr DataType value 这个成员的声明,怀疑蹊跷处在static constexpr 的修饰符上,百度static constexpr后发现很多说明该修饰符的用法和特性,其中特别强调了它会在编译阶段被编译器直接优化成一个常量,提示了自己在定制tensorflow的过程中为了debug tensorflow的运行过程,将gcc的编译开关做过调整:改为了-O0 -g,即不做任何优化编译带debug symbol的binary;通过将编译开关改为-O2 后即可以正常编译通过,问题得到解决
- 为了进一步求证编译开关对static constexpr的影响,可以使用下面的问题重现示意代码
//base.h
class base {
public:
static constexpr unsigned int A_VAL{0x69U};
};
//derived.h
#include "base.h"
#include <iostream>
using namespace std;
class derived : public base
{
public:
int some_func(void) {
cout << "Some func" << endl;
return 0;
}
};
//concrete.h
#include "derived.h"
#include <utility>
class concrete : public derived
{
public:
concrete(int a, std::pair<unsigned int, unsigned int> data = {A_VAL, A_VAL}) {
some_func();
std::cout << "First: " << data.first << " Second: " << data.second << endl;
}
};
//main.cpp
#include "concrete.h"
int main (int argc, char *argv[])
{
concrete c{1};
c.some_func();
}
- 使用-O2优化编译成功,程序运行成功
# g++ -O2 -std=c++11 main.cpp -o main
# ./main
Some func
First: 105 Second: 105
Some func
- 使用-O0不带优化编译,发生找不到static constexpr修饰符的成员变量A_VAL
# g++ -O0 -std=c++11 main.cpp -o main
/tmp/ccBUwOEa.o: In function `main':
main.cpp:(.text+0x25): undefined reference to `base::A_VAL'
main.cpp:(.text+0x2c): undefined reference to `base::A_VAL'
collect2: error: ld returned 1 exit status