总体介绍
为什么通过Bazel编译基于Windows的动态链接库?
为什么不用cmake?因为cmake是开发人员自发维护的,当tensorflow升级到1.12时,维护cmake的人已放弃,从而得不到过多支持,编译出错的概率大,而且切问题不好定位,也找不到答案。所以转用有官方支撑的bazel才是正道。
安装、配置环境
-1- 安装VS2015
原因:
- tensorflow的编译需要用到vs2015自带的build tool;
- 已安装了vs2017的也可尝试编译,但编译过程中出现错误(无法识别到某某函数);
- 已安装过vs2017的也可以直接下载旧版的build tool编译工具,但安装的时候系统提示已有最新版本无法安装;
- 所以,建议直接安装vs2015,而且,vs2017无需删除,两个IDE可并存;
-2- 安装 MSYS2
原因:
- msys2是一个运行环境,也是一个编译器;
- tensorflow编译前的环境配置得按linux模式来运行;
安装建议:
- 安装在默认位置
- 否者运行配置文件时,会出现莫名错误
- 安装完成后,通过命令行运行mingw32.exe,并输入如下命令
pacman -Syu
pacman -Su
pacman -S zip unzip patch diffutils git
-3- 安装python3.6.7
原因:
- 因为编译时,提示采用python3.6.7配合编译;
-4- 安装 Bazel
安装建议:
- 下载指定版本(bazel0.15,因为tensorflow1.12需要基于bazel0.15进行配置;
- 复制可执行文件到msys2安装目录下,并修改执行文件的名称为bazel.exe
- 新建环境变量:BAZEL_SH,BAZEL_VC ,BAZEL_VS 如下
-5- 下载Tensorflow-windows-build-script
原因:
因为有墙,越不过就下不了需要的依赖库,编译就会不成功。此脚本已经把需要的依赖和配置全部通过脚本实现,只需运行一行命令,根据提示选择y 或 n,就能配置成功并开始编译。
脚本提供几个参数设置,具体参考GitHub说明:
-BazelBuildParameters 强制
- 传递给Bazel以构建Tensorflow的字符串。
- 如果构建C API,需要输入 //tensorflow:libtensorflow.so。
- 如果构建C ++ API,需要输入 //tensorflow:libtensorflow_cc.so。
-BuildCppAPI可选
- 构建v1.11.0,v1.12.0和v1.13.1的C ++ API时需要使用此功能。
-ReserveSource可选
- 当确认源文件夹中有有效的tensorflow,并且,不想重新克隆时;
-ReserveVenv可选
- 当确认venv文件夹中有有效的虚拟环境并且不重新创建虚拟环境时。
-IgnoreDepsVersion问题可选
- 可忽略由于安装的依赖库的版本不同而引起的警告;
-InstallDefaultDeps可选
- 如果指定,则如果依赖库未安装,将安装默认版本的依赖项。
-6- 下载tensorflow1.12
解压到tensorflow-windows-build-script目录下,并把文件名更名为resource
-7- 编译
已管理员权限运行PowerShell;
进入tensorflow-windows-build-script目录,输入命令
$parameterString = "--config=opt //tensorflow:libtensorflow_cc.so //tensorflow:install_headers //tensorflow:libtensorflow_framework.so"
.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
//tensorflow:install_headers:编译后,用到的头文件,都会install到bazel_bin目录下。
之后,根据提示,选择回车和输入,编译成功后,so.dll lib 都在bazel-bin目录下:
-8- 调用,运行
- 如果成功,libtensorflow_cc.so.if.lib, libtensorflow_cc.so( 名字修改为 tensorflow_cc.dll 即可)和众多头文件就会出现再bazel-bin文件下
- 在vs里面调用上述文件,再配合tensorflow\examples\label_image\main.cc 运行程序,即可看到结果
-9- debug
如果那么容易成功,我TM还记录这么多步骤干嘛?所以,基于上述-8- 的步骤,点击编译,可能出现很多很多无法识别的外部符号,如:
Error LNK2019 unresolved external symbol “public: virtual __cdecl
tensorflow::internal::LogMessage::~LogMessage(void)”
(??1LogMessage@internal@tensorflow@@UEAA@XZ) referenced in function
“public: void __cdecl tensorflow::internal::LogMessage::`vbase
destructor’(void)”
(??_DLogMessage@internal@tensorflow@@QEAAXXZ) TFBzl112 D:\Code\cc\TF1.12BazelDemo\build\main.obj 1
把第一个括号内的字符串(这是一个正则表达式,用于声明tensorflow被用到的api,让api可以被外部调用),拷贝到 tensorflow\tf_exported_symbols_msvc.lds,把原先的tf_exported_symbols_msvc.lds覆盖掉。
注意,因为脚本每次都会checkout tensorflow,tf_exported_symbols_msvc.lds也会被复原所以,需等checkout 后,再粘贴tf_exported_symbols_msvc.lds
然后,重新执行步骤7;