Windows 环境TensorFlow源码C++编译———实战与避坑记(3)

Windows 环境TensorFlow源码C++编译———实战与避坑记(3),第1张

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:Usersstone_bazel_stone7t3zwoz4execrootorg_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,class std::allocator > 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 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 > const &,class std::vector > *)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文件

通过在tensorflowtoolsdef_file_filterdef_file_filter.py.tpl文件中增加符号后,重新编译dll、lib和include。
特别注意格式,每行前面不能用TAB键,只能用4个空格,行尾不能有空格。
def_fp.write("t ??0SessionOptions@tensorflow@@QEAA@XZn")
def_fp.write("t ?NewSession@tensorflow@@YAPEAVSession@1@AEBUSessionOptions@1@@Zn")
def_fp.write("t ??1SavedModelBundleInterface@tensorflow@@UEAA@XZn")
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@@Zn")
def_fp.write("t ?MaybeSavedModelDirectory@tensorflow@@YA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Zn")
def_fp.write("t ?_TensorShapeProto_default_instance_@tensorflow@@3VTensorShapeProtoDefaultTypeInternal@1@An")
def_fp.write("t ??0Cast@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@W4DataType@2@@Zn")
def_fp.write("t ?Const@ops@tensorflow@@YA?AVOutput@2@AEBVScope@2@AEBUInitializer@Input@2@@Zn")
def_fp.write("t ??1ClientSession@tensorflow@@QEAA@XZn")
def_fp.write("t ??0ClientSession@tensorflow@@QEAA@AEBVScope@1@@Zn")
def_fp.write("t ??0DecodeGif@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Zn")
def_fp.write("t ??0DecodePng@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Zn")
def_fp.write("t ??0DecodeJpeg@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@AEBUAttrs@012@@Zn")
def_fp.write("t ??0DecodeBmp@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Zn")
def_fp.write("t ??0Div@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Zn")
def_fp.write("t ??0ExpandDims@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Zn")
def_fp.write("t ??0Initializer@Input@tensorflow@@QEAA@AEBV?$initializer_list@UInitializer@Input@tensorflow@@@std@@@Zn")
def_fp.write("t ?NewRootScope@Scope@tensorflow@@SA?AV12@XZn")
def_fp.write("t ?NewSession@tensorflow@@YA?AVStatus@1@AEBUSessionOptions@1@PEAPEAVSession@1@@Zn")
def_fp.write("t ??0Operation@tensorflow@@QEAA@PEAVNode@1@@Zn")
def_fp.write("t ??0ResizeBilinear@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Zn")
def_fp.write("t ??0ReadFile@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Zn")
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@@Zn")
def_fp.write("t ??1Scope@tensorflow@@QEAA@XZn")
def_fp.write("t ??0Subtract@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Zn")
def_fp.write("t ??0Squeeze@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@@Zn")
def_fp.write("t ??0TopK@ops@tensorflow@@QEAA@AEBVScope@2@VInput@2@1@Zn")
def_fp.write("t ??0Placeholder@ops@tensorflow@@QEAA@AEBVScope@2@W4DataType@2@@Zn")
def_fp.write("t ?ToGraphDef@Scope@tensorflow@@QEBA?AVStatus@2@PEAVGraphDef@2@@Zn")
def_fp.write("t ?WithOpNameImpl@Scope@tensorflow@@AEBA?AV12@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Zn")

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

4.4.5.MFC测试TensorFlow

4.4.5.1.  新建MFC项目

新建MFC对话框程序,并添加按钮“TensorFlow测试”。

4.4.5.2. 为MFC程序开启命令行窗口

为了便于调试分析,为MFC程序开启命令行窗口。
在应用程序App类实现文件中添加下面的代码:

//增加下面这行代码,控制台输出信息会更多

#pragma comment( linker, "/subsystem:console /entry:wWinMainCRTStartup" )

#include

#include

void InitConsole()

{

    ::AllocConsole();

    FILE* fp;

    freopen_s(&fp, "CONOUT$", "w+t", stdout);

}

在应用程序App类的初始化函数InitInstance中调用InitConsole函数初始化控制台资源。

在应用程序App类的退出函数ExitInstance中调用FreeConsole函数释放控制台资源。

4.4.5.3. 配置项目Release属性—头文件和库文件目录

由于我们编译的只有Release版的TensorFlow,因此在VS中只需要配置项目Release的属性即可。
加入tensorflow的include和lib目录。

为了使用方便,将编译好的tensorflow的安装目录配置为系统环境变量$(THIRDPARTY_HOME)。

4.4.5.4. 配置项目Release属性—加入预定义宏NOMINMAX

配置项目Release属性,在C/C++预处理器定义中加入NOMINMAX。

在MFC中调用TensorFlow时,会报错,主要是因为tensorflow调用的min,max函数是std命名空间下的,而MFC使用的min,max是Windows SDK提供的(头文件minwindef.h),这会导致下面的错误。

解决办法:在工程项目的预处理器中定义:NOMINMAX,这样MFC中就不会调用minwindef.h中的min,max宏。

4.4.5.5. 配置项目pch.h文件—为Gdiplus指定min,max

在pch.h的头文件中,在#include “framework.h”之前为gdiplus指定使用的min,max函数。
#include
namespace Gdiplus
{
using std::min;
using std::max;
}

注意:在项目属性配置时加入预定义宏NOMINMAX,会导致gdiplustypes.h中找不到min,max的错误出现:

查看minwindef.h文件中有明确的定义:只有在没有定义NOMINMAX宏的情况下,才会有min,max宏定义。

解决办法:在MFC所有头文件引用之前,为Gdiplus命名空间指定使用std::min和std::max函数。

4.4.5.6. 配置项目pch.h文件—引入tensorflow头文件和库文件

在pch.h的头文件中,在#include “framework.h”之后加入引入tensorflow的头文件和库文件的代码。
#pragma warning (disable: 4995)
#include 
#include 
 
#pragma comment(lib,"tensorflow_cc.lib")

4.4.5.7. 编写测试代码

在对话框类中添加testtf函数。

void CTFTestDlg::testtf()

{

    tensorflow::Session* session;

    tensorflow::Status status = tensorflow::NewSession(tensorflow::SessionOptions(), &session);

    if (!status.ok()) {

        std::cout << status.ToString() << std::endl;

        return;

    }

    std::cout << "Session successfully created.n";

}
在对话框类的按钮“TensorFlow测试”BN_CLICK消息响应函数中调用testtf()。

4.4.5.8. 编译程序的Release版

注意要选择Release项进行编译。

4.4.5.9. 执行测试程序

运行程序界面如下。

点击“Tensorflow测试”按钮后,命令行窗口出现“Session successfully created.”,测试通过。

后记:

    整个编译测试过程还是挺艰辛曲折的。如果有需要编译好的动态库和python安装包,可以私信我。

    本人第一次发博客,想请教一个问题:如何将word内容直接发布到CSDN?按照网上教程,添加URL: http://write.blog.csdn.net/xmlrpc/index 后,输入用户名和密码点击“确定”,提示无法注册账户。已确认用户名和密码是正确的。有谁知道,烦请告知,谢谢! 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5657630.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存