Friday, March 22, 2019

c++11 - VisualC++ Tensorflow C API Wrapper causes LNK2019



I am currently writing a VisualC++ 12 Tensorflow Wrapper to enable Inference Tasks for the Tensorflow Object Detection API. However, I get some linking errors of the Type LNK2019 ("unresolved external symbol").



I researched some usual causes for this error and found the following, but I am not able to spot any of these in my code (The causes are listed on The Microsoft reference for Linker Tool Error LNK2019).



Here are the code snippets, that cause the Error:




  • File TensorflowTensor.h:




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

    // inner class for convenient access to tensors' data
    template

    class TensorView
    {
    public:
    TensorView(TensorflowTensor& tensor);
    const DType& operator()(std::array n) const;
    DType& operator()(std::array n);
    size_t NumElements() const;

    private:
    DType* data_;

    std::array dims_;
    size_t num_el_;
    };

    template
    TensorView View();
    };
    }

  • The Implementation in TensorflowTensor.cpp (only the lines, that cause the linker error):




    namespace tf {
    // Constructors of TensorflowTensor are here

    template
    TensorflowTensor::TensorView::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(tensor.Bytes());
    }

    template
    const DType& TensorflowTensor::TensorView::operator()(std::array n) const
    {

    return data_[ComputeOffset(n)];
    }

    template
    DType& TensorflowTensor::TensorView::operator()(std::array n)
    {
    return data_[ComputeOffset(n)];
    }

    template

    size_t TensorflowTensor::TensorView::NumElements() const
    {
    return num_el_;
    }

    template
    TensorflowTensor::TensorView TensorflowTensor::View()
    {
    return TensorView(*this);
    }

    }

  • And here are the lines from which i call the functions (In a method: TensorflowInference::detect(* some args */)):



    const auto output_scores = result_tensors[0]->TensorflowTensor::View();
    const auto output_boxes = result_tensors[1]->TensorflowTensor::View();
    const auto output_classes = result_tensors[2]->TensorflowTensor::View();

    // 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 }}));

    }
    }



I don't get the error if I comment these lines.



I have included all Header Files and don't get any compiler errors or warnings except for the following 5 LNK2019s:





TensorflowInference.obj : error LNK2019: unresolved external symbol "public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)" (??$View@M$01@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$01@01@XZ) referenced in function "public: void __cdecl tf::TensorflowInference::detect(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 : error LNK2019: unresolved external symbol "public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const " (??R?$TensorView@M$01@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$01@std@@@Z) referenced in function "public: void __cdecl tf::TensorflowInference::detect(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 : error LNK2019: unresolved external symbol "public: unsigned __int64 __cdecl tf::TensorflowTensor::TensorView::NumElements(void)const " (?NumElements@?$TensorView@M$01@TensorflowTensor@tf@@QEBA_KXZ) referenced in function "public: void __cdecl tf::TensorflowInference::detect(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 : error LNK2019: unresolved external symbol "public: class tf::TensorflowTensor::TensorView __cdecl tf::TensorflowTensor::View(void)" (??$View@M$02@TensorflowTensor@tf@@QEAA?AV?$TensorView@M$02@01@XZ) referenced in function "public: void __cdecl tf::TensorflowInference::detect(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 : error LNK2019: unresolved external symbol "public: float const & __cdecl tf::TensorflowTensor::TensorView::operator()(class std::array)const " (??R?$TensorView@M$02@TensorflowTensor@tf@@QEBAAEBMV?$array@_K$02@std@@@Z) referenced in function "public: void __cdecl tf::TensorflowInference::detect(class cv::Mat const &,class std::vector > &)const " (?detect@TensorflowInference@tf@@QEBAXAEBVMat@cv@@AEAV?$vector@UDetection@tf@@V?$allocator@UDetection@tf@@@std@@@std@@@Z)





Lord, that's a wall of text, but I included only the important lines for the error.



I appreciate any hint that helps me to solve these errors! I'm still quite new to C++ programming and especially the templates are still giving me some pain in the neck.


Answer



A C++ compiler comprises of two main stages:




  1. Compilation: This is where your *.cpp files are turned into *.obj files. Compile time errors appear after this stage.




If no compile time errors happen, the build process moves to:




  1. Linking: This is when all the obj files are linked together, along with any dependencies, such as lib/dll files, to create a final executable file. If any dependencies are missing, you will get link time errors.



So, with this information in mind, let's take a look at your error:
'LNK2019'. This means it is a link time error (denoted by LNK), and the error number signifies an unresolved symbol, and in several places, mentioning TensorFlowTensor, which indicates the file you have just posted.




So, what is happening is that the linker can't find the definition of the functions specified in each error. The reason for this, in this very specific case, is that you have provided the implementation for templated functions in a cpp file.



This will cause problems as template functions must be defined inline, i.e. in the header file.



Move all the code in TensorflowTensor.cpp to TensorflowTensor.h, like so:



namespace tf {
class TensorflowTensor : public TensorflowCWrapper
{
public:

TensorflowTensor(const cv::Mat& input_image);
TensorflowTensor(TF_Tensor* tensor);

// inner class for convenient access to tensors' data
template
class TensorView
{
public:
TensorView(TensorflowTensor& tensor){
// Constructor body goes here instead of cpp file.

}
const DType& operator()(std::array n) const{
// operator body goes here
}
DType& operator()(std::array n){
// Here too
}
size_t NumElements() const;

private:

DType* data_;
std::array dims_;
size_t num_el_;
};

template
TensorView View();
};
}



This way, the compiler and linker can find the definition of the functions you wish to use.


No comments:

Post a Comment

plot explanation - Why did Peaches&#39; mom hang on the tree? - Movies &amp; TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...