VisualC++ Tensorflow C API Wrapper 导致LNK2019

VisualC++ Tensorflow C API Wrapper causes LNK2019

提问人:ITiger 提问时间:1/18/2018 最后编辑:ITiger 更新时间:1/18/2018 访问量:674

问:

我目前正在编写一个 VisualC++ 12 Tensorflow 包装器,以便为 Tensorflow 对象检测 API 启用推理任务。但是,我遇到了一些类型LNK2019的链接错误(“未解析的外部符号”)。

我研究了此错误的一些常见原因,并发现了以下内容,但我无法在我的代码中发现其中任何一个(原因列在链接器工具错误LNK2019的Microsoft参考中)。

下面是导致错误的代码片段:

  • 文件 TensorflowTensor.h:

    namespace tf {
    class TensorflowTensor : public TensorflowCWrapper<TF_Tensor>
    {
    public:
      TensorflowTensor(const cv::Mat& input_image);
      TensorflowTensor(TF_Tensor* tensor);
    
      // inner class for convenient access to tensors' data
      template<typename DType, size_t D>
      class TensorView
      {
      public:
        TensorView<DType, D>(TensorflowTensor& tensor);
        const DType& operator()(std::array<size_t, D> n) const;
        DType& operator()(std::array<size_t, D> n);
        size_t NumElements() const;
    
      private:
        DType* data_;
        std::array<size_t, D> dims_;
        size_t num_el_;
      };
    
      template<typename DType, size_t D>
      TensorView<DType, D> View();
    };
    }
    
  • TensorflowTensor.cpp 中的实现(仅导致链接器错误的行):

    namespace tf {
    // Constructors of TensorflowTensor are here
    
      template<typename DType, size_t D>
      TensorflowTensor::TensorView<DType, D>::TensorView(TensorflowTensor& tensor)
      {
        if (tensor.NumDims() != D)
        {
          throw std::runtime_error("Number of dimensions do not match!");
        }
    
        num_el_ = 1;
        for (size_t i = 0; i < D; ++i)
        {
          dims_[i] = tensor.Dim(i);
          num_el_ *= dims_[i];
        }
    
        if (tensor.NumBytes() != (num_el_ * sizeof(DType)))
        {
          throw std::runtime_error("Wrong TensorView!");
        }
    
        data_ = static_cast<DType*>(tensor.Bytes());
      }
    
      template<typename DType, size_t D>
      const DType& TensorflowTensor::TensorView<DType, D>::operator()(std::array<size_t, D> n) const
      {
        return data_[ComputeOffset(n)];
      }
    
      template<typename DType, size_t D>
      DType& TensorflowTensor::TensorView<DType, D>::operator()(std::array<size_t, D> n)
      {
        return data_[ComputeOffset(n)];
      }
    
      template<typename DType, size_t D>
      size_t TensorflowTensor::TensorView<DType, D>::NumElements() const
      {
        return num_el_;
      }
    
      template<typename DType, size_t D>
      TensorflowTensor::TensorView<DType, D> TensorflowTensor::View()
      {
        return TensorView<DType, D>(*this);
      }
    }
    
  • 以下是我从中调用函数的行(在方法中: ):TensorflowInference::detect(* some args */)

    const auto output_scores = result_tensors[0]->TensorflowTensor::View<float, 2>();
    const auto output_boxes = result_tensors[1]->TensorflowTensor::View<float, 3>();
    const auto output_classes = result_tensors[2]->TensorflowTensor::View<float, 2>();
    
    // copy detections to the results vector
    results.clear();
    for (size_t i = 0; i < output_scores.NumElements(); ++i)
    {
      if (output_scores({{0, i}}) > 0.)
      {
        results.emplace_back(output_classes({{ 0, i }}),
          output_scores({{ 0, i }}),
          output_boxes({{ 0, i, 1 }}),
          output_boxes({{ 0, i, 0 }}),
          output_boxes({{ 0, i, 3 }}),
          output_boxes({{ 0, i, 2 }}));
      }
    }
    

如果我注释这些行,我不会收到错误。

我已经包含了所有头文件,除了以下 5 个 LNK2019 之外,没有收到任何编译器错误或警告:

TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)” (??$View@M$01@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$01@01@XZ) 在函数 “public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)

TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const ” (??R?$TensorView@M$01@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$01@std@@@Z) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)

TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public:unsigned __int64 __cdecl tf::TensorflowTensor::TensorView::NumElements(void)const ”(?01@TensorflowTensor@tf@@QEBA_KXZ$TensorView NumElements@函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z) 中引用

TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)” (??$View@M$02@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$02@01@XZ) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)

TensorflowInference.obj:错误 LNK2019:未解析的外部符号“public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const ” (??R?$TensorView@M$02@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$02@std@@@Z) 在函数“public: void __cdecl tf::TensorflowInference::d etect(class cv::Mat const &,class std::vector > &)const ” (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)

主啊,这是一堵文字墙,但我只包括了错误的重要行。

我很感激任何帮助我解决这些错误的提示!我对 C++ 编程还很陌生,尤其是模板仍然让我有些痛苦。

C++11 visual-studio-2013 链接器错误 lnk2019

评论

0赞 Nitesh 1/18/2018
从错误LNK2019中可以明显看出这是一个链接错误。可能您没有包含某些 cpp 文件或忘记指定要链接的库。

答:

2赞 Ian Young 1/18/2018 #1

C++ 编译器由两个主要阶段组成:

  1. 编译:这是将*.cpp文件转换为*.obj文件的地方。在此阶段之后会出现编译时错误。

如果未发生编译时错误,则生成过程将移至:

  1. 链接:这是将所有 obj 文件与任何依赖项(如 lib/dll 文件)链接在一起以创建最终可执行文件。如果缺少任何依赖项,则会出现链接时间错误。

因此,考虑到这些信息,让我们看一下您的错误: “LNK2019”。这意味着这是一个链接时间错误(用 LNK 表示),错误号表示未解析的符号,并且在几个地方提到了 TensorFlowTensor,它表示您刚刚发布的文件。

因此,发生的情况是链接器找不到每个错误中指定的函数的定义。在这种非常具体的情况下,这样做的原因是您已在 cpp 文件中提供了模板化函数的实现。

这将导致问题,因为模板函数必须以内联方式定义,即在头文件中。

将所有代码移入 ,如下所示:TensorflowTensor.cppTensorflowTensor.h

namespace tf {
    class TensorflowTensor : public TensorflowCWrapper<TF_Tensor>
    {
    public:
      TensorflowTensor(const cv::Mat& input_image);
      TensorflowTensor(TF_Tensor* tensor);

      // inner class for convenient access to tensors' data
      template<typename DType, size_t D>
      class TensorView
      {
      public:
        TensorView<DType, D>(TensorflowTensor& tensor){
           // Constructor body goes here instead of cpp file.
        }
        const DType& operator()(std::array<size_t, D> n) const{
           // operator body goes here
        }
        DType& operator()(std::array<size_t, D> n){
           // Here too
        }
        size_t NumElements() const;

      private:
        DType* data_;
        std::array<size_t, D> dims_;
        size_t num_el_;
       };

      template<typename DType, size_t D>
      TensorView<DType, D> View();
    };
}

这样,编译器和链接器就可以找到要使用的函数的定义。

评论

0赞 ITiger 1/18/2018
谢谢!您能推荐有关 C++ 模板功能的任何文献吗?
0赞 Ian Young 1/18/2018
有很多在线教程,你可以通过粗略的谷歌搜索找到,而且大多数书都相当不错。老实说,如果你是C++的新手,我建议你先熟悉一下,然后先使用标准模板库。