资讯详情

TensorFlow 1.10 CPU版C++库编译指南:Bazel+VS2015实战

📅 2026/10/14 8:38:03 | 华诺云谱 👁 阅读
TensorFlow 1.10 CPU版C++库编译指南:Bazel+VS2015实战
简介这份资源是CPU版TensorFlow 1.10.0编译产出的C API库文件面向需要在Windows平台用C调用TensorFlow进行推理与训练的开发者尤其适合使用VS2015-64位环境、希望直接跑通训练模型或加载GPU训练所得模型的工程人员。压缩包为rar格式共2388个文件约80.87MB其中以2248个h头文件为主体另含exe可执行文件、txt说明、lib与dll库文件以及core、tensor、eigen、sparse、fft、svd、qr、cholesky等模块相关文件覆盖矩阵运算、线性代数与神经网络等依赖目录结构完整便于按模块检索与集成。已有519人学习下载。资源省去从源码编译的繁琐过程可直接在VS2015中配置引用用于编写C程序调用TensorFlow跑例程、加载并运行训练好的模型同时兼容GPU训练产出的模型作者亲测可用适合需要快速搭建C推理环境的开发者参考使用。1. 为什么今天还要折腾 CPU 版 TensorFlow 1.10 的 C 库如果你手上有一个 2018 年前后落地的工业视觉项目模型是冻结好的.pb推理代码是 C 写的部署机器是一台没有独显、也不允许随便装运行时的工控机那你大概率绕不开一个名字CPU 版的 TensorFlow 1.10.0配上 VS2015 编译出 C API 的库文件。这不是怀旧是很多产线设备至今还在跑这套组合换框架的成本远高于把库编出来。TensorFlow 1.10 的 C API 和 Python API 是两套东西Python 侧import tensorflow就能用C 侧必须自己用 Bazel 从源码编译出tensorflow.dll、tensorflow.lib和一堆头文件再用 VS2015 链接进自己的工程。标题里的每个词都是硬约束——CPU 版意味着不用 CUDA、不碰 cuDNN1.10.0 意味着 API 和目录结构锁死在这个版本VS2015 意味着 MSVC 14.0 工具链和后面 VS2017/2019 的 ABI 不通用。这篇笔记面向两类人一类是第一次要从源码编 TensorFlow C 库、被 Bazel 和 MSVC 折腾到怀疑人生的新手另一类是编过但总在链接期翻车、想知道参数边界和踩坑点的熟手。我会把选型理由、编译步骤、参数含义、排错路径讲透让你能照着复现而不是对着报错发呆。2. 编译前的环境选型为什么是 Bazel MSVC 14.0 这套组合2.1 TensorFlow 1.10 的构建系统为什么只能用 BazelTensorFlow 1.x 的官方构建入口就是 Bazeltensorflow/BUILD、tensorflow/contrib/BUILD这些文件是构建图的唯一真相来源。CMake 在 1.10 时代对 C API 的支持是残缺的社区那几个 CMake 脚本只能编出部分算子遇到libtensorflow_cc.so这种完整目标就歇了。所以想拿到完整的 C APIBazel 不是可选项是唯一路径。Bazel 版本也要卡死。TensorFlow 1.10 官方推荐 Bazel 0.15.0 到 0.16.1 之间我一般用 0.15.2。用 0.17 以上会在解析WORKSPACE时因为http_archive规则变更直接报错用 0.14 以下又会缺--config相关能力。这个版本区间是血泪经验别想着用新版 Bazel 编老 TensorFlow玄学报错能让你查一整天。2.2 MSVC 14.0 工具链和 Python 2.7 的绑定关系TensorFlow 1.10 的 Windows 构建脚本tensorflow/contrib/cmake和 Bazel 的msvc配置默认锚定的是 VS2015 的 MSVC 14.0。原因很实际1.10 的tensorflow/core/platform/default/integral_types.h和一批std::相关头文件在 MSVC 14.1VS2017下会有std::string_view之类的兼容问题官方没做适配。你硬用 VS2017 编可能在编译protobuf或eigen时就挂掉。Python 侧必须是 2.7且是 64 位。Bazel 构建过程中会调用 Python 脚本生成pywrap相关代码1.10 的脚本是 Python 2 语法用 Python 3 会在print语句和unicode处理上直接报语法错误。我一般装一个干净的 Python 2.7.15把python.exe加进 PATH并在configure时明确指定路径。2.3 CPU 版编译要关掉哪些开关CPU 版的核心是--configopt加上--confignoaws --confignogcp --confignohdfs这类裁剪开关把用不到的云存储、GPU 支持全关掉减少依赖和编译时间。关键配置项在configure脚本里交互式回答配置项CPU 版取值说明CUDA supportN关掉 GPU避免拉 cuDNN 依赖Compute capability留空不填填了会尝试编 GPU 算子TensorFlow C APIY必须开否则不生成 C 头文件Optimization-marchnative按本机 CPU 指令集优化跨机部署改 -mavx2 等Python pathC:\Python27\python.exe指向 2.7 解释器-marchnative在编译机和部署机 CPU 不同代时会触发非法指令这是部署期最常见的翻车点。如果部署机型号杂老老实实写-mavx -mfma这种保守组合。3. 从源码到 tensorflow.lib一步步编出 C API 库3.1 拉源码、切分支、装 Bazel 0.15.2先把源码和工具链准备好。TensorFlow 1.10.0 的 tag 是v1.10.0别用 mastermaster 的 API 已经变了。# 拉取 TensorFlow 源码并切到 1.10.0 git clone https://github.com/tensorflow/tensorflow.git cd tensorflow git checkout v1.10.0 # 下载 Bazel 0.15.2 的 Windows 安装包bazel-0.15.2-windows-x86_64.exe # 安装后把 bazel.exe 所在目录加入 PATH验证版本 bazel version # 期望输出Build label: 0.15.2这里的关键是git checkout v1.10.0切错分支后面所有编译都是白费。Bazel 装好后用bazel version确认如果显示的不是 0.15.x先解决版本问题再往下走。源码目录不要放在带中文或空格的路径下Bazel 对路径里的空格处理有 bug会在生成genrule时莫名失败。3.2 跑 configure 脚本CPU 版的关键回答在源码根目录执行python configure.py这是交互式的每个回答都影响后续编译。# 在 tensorflow 源码根目录执行 python configure.py # 交互回答示例CPU 版 # Please specify the location of python. [Default is ...]: C:\Python27\python.exe # Do you wish to build TensorFlow with CUDA support? [y/N]: N # Do you wish to build TensorFlow with OpenCL support? [y/N]: N # Do you wish to build TensorFlow with MKL support? [y/N]: N # Please specify optimization flags: -mavx -mfma # Do you wish to build TensorFlow with Apache Kafka platform support? [y/N]: NCUDA support选 N 之后脚本不会再问 compute capability这是 CPU 版省事的地方。MKL support选 N 是因为 MKL 在 1.10 的 Windows 构建里经常和 MSVC 运行库冲突除非你明确需要它加速矩阵运算否则关掉更稳。optimization flags我填-mavx -mfma兼顾性能和部署兼容性比-marchnative安全。回答完会在源码根目录生成.tf_configure.bazelrc里面记录了 Python 路径、优化选项等。这个文件是后续bazel build的配置来源改配置就改它不用重跑 configure。3.3 用 bazel build 编出 C API 目标CPU 版 C API 的构建目标是//tensorflow:libtensorflow_cc.so但 Windows 下我们要的是.dll和.lib对应目标//tensorflow:libtensorflow_cc.so在 Windows 上会生成tensorflow.dll和导入库。命令如下# 编译 C API 动态库CPU 版 bazel build --configopt \ --confignoaws --confignogcp --confignohdfs \ //tensorflow:libtensorflow_cc.so # 同时编出 C API 库可选某些工程用 C API 更省事 bazel build --configopt \ //tensorflow:libtensorflow.so--configopt开启优化--confignoaws等裁剪掉云存储依赖能显著减少编译时间和链接错误。第一次编译大概 40 分钟到 1 小时取决于机器。编译产物在bazel-bin/tensorflow/下Windows 上你会看到tensorflow.dll、tensorflow.lib导入库以及tensorflow_cc.dll之类的文件具体命名随 Bazel 版本略有差异。编译过程中如果卡在protobuf或eigen的编译上多半是 MSVC 版本不对或 Bazel 版本不对回到 2.1、2.2 检查。3.4 收集头文件和库文件整理成可链接的目录编完之后头文件散落在源码树和bazel-genfiles里需要收集。我一般建一个tf_cpu_1.10目录结构如下# 整理产物目录结构在源码根目录执行 mkdir -p tf_cpu_1.10/include mkdir -p tf_cpu_1.10/lib # 拷贝核心头文件 cp -r tensorflow/core tf_cpu_1.10/include/tensorflow/ cp -r tensorflow/cc tf_cpu_1.10/include/tensorflow/ cp -r bazel-genfiles/tensorflow/core/framework tf_cpu_1.10/include/tensorflow/core/ # 拷贝库文件 cp bazel-bin/tensorflow/tensorflow.dll tf_cpu_1.10/lib/ cp bazel-bin/tensorflow/tensorflow.lib tf_cpu_1.10/lib/头文件里tensorflow/core/framework下的*.pb.h是 Bazel 生成的必须从bazel-genfiles拷源码树里没有。漏拷这个目录VS2015 里会报tensorflow/core/framework/graph.pb.h: No such file or directory。库文件里tensorflow.lib是导入库链接时用tensorflow.dll是运行时用部署时要和 exe 放一起。4. VS2015 工程配置让 C 代码真正链接上 tensorflow.lib4.1 新建工程并设置包含目录、库目录打开 VS2015新建一个 Win32 控制台工程配置选 Release x64。在项目属性里设置C/C - 常规 - 附加包含目录加上tf_cpu_1.10/include链接器 - 常规 - 附加库目录加上tf_cpu_1.10/lib链接器 - 输入 - 附加依赖项加上tensorflow.lib这三步是基础但很多人漏了 x64 配置。TensorFlow 1.10 的 Windows 构建默认是 64 位你的工程如果选 Win32链接时会报模块计算机类型“x86”与目标计算机类型“x64”冲突。这个报错很直白但新手容易忽略配置管理器里的平台选择。4.2 写一个最小 C 推理代码验证链接用一段加载.pb模型并跑一次推理的代码验证库是否可用// minimal_infer.cpp #include tensorflow/core/public/session.h #include tensorflow/core/platform/env.h #include tensorflow/core/framework/tensor.h #include iostream int main() { using namespace tensorflow; // 创建 SessionCPU 版默认用本机 CPU Session* session; Status status NewSession(SessionOptions(), session); if (!status.ok()) { std::cerr NewSession failed: status.ToString() std::endl; return 1; } // 加载冻结图路径按实际模型改 GraphDef graph_def; status ReadBinaryProto(Env::Default(), model.pb, graph_def); if (!status.ok()) { std::cerr ReadProto failed: status.ToString() std::endl; return 1; } status session-Create(graph_def); if (!status.ok()) { std::cerr Create graph failed: status.ToString() std::endl; return 1; } // 构造输入张量形状要和模型输入节点一致 Tensor input(DT_FLOAT, TensorShape({1, 224, 224, 3})); // 这里省略填充数据的逻辑实际用 input.flatfloat() 写入 std::vectorstd::pairstd::string, Tensor inputs {{input:0, input}}; std::vectorTensor outputs; status session-Run(inputs, {output:0}, {}, outputs); if (!status.ok()) { std::cerr Run failed: status.ToString() std::endl; return 1; } std::cout Inference OK, output dim: outputs[0].shape().DebugString() std::endl; session-Close(); delete session; return 0; }NewSession创建会话ReadBinaryProto读.pbsession-Create把图加载进会话session-Run执行推理。输入节点名input:0和输出节点名output:0必须和冻结图里的一致用错名字会报Node not found。TensorShape({1, 224, 224, 3})是 NHWC 格式CPU 版默认布局别写成 NCHW。4.3 运行时 DLL 缺失和常见链接错误的处理编译通过但运行时报找不到 tensorflow.dll把tf_cpu_1.10/lib/tensorflow.dll拷到 exe 同目录或者加进系统 PATH。如果报无法解析的外部符号检查附加依赖项里tensorflow.lib是否拼对以及工程平台是不是 x64。链接期还可能遇到LNK2038: 检测到“RuntimeLibrary”的不匹配项这是 TensorFlow 库用的运行库/MD和你工程设置/MT不一致。在C/C - 代码生成 - 运行库里改成多线程 DLL (/MD)和 TensorFlow 对齐。5. 避坑与排查编译和链接期最常见的 5 个翻车点5.1 Bazel 版本不对导致 WORKSPACE 解析失败现象执行bazel build时立刻报ERROR: Skipping //tensorflow:libtensorflow_cc.so: no such package或WORKSPACE:... http_archive rule相关错误。原因Bazel 0.17 以上改了http_archive的参数校验TensorFlow 1.10 的WORKSPACE文件按老规则写的解析不过。解决卸载新版 Bazel装 0.15.2bazel version确认后重试。别试图改WORKSPACE去适配新版改动会牵连一堆依赖。5.2 Python 3 环境导致 configure 脚本语法错误现象跑python configure.py时报SyntaxError: invalid syntax指向print语句或unicode。原因1.10 的 configure 脚本是 Python 2 写的系统默认python指向了 Python 3。解决用绝对路径C:\Python27\python.exe configure.py执行或在 PATH 里把 Python 2.7 放前面。装完 Python 2.7 后确认是 64 位版本32 位会在后续 Bazel 构建时找不到匹配的库。5.3 头文件漏拷导致 VS2015 报找不到 graph.pb.h现象VS2015 编译时报无法打开包括文件: tensorflow/core/framework/graph.pb.h。原因graph.pb.h是 Bazel 在构建时生成的不在源码树里只在bazel-genfiles/tensorflow/core/framework/下。解决把bazel-genfiles/tensorflow/core/framework整个目录拷进tf_cpu_1.10/include/tensorflow/core/保持相对路径一致。类似的还有*.pb.cc对应的头文件一并拷全。5.4 运行库不匹配引发 LNK2038现象链接时大量LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”。原因TensorFlow 官方构建用/MD动态运行库你的工程默认可能是/MT。解决项目属性C/C - 代码生成 - 运行库改成多线程 DLL (/MD)。如果工程里引了其他静态库也要确认它们同样是/MD编的否则冲突会转移。5.5 部署机 CPU 指令集不支持导致非法指令现象编译机跑得好好的 exe拷到部署机一运行就崩报0xC000001D: Illegal Instruction。原因编译时用了-marchnative生成的指令用了编译机支持但部署机不支持的 AVX512 等指令。解决重新 configure优化选项改成保守组合如-mavx -mfma重新编译。如果部署机更老连 AVX 都没有就写-msse4.2。这个坑在跨机型部署时几乎必踩提前确认部署机 CPU 型号能省很多事。6. 进阶技巧把 C API 库做成可复用工程模板编一次库不容易每次新建工程都手动配包含目录、库目录、依赖项太费劲。我的习惯是做一个 VS2015 的属性表.props把 TensorFlow 相关的路径和依赖全写进去新工程导入这个属性表就行。属性表里关键节点是IncludePath、LibraryPath和AdditionalDependencies用相对路径指向tf_cpu_1.10这样整个tf_cpu_1.10目录连同属性表可以一起拷给同事换台机器只要改属性表里的根路径。属性表内容大致如下!-- tensorflow_cpu_1.10.props 关键片段 -- Project PropertyGroup TFRoot$(MSBuildThisFileDirectory)..\tf_cpu_1.10/TFRoot /PropertyGroup ItemDefinitionGroup ClCompile AdditionalIncludeDirectories$(TFRoot)\include;%(AdditionalIncludeDirectories)/AdditionalIncludeDirectories /ClCompile Link AdditionalLibraryDirectories$(TFRoot)\lib;%(AdditionalLibraryDirectories)/AdditionalLibraryDirectories AdditionalDependenciestensorflow.lib;%(AdditionalDependencies)/AdditionalDependencies /Link /ItemDefinitionGroup /Project$(MSBuildThisFileDirectory)是属性表自身所在目录用相对路径定位tf_cpu_1.10这样整个目录树可以整体迁移。导入方式是在 VS2015 的属性管理器里右键工程选添加现有属性表选中这个.props文件。另一个进阶点是验证库的完整性。编完之后别急着写业务代码先用 4.2 那段最小推理代码跑通一次确认NewSession、ReadBinaryProto、Run三个环节都不报错。这一步能提前暴露 90% 的链接和运行时问题比在业务代码里 debug 高效得多。我自己的教训是第一次编 1.10 的 C 库时图省事用了系统里的 Python 3 和 Bazel 0.19结果 configure 报语法错误、build 报 WORKSPACE 解析失败来回折腾了一下午才回到正确版本组合。后来我养成习惯动手前先把 Bazel 版本、Python 版本、MSVC 版本三个数字写在纸上核对一遍确认无误再敲第一条命令。这个习惯帮我省下的时间远比核对本身花的多。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑