1. 程式人生 > 其它 >Windows 環境TensorFlow原始碼C++編譯———實戰與避坑記(3)

Windows 環境TensorFlow原始碼C++編譯———實戰與避坑記(3)

4.4. TensorFlow C++版開發庫編譯

4.4.1. release編譯

4.4.1.1. 編譯tensorflow_cc.dll

bazel build --config=opt --define=no_tensorflow_py_deps=true --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK --copt=-nvcc_options=disable-warnings --local_ram_resources=10240 --local_cpu_resources=3 //tensorflow:tensorflow_cc.dll

4.4.1.2. 編譯tensorflow_cc.lib

bazel build --config=opt --define=no_tensorflow_py_deps=true --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK --copt=-nvcc_options=disable-warnings --local_ram_resources=10240 --local_cpu_resources=3 //tensorflow:tensorflow_cc.lib

4.4.1.3. 編譯include

bazel build --config=opt --define=no_tensorflow_py_deps=true --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK --copt=-nvcc_options=disable-warnings --local_ram_resources=10240 --local_cpu_resources=3 //tensorflow:install_headers

4.4.2. debug編譯

編譯時,通過新增”-c dbg”來實現debug版的編譯。編譯過程中遇到問題較多,未能成功編譯。
bazel build -c dbg --config=opt --define=no_tensorflow_py_deps=true --copt=-DTHRUST_IGNORE_CUB_VERSION_CHECK --copt=-nvcc_options=disable-warnings --local_ram_resources=10240 --local_cpu_resources=3 //tensorflow:tensorflow_cc.dll

4.4.3. 編譯結果

編譯結果位於bazel_bin中,bazel_bin實際是一個軟連結,真實資料儲存在C:\Users\stone\_bazel_stone\7t3zwoz4\execroot\org_tensorflow
將編譯結果整理到Tensorflow的安裝目錄下:

4.4.4. 【坑】C++開發時報缺少外部符號錯誤的解決辦法

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::Subtract::Subtract(class tensorflow::Scope const &,class tensorflow::Input,class tensorflow::Input)" (??0Subtract@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::Squeeze::Squeeze(class tensorflow::Scope const &,class tensorflow::Input)" (??0Squeeze@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::DecodeGif::DecodeGif(class tensorflow::Scope const &,class tensorflow::Input)" (??0DecodeGif@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::TopK::TopK(class tensorflow::Scope const &,class tensorflow::Input,class tensorflow::Input)" (??0TopK@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::ExpandDims::ExpandDims(class tensorflow::Scope const &,class tensorflow::Input,class tensorflow::Input)" (??0ExpandDims@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::ResizeBilinear::ResizeBilinear(class tensorflow::Scope const &,class tensorflow::Input,class tensorflow::Input)" (??0ResizeBilinear@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "class tensorflow::Output __cdecl tensorflow::ops::Const(class tensorflow::Scope const &,struct tensorflow::Input::Initializer const &)" (?Const@ops@tensorflow@@YA?AVOutput@2@AEBVScope@2@AEBUInitializer@Input@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::DecodePng::DecodePng(class tensorflow::Scope const &,class tensorflow::Input,struct tensorflow::ops::DecodePng::Attrs const &)" (??0DecodePng@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::Placeholder::Placeholder(class tensorflow::Scope const &,enum tensorflow::DataType)" (??0Placeholder@ops@tensorflow@@QEAA@AEBVScope@2@W4DataType@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::Cast::Cast(class tensorflow::Scope const &,class tensorflow::Input,enum tensorflow::DataType)" (??0Cast@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@W4DataType@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::DecodeJpeg::DecodeJpeg(class tensorflow::Scope const &,class tensorflow::Input,struct tensorflow::ops::DecodeJpeg::Attrs const &)" (??0DecodeJpeg@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::DecodeBmp::DecodeBmp(class tensorflow::Scope const &,class tensorflow::Input)" (??0DecodeBmp@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::Div::Div(class tensorflow::Scope const &,class tensorflow::Input,class tensorflow::Input)" (??0Div@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::Operation::Operation(class tensorflow::Node *)" (??0Operation@tensorflow@@QEAA@PEAVNode@1@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "private: class tensorflow::Scope __cdecl tensorflow::Scope::WithOpNameImpl(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)const " (?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: class tensorflow::Status __cdecl tensorflow::Scope::ToGraphDef(class tensorflow::GraphDef *)const " (?ToGraphDef@Scope@tensorflow@@QEBA?AVStatus@2@PEAVGraphDef@2@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: static class tensorflow::Scope __cdecl tensorflow::Scope::NewRootScope(void)" (?NewRootScope@Scope@tensorflow@@SA?AV12@XZ)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::Scope::~Scope(void)" (??1Scope@tensorflow@@QEAA@XZ)

1>main.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::Input::Initializer::Initializer(class std::initializer_list<struct tensorflow::Input::Initializer> const &)" (??0Initializer@Input@tensorflow@@QEAA@AEBV?$initializer_list@UInitializer@Input@tensorflow@@@std@@@Z)

1>main.obj : error LNK2001: 無法解析的外部符號 "class tensorflow::Status __cdecl tensorflow::NewSession(struct tensorflow::SessionOptions const &,class tensorflow::Session * *)" (?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Z)

1>ModelLoader.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ops::ReadFile::ReadFile(class tensorflow::Scope const &,class tensorflow::Input)" (??0ReadFile@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z)

1>ModelLoader.obj : error LNK2001: 無法解析的外部符號 "public: class tensorflow::Status __cdecl tensorflow::ClientSession::Run(class std::vector<class tensorflow::Output,class std::allocator<class tensorflow::Output> > const &,class std::vector<class tensorflow::Tensor,class std::allocator<class tensorflow::Tensor> > *)const " (?Run@ClientSession@tensorflow@@QEBA?AVStatus@2@AEBV?$vector@VOutput@tensorflow@@V?$allocator@VOutput@tensorflow@@@std@@@std@@PEAV?$vector@VTensor@tensorflow@@V?$allocator@VTensor@tensorflow@@@std@@@5@@Z)

1>ModelLoader.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ClientSession::~ClientSession(void)" (??1ClientSession@tensorflow@@QEAA@XZ)

1>ModelLoader.obj : error LNK2001: 無法解析的外部符號 "public: __cdecl tensorflow::ClientSession::ClientSession(class tensorflow::Scope const &)" (??0ClientSession@tensorflow@@QEAA@AEBVScope@1@@Z)

整理後主要是下面這些符號:

??0Cast@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@W4DataType@2@@Z

?Const@ops@tensorflow@@YA?AVOutput@2@AEBVScope@2@AEBUInitializer@Input@2@@Z

??1ClientSession@tensorflow@@QEAA@XZ

??0ClientSession@tensorflow@@QEAA@AEBVScope@1@@Z

??0DecodeGif@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z

??0DecodePng@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z

??0DecodeJpeg@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z

??0DecodeBmp@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z

??0Div@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z

??0ExpandDims@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z

??0Initializer@Input@tensorflow@@QEAA@AEBV?$initializer_list@UInitializer@Input@tensorflow@@@std@@@Z

?NewRootScope@Scope@tensorflow@@SA?AV12@XZ

?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Z

??0Operation@tensorflow@@QEAA@PEAVNode@1@@Z

??0ResizeBilinear@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z

??0ReadFile@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z

?Run@ClientSession@tensorflow@@QEBA?AVStatus@2@AEBV?$vector@VOutput@tensorflow@@V?$allocator@VOutput@tensorflow@@@std@@@std@@PEAV?$vector@VTensor@tensorflow@@V?$allocator@VTensor@tensorflow@@@std@@@5@@Z

??1Scope@tensorflow@@QEAA@XZ

??0Subtract@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z

??0Squeeze@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z

??0TopK@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z

??0Placeholder@ops@tensorflow@@QEAA@AEBVScope@2@W4DataType@2@@Z

?ToGraphDef@Scope@tensorflow@@QEBA?AVStatus@2@PEAVGraphDef@2@@Z

?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z

4.4.4.1. 【不推薦】方式一:宣告TF_EXPORT

在相關類宣告的標頭檔案新增TF_EXPORT後,重新編譯dll、lib和include。增加TF_EXPORT時需要視情新增標頭檔案引用#include "tensorflow/core/platform/macros.h。
主要需修改的標頭檔案有:
tensorflow/cc/client/client_session.h
tensorflow/cc/framework/scope.h
tensorflow/core/public/session.h
tensorflow/core/public/session_options.h 
tensorflow/cc/framework/ops.h
bazel-bin/tensorflow/cc/ops/ image_ops.h
bazel-bin/tensorflow/cc/ops/io_ops.h
bazel-bin/tensorflow/cc/ops/array_ops.h
bazel-bin/tensorflow/core/framework/graph.pb.h
bazel-bin/tensorflow/core/protobuf/meta_graph.pb.h
bazel-bin/tensorflow/core/protobuf/config.pb.h
bazel-bin/tensorflow/cc/ops/nn_ops.h
這種方式,修改的地方太多了,不推薦。

4.4.4.1. 方式二:修改def_file_filter.py.tpl檔案

通過在tensorflow\tools\def_file_filter\def_file_filter.py.tpl檔案中增加符號後,重新編譯dll、lib和include。
特別注意格式,每行前面不能用TAB鍵,只能用4個空格,行尾不能有空格。
def_fp.write("\t ??0SessionOptions@tensorflow@@QEAA@XZ\n")
def_fp.write("\t ?NewSession@tensorflow@@YAPEAVSession@1@AEBUSessionOptions@1@@Z\n")
def_fp.write("\t ??1SavedModelBundleInterface@tensorflow@@UEAA@XZ\n")
def_fp.write("\t ?LoadSavedModel@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@AEBVRunOptions@1@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV?$unordered_set@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@U?$hash@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@U?$equal_to@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@6@QEAUSavedModelBundle@1@@Z\n")
def_fp.write("\t ?MaybeSavedModelDirectory@tensorflow@@YA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z\n")
def_fp.write("\t ?_TensorShapeProto_default_instance_@tensorflow@@3VTensorShapeProtoDefaultTypeInternal@1@A\n")
def_fp.write("\t ??0Cast@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@W4DataType@2@@Z\n")
def_fp.write("\t ?Const@ops@tensorflow@@YA?AVOutput@2@AEBVScope@2@AEBUInitializer@Input@2@@Z\n")
def_fp.write("\t ??1ClientSession@tensorflow@@QEAA@XZ\n")
def_fp.write("\t ??0ClientSession@tensorflow@@QEAA@AEBVScope@1@@Z\n")
def_fp.write("\t ??0DecodeGif@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z\n")
def_fp.write("\t ??0DecodePng@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z\n")
def_fp.write("\t ??0DecodeJpeg@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Z\n")
def_fp.write("\t ??0DecodeBmp@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z\n")
def_fp.write("\t ??0Div@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
def_fp.write("\t ??0ExpandDims@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
def_fp.write("\t ??0Initializer@Input@tensorflow@@QEAA@AEBV?$initializer_list@UInitializer@Input@tensorflow@@@std@@@Z\n")
def_fp.write("\t ?NewRootScope@Scope@tensorflow@@SA?AV12@XZ\n")
def_fp.write("\t ?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Z\n")
def_fp.write("\t ??0Operation@tensorflow@@QEAA@PEAVNode@1@@Z\n")
def_fp.write("\t ??0ResizeBilinear@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
def_fp.write("\t ??0ReadFile@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z\n")
def_fp.write("\t ?Run@ClientSession@tensorflow@@QEBA?AVStatus@2@AEBV?$vector@VOutput@tensorflow@@V?$allocator@VOutput@tensorflow@@@std@@@std@@PEAV?$vector@VTensor@tensorflow@@V?$allocator@VTensor@tensorflow@@@std@@@5@@Z\n")
def_fp.write("\t ??1Scope@tensorflow@@QEAA@XZ\n")
def_fp.write("\t ??0Subtract@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
def_fp.write("\t ??0Squeeze@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Z\n")
def_fp.write("\t ??0TopK@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Z\n")
def_fp.write("\t ??0Placeholder@ops@tensorflow@@QEAA@AEBVScope@2@W4DataType@2@@Z\n")
def_fp.write("\t ?ToGraphDef@Scope@tensorflow@@QEBA?AVStatus@2@PEAVGraphDef@2@@Z\n")
def_fp.write("\t ?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z\n")

4.4.4.3. 【推薦】方式三:修改tensorflow_filtered_def_file檔案

在tensorflow_filtered_def_file.def檔案中新增外部符號,然後利用link.exe重新生成dll、lib。
為了便於後續開發過程中遇到其他未知外部符號的解決,可以將tensorflow編譯過程中生成的各個依賴lib檔案收集在一處,然後修改tensorflow_cc.dll-2.params檔案中每個lib的路徑,最後使用link.exe重新生成dll和lib。
tensorflow_filtered_def_file.def需要增加的外部符號如下圖:
tensorflow_cc.dll-2.params修改前後如下所示:
link.exe執行過程:
(1)以管理員許可權啟動VS命令列工具
(2)在命令列下定位到tensorflow_cc.dll-2.params和tensorflow_filtered_def_file.def所在目錄。
(3)執行命令:link.exe @tensorflow_cc.dll-2.params