win10 + bazel-0.20.0 + tensorflow-1.13.1 编译tensorflow GPU版本的C++库

  • 安装所需软件/库
  • Step1. 安装vs2015,CUDA 10.0和cuDNN 7.6
  • Step2. 安装msys2
  • Step3. 安装bazel
  • Step4. 下载编译所需文件(tensorflow源码及其他文件)
  • Step5. 使用powershell进行配置与编译
  • Step6. 整理生成的文件——dll,lib,include
  • Step7. 调用模型测试程序
  • 支线任务

参考资料:

  • windows+bazel+tensorflow-v1.12.0(GPU)编译生成dll与lib;
  • Error: “execution of scripts is disabled on this system” ;
  • tensorflow1.4 c++编译以及API使用;
  • window+tensorflow+cuda+cudnn 出现‘CUDnn_STATUS_ALLOC_FAILED’的可能解决办法;
  • Return coordinates for bounding boxes Google’s Object Detection API;
  • visualize_boxes_and_labels_on_image_array 函数.

---------------------- 超长文多图预警!!! ----------------------

安装所需软件/库

  • vs2015;
  • Anaconda3;
  • CUDA 10.0;
  • cuDNN 7.6;
  • python3.6.7;
  • tensorflow-1.13.1;
  • bazel0.20.0;
  • msys2-x86_64-20190524.

Step1. 安装vs2015,CUDA 10.0和cuDNN 7.6

vs2015的安装这里就不多说了,Anaconda3、CUDA和cuDNN的安装可参考cmake编译opencv: Win10+cmake3.14.4+cuda10.0+cudnn7.6+opencv-4.0.0+contrib+vs2015。

Step2. 安装msys2

进入msys2官网,选择msys2-x86_64-20190524.exe,或直接点击此链接: msys2-x86_64-20190524,进行下载。


下载好后开始安装,点击Next


接下来选择安装路径,我个人为了避免安装在系统盘,将盘符改成了D盘,如下图。然而在之后的编译过程中发现,msys64会在C盘再安装一遍,所以这里推荐使用默认,即安装在 C:\msys64 下。接着点击Next,进入下一步。


这里直接Next


软件开始安装,稍微等一会儿就好了。


安装完成,点击Finish


弹出一个类似cmd的命令窗口,输入一下命令:

pacman -Syu
  • 1

询问是否进行安装,输入y,回车:


第一个命令执行完毕:


接着输入以下命令:

pacman -S git
  • 1

同样地,询问是否安装输入 y,然后回车:


第二个命令执行完毕:


接着输入:

pacman -S patch unzip grep
  • 1

是否安装输入 y,回车:


第三个命令执行完毕:

软件装好以后,需要配置环境变量。
将以下路径添加到系统变量 Path 中:

D:\msys64
D:\msys64\usr\bin

注意,如果之前装在C盘,则需要进行相应修改。
如下图所示:


msys2安装配置完毕!

Step3. 安装bazel

进入github,选择合适的bazel版本进行下载。
如果CUDA和Tensorflow的版本与本文一致,也可点此链接下载:bazel-0.20.0-windows-x86_64.exe。
github上选择下载文件如下图所示:


将下载好的 .exe 文件复制到 D:\msys64 下(路径根据个人安装情况而定),更名为 bazel.exe


复制完成后,配置bazel环境变量。
新建三个系统变量:BAZEL_SHBAZEL_VCBAZEL_VS。相应的路径如以下表格所示:

变量
BAZEL_SH D:\msys64\usr\bin\bash.exe
BAZEL_VC D:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
BAZEL_VS D:\Program Files (x86)\Microsoft Visual Studio 14.0

环境变量配置完成:

bazel安装配置完毕!

Step4. 下载编译所需文件(tensorflow源码及其他文件)

进入tensorflow-v1.13.1源码的github的页面 ,点击页面右侧绿色按钮Clone or download,然后点击Download ZIP进行下载,如下图所示。
或者也可直接点此链接:tensorflow-1.13.1 进行下载。
下载时间也许会很长,请耐心等待。

进入tensorflow-windows-build-script-master的github页面,下载tensorflow-windows-build-script-master.zip(此链接可直接下载)。

以上两个 .zip 文件下载完成后,在D盘新建一个文件夹,命名为 tensorflow-1.13.1 (也可根据个人喜好决定)。

  • 将下载好的 tensorflow-1.13.1.zip 解压到刚刚新建的文件夹下,重新命名为 source
  • tensorflow-windows-build-script-master.zip 解压到任意位置,然后把其中的 patchesbuild.ps1 文件,复制到新建的 D:\tensorflow-1.13.1目录下,如下图所示:

  • patches 下的 eigen_half.patch 复制到 tensorflow-1.13.1\source\third_party 下:

  • patches 下的 tf_exported_symbols_msvc.lds 复制到 tensorflow-1.13.1\source\tensorflow 下:

  • 用文本编辑器打开 build.ps1 文件,将以下语句注释掉:

Copy-Item …\patches\tf_exported_symbols_msvc.lds tensorflow\

防止编译时出现Copy-Item命令的问题。
位置在 build.ps1 的180行,如下图所示:


编译所需文件准备完毕!

Step5. 使用powershell进行配置与编译

C:\Windows\SysWOW64\WindowsPowerShell\v1.0 目录下,右键以管理员身份运行 powershell.exe


powershell 窗口中输入以下命令,转到 tensorflow-1.13.1 目录下:

cd D:\tensorflow-1.13.1
  • 1

输入bazel编译的选项:

$parameterString = "--config=opt --config=cuda --define=no_tensorflow_py_deps=true --copt=-nvcc_options=disable-warnings //tensorflow:libtensorflow_cc.so --verbose_failures"
  • 1

然后输入以下命令,执行 build.ps1 脚本文件:

.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
  • 1

执行命令时出现 UnauthorizedAccess 错误,说明可能是 powershell 的执行策略受限,输入以下命令查看当前执行策略:

Get-ExecutionPolicy
  • 1

我这里显示的是Restricted(受限的),所以需要输入以下语句来取消限制:

Set-ExecutionPolicy Unrestricted
  • 1

询问是否改变执行策略,输入 y,回车。
修改好后,可以再次输入:

Get-ExecutionPolicy
  • 1

查看当前执行策略是否已经取消限制。


执行策略的问题解决以后,重新执行 build.ps1 脚本文件:

.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
  • 1

如果一切正常,我们将开始编译前的配置。可参照以下两图进行配置。有些提问可以直接按回车来选择默认配置,括号中出现 default 字眼的,都可以这么做。


注意 :当问到GPU的计算能力(compute capability),即出现 [Default is: 3.5, 7.0]: 时,先不要急着按回车。我们先找到跟自己显卡对应的计算能力,再进行填写,可参考后面的方法来查看显卡的计算能力。


打开设备管理器,找到自己的显卡型号:


然后进入NVDIA官网的CUDA GPUs页面,点击 CUDA-Enabled GeForce and TITAN Products,找到自己的显卡型号对应的数值,将其填入 [Default is: 3.5, 7.0]: 后面,回车继续配置。


都配置完成后,编译正式开始。注意保持网络通畅,因为编译之前需要下载各种依赖库,网络异常会导致下载失败停止编译。编译时间很长,不要光盯着屏幕看,该吃吃该喝喝该玩玩该睡睡。

编译可能出现无法解析的外部符号的问题,以下面的错误为例:

无法解析的外部符号 “public: virtual __cdecl tensorflow::internal::LogMessage::~LogMessage(void)” (??1LogMessage@internal@tensorflow@@UEAA@XZ),该符号在函数 “public: void __cdecl tensorflow::internal::LogMessage::`vbase destructor’(void)” (??_DLogMessage@internal@tensorflow@@QEAAXXZ) 中被引用

解决方法:
用文本编辑器打开 D:\tensorflow-1.13.1\source\tensorflow\tf_exported_symbols_msvc.lds ,找到前面一个括号中带问号的内容:

??1LogMessage@internal@tensorflow@@UEAA@XZ

将其删除。如果有多个无法解析外部符号的问题,用同样的方法逐一删除即可。
确认全部清除后,重新执行以下命令配置和编译:

.\build.ps1 -BazelBuildParameters $parameterString -BuildCppAPI -ReserveSource
  • 1

如果一切正常,在漫长的等待之后,将会出现以下结果:
注意:第一个红框部分为编译生成的动态库 libtensorflow_cc.so 所在位置,请记录下来,后面需要用到。


编译任务圆满完成!!!
可以稍作休息小小庆祝一下!

Step6. 整理生成的文件——dll,lib,include

新建一个文件夹,在文件夹中创建以下三个目录:dlllibinclude


根据编译结束时显示的动态库所在位置,找到生成的库 libtensorflow_cc.soliblibtensorflow_cc.so.ifso

  • libtensorflow_cc.so 更名为 tensorflow_cc.dll,放到刚才创建的 dll 目录下;
  • liblibtensorflow_cc.so.ifso 更名为 tensorflow_cc.lib,放到刚才创建的 lib 目录下。


接下来要做的是填满 include 目录,该步相对繁琐,最终将包含以下文件夹:

1)在include目录中新建名为 _bin 的文件夹。参考以下路径,打开 _embedded_binaries 目录,将下图红框中的文件复制到 _bin 文件夹中:

C:\Users\xxx_bazel_xxx\install\d5b1be53d8db6a1e2d160364df2e7ef6_embedded_binaries


2-1) 参考以下路径,将下图红框中的 bazel-out 文件夹复制到 include 目录下:

C:\Users\xxx_bazel_xxx\y46qiod6\execroot\org_tensorflow


2-2) 参考以下路径,将 protobuf_archive 文件夹复制到 include 下的 bazel-out\x64_windows-opt\genfiles\external 目录中:

C:\Users\xxx_bazel_xxx\y46qiod6\external

3) 将 D:\tensorflow-1.13.1\source 下的 tensorflowthird_party 复制到 include 目录下:


4-1) 参照以下路径,将下图红框中的 external 文件夹复制到 include 目录下:

C:\Users\xxx_bazel_xxx\y46qiod6


4-2) 参照以下路径,将 embedded_tools 文件夹下的所有文件复制到 include 下的 external\bazel_tools 目录中(如果 external 里面没有该文件夹,需新建并命名为 bazel_tools):

C:\Users\xxx_bazel_xxx\install\d5b1be53d8db6a1e2d160364df2e7ef6_embedded_binaries\embedded_tools

4-3) 将 D:\tensorflow-1.13.1\source 下的 tensorflow 复制到 include 下的 external\org_tensorflow 目录中(如果 external 里面没有该文件夹,需新建并命名为 rg_tensorflow):


至此,调用tensorflow所需的库及包含的目录准备完毕!

Step7. 调用模型测试程序

新建测试工程,在 .cpp 文件中写入以下代码:

#define COMPILER_MSVC
#define NOMINMAX
#define PLATFORM_WINDOWS   // 指定使用tensorflow/core/platform/windows/cpu_info.h

#include “stdafx.h”
#include<iostream>
#include<opencv2/opencv.hpp>
#include"tensorflow/core/public/session.h"
#include “tensorflow/core/platform/env.h”
#include <time.h>

using namespace tensorflow;
using namespace cv;
using std::cout;
using std::endl;

int main() {
const std::string model_path = “frozen_inference_graph.pb”;// tensorflow模型文件,注意不能含有中文
const std::string image_path = “image1.jpg”; // 待inference的图片grace_hopper.jpg

// 设置输入图像
cv::Mat img = cv::imread(image_path);
cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
int height = img.rows;
int width = img.cols;
int depth = img.channels();// 取图像数据,赋给tensorflow支持的Tensor变量中
tensorflow::Tensor input_tensor(DT_UINT8, TensorShape({ 1, height, width, depth }));
const uint8* source_data = img.data;
auto input_tensor_mapped = input_tensor.tensor&lt;uint8, 4&gt;();for (int i = 0; i &lt; height; i++) {const uint8* source_row = source_data + (i * width * depth);for (int j = 0; j &lt; width; j++) {const uint8* source_pixel = source_row + (j * depth);for (int c = 0; c &lt; depth; c++) {const uint8* source_value = source_pixel + c;input_tensor_mapped(0, i, j, c) = *source_value;}}
}// 初始化tensorflow session
Session* session;
Status status = NewSession(SessionOptions(), &amp;session);
if (!status.ok()) {std::cerr &lt;&lt; status.ToString() &lt;&lt; endl;return -1;
}
else {cout &lt;&lt; "Session created successfully" &lt;&lt; endl;
}// 读取二进制的模型文件到graph中
tensorflow::GraphDef graph_def;
status = ReadBinaryProto(Env::Default(), model_path, &amp;graph_def);
if (!status.ok()) {std::cerr &lt;&lt; status.ToString() &lt;&lt; endl;return -1;
}
else {cout &lt;&lt; "Load graph protobuf successfully" &lt;&lt; endl;
}// 将graph加载到session
status = session-&gt;Create(graph_def);
if (!status.ok()) {std::cerr &lt;&lt; status.ToString() &lt;&lt; endl;return -1;
}
else {cout &lt;&lt; "Add graph to session successfully" &lt;&lt; endl;
}
// 输入inputs,“ x_input”是我在模型中定义的输入数据名称
std::vector&lt;std::pair&lt;std::string, tensorflow::Tensor&gt;&gt; inputs = {{ "image_tensor:0", input_tensor },
};// 输出outputs
std::vector&lt;tensorflow::Tensor&gt; outputs;//批处理识别
double start = clock();
std::vector&lt;std::string&gt; output_nodes;
output_nodes.push_back("num_detections");
output_nodes.push_back("detection_boxes");
output_nodes.push_back("detection_scores");
output_nodes.push_back("detection_classes");
// 运行会话,最终结果保存在outputs中
status = session-&gt;Run(inputs, { output_nodes }, {}, &amp;outputs);
if (!status.ok()) {std::cerr &lt;&lt; status.ToString() &lt;&lt; endl;return -1;
}
else {cout &lt;&lt; "Run session successfully" &lt;&lt; endl;
}double finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout &lt;&lt; "spend time:" &lt;&lt; duration &lt;&lt; endl;
cv::imshow("image", img);
cv::waitKey();
return 0;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

先别急着编译工程,首先我们需要把环境配置好:

  • 配置opencv (Release版本);
  • 配置tensorflow C++库。

opencv库配置就不多赘述,这里主要说明tensorflow库的配置。
1)包含目录:

D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include\external\org_tensorflow;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include\external\protobuf_archive\src;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include\external\com_google_absl;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include\external\eigen_archive;D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\include\bazel-out\x64_windows-opt\genfiles;
  • 1

2)库目录:

D:\libtensorflow-gpu-windows-x86_64-1.13.1-avx2cuda10cudnn76\lib;
  • 1

3)链接器输入附加依赖项:

tensorflow_cc.lib;
  • 1

环境配置好后,将之前生成的动态库放入应用程序目录,即复制 tensorflow_cc.dll 到与工程文件 .sln 同级的 x64\Release 文件夹下,如下图所示:


接下来,从网盘下载模型文件 frozen_inference_graph.pb 和测试图片 image1.jpg(点此链接)

  • 模型文件在 tensorflow\ssd_mobilenet_v1_coco_2017_11_17 目录下;
  • 测试图片在 tensorflow\test_images 目录下。

把它们放到与 .cpp 文件同级的目录下,如下图所示:


编译前的准备工作完成,现在我们可以编译生成项目。生成之前,注意选择 Releasex64,如下图红框所示:


编译可能出现无法解析的外部符号的问题,以下面的错误为例:

无法解析的外部符号 “public: virtual __cdecl tensorflow::internal::LogMessage::~LogMessage(void)” (??1LogMessage@internal@tensorflow@@UEAA@XZ),该符号在函数 “public: void __cdecl tensorflow::internal::LogMessage::`vbase destructor’(void)” (??_DLogMessage@internal@tensorflow@@QEAAXXZ) 中被引用

解决方法:
用文本编辑器打开 D:\tensorflow-1.13.1\source\tensorflow\tf_exported_symbols_msvc.lds ,将前面一个括号中带问号的内容:

??1LogMessage@internal@tensorflow@@UEAA@XZ

复制到该文件的末尾,如下图所示。
如果有多个无法解析外部符号的问题,用同样的方法逐一添加。全部添加完成后保存关闭文件,然后重新编译tensorflow,也就是说从运行脚本文件开始,后面的流程要重新走一遍,想想有点心累,不过都已经走到这里了,半途而废有点说不过去呀,咬咬牙重来一遍吧。

上面的问题已经成功解决,没有意外,还会出现max问题:


解决办法如下:
双击错误提示,跳转到有max问题的文件: logging.htensor_shape.h,分别进行以下修改:

1)logging.h:

将第250行的

if (TF_PREDICT_FALSE(v2 >= std::numeric_limits<int>::max())) {      \
  • 1

改为

if (TF_PREDICT_FALSE(v2 >= (std::numeric_limits<int>::max)())) {      \
  • 1

修改后如下图所示:

2)tensor_shape.h:
将108-111行的

static const int64 kMaxRep16 = std::numeric_limits<uint16>::max() - 1;
static const int64 kMaxRep32 = std::numeric_limits<uint32>::max() - 1;
static const uint16 kUnknownRep16 = std::numeric_limits<uint16>::max();
static const uint32 kUnknownRep32 = std::numeric_limits<uint32>::max();
  • 1
  • 2
  • 3
  • 4

改为:

static const int64 kMaxRep16 = (std::numeric_limits<uint16>::max)() - 1;
static const int64 kMaxRep32 = (std::numeric_limits<uint32>::max)() - 1;
static const uint16 kUnknownRep16 = (std::numeric_limits<uint16>::max)();
static const uint32 kUnknownRep32 = (std::numeric_limits<uint32>::max)();
  • 1
  • 2
  • 3
  • 4

修改后如下图所示:


修改好后我们重新生成项目,如果上面的步骤都没有问题,将会出现下面的结果:


没错!编译成功!小腿抖起来小曲儿唱起来!

到这里还没有结束,将程序运行起来,你将看到以下结果:


红框部分说明GPU和模型调用没毛病,妥妥地成功!小腿再次抖起来小曲儿再次唱起来!

tensorflow C++库的生成和调用全部结束!

支线任务

注意,这是作业,不是彩蛋。
测试程序结尾出现了以下神秘图片:


蓝狗?!
还别说,狗狗蓝色的美瞳还真是洋气,蓝色的皮鞋更显骚气。
灵魂三问:小狗为什么是蓝色?定位框在哪?识别的结果在哪?
这就需要骚年们好好的研究和琢磨了。

Happy Ending:

                                </div>

win10 + bazel-0.20.0 + tensorflow-1.13.1 编译tensorflow GPU版本的C++库相关推荐

  1. 假设用于通信的电文由字符集{a,b,c,d,e,f,g}中的字母构成。 它们在电文中出现的频度分别为{0.31,0.16,0.10,0.08,0.11,0.20,0.04}。【MOOC答案】

    目   录 1.题目 2.答案and详细题解过程 1)为这7个字母设计哈夫曼编码: 1.1.答案 1.2.详细题解过程 2)为这7个字母设计等长编码,至少需要几位二进制数?[3位] 2.1.答案 2. ...

  2. linux下安装虚拟天文馆,如何在Ubuntu 20.04、18.04中安装Stellarium 0.20.0虚拟天文馆

    如何在Ubuntu 20.04.18.04中安装Stellarium 0.20.0虚拟天文馆 几天前发布了Stellarium 0.20.0,它时一个免费开源的桌面虚拟天文馆软件.以下是在Ubuntu ...

  3. SIP.js 0.20.0版本简单Demo

    SIP.js的0.20.0版本是使用typescript开源的JavaScript库 首先从npm上加载SIP.js npm install sip.js 可以根据习惯使用ts或js来开发 <s ...

  4. 安装数据库MySQL 8.0.20.0 详细过程 小白安装

    安装数据库MySQL 8.0.20.0 详细过程 小白安装 耐心等待 复制完回到这里来 我们输入 net start 我们输入 net start 当然 我们也可以关闭数据库 命令如下 net sto ...

  5. Tensorflow2.0安装教程(windows系统,CPU和GPU版本)

    文章目录 一.Anaconda安装 二.tensorflow2.0安装 2.1 创建Anaconda环境 2.2 进入TF20环境 2.3 Tensorflow安装 三.验证tensorflow安装成 ...

  6. 怎么安装mysql8.0.20_Mysql 8.0.20安装教程

    MySQL最新版本8.0.20正式发布.与之前8.0的系列版本一样,这次的发行版除了包含缺陷修复,也同样包括新功能:关键字:hash join.InnoDB双写缓冲.二进制日志事务压缩等. 安装教程( ...

  7. 常识——windows的tensorflow安装gpu版本,cuda算力只有3.0也可以

    文章目录 问题 windows安装tensorflow_gpu版本 检查显卡是否支持cuda 查看自己的显卡型号 去官网查看是否支持cuda 检查显卡的cuda算力 按照GPU算力3.0的电脑配置进行 ...

  8. ValueError: With n_samples=0, test_size=0.2 and train_size=None, the resulting train set will be emp

    今天写代码labelmetovoc,即将labelme标注的转化为voc标准格式参考的这篇文章时遇到了如下问题: ValueError: With n_samples=0, test_size=0.2 ...

  9. 当小数遇上二进制——全面解析JS中的小数二进制计算(附赠0.1+0.2 !== 0.3问题解释)

    二进制小数如何转换为十进制 二进制转换十进制的方法是: 从二进制数的最低位开始,每一位乘以对应的2的幂数,然后将最终的结果小数部分与整数部分分别相加 对应的2的幂,以个位为0,向高位依次增1,向地位依 ...

最新文章

  1. LeetCode简单题之将每个元素替换为右侧最大元素
  2. Redis Manager 主要功能介绍
  3. 隐藏标准选择界面按钮
  4. [转贴] 软件测试职业发展的 A 面和 B 面
  5. 2d的公式_西师大版六年级数学上册全册必背公式+高清版电子课文,收藏预习
  6. elasticsearch系列八:ES 集群管理(集群规划、集群搭建、集群管理)
  7. 2021北京民营企业百强榜单发布 美团、水滴等公司入选
  8. Linux的java配置及tomcat的启动
  9. CPU虚拟化是否开启
  10. 三星android mac地址修改,三星手机如何改mac地址啊
  11. 我的CSDN博客文章,被大学老师、本科生、公司 “引用“ 了!
  12. 遇到RAID5阵列硬盘出现问题的情况该如何解决?
  13. 1-1/2+1/3-1/4+.........+1/99-1/100
  14. 网格化管理服务系统,携同用户创新共进步
  15. 金立 M6 (GN8003) 解锁 BootLoader 进入第三方 recovery 刷机 ROOT
  16. 社交/SNS社交网络服务-ISP
  17. java Android创建容器,Java-在具有(没有)DI容器的Android中正确进行依赖项注入(匕首1)...
  18. Echarts 深色模式图表背景透明
  19. SQLServer数据库导入.mdf文件报错解决问题
  20. 咕咕数据 A 股实时行情数据

热门文章

  1. 喜欢就争取,得到就珍惜,错过就忘记—dbGet(二)
  2. Nodejs学习笔记(十二)--- 定时任务(node-schedule)
  3. thinkphp仿素材火教程_thinkphp6学习教程与源码 tp6开源CMS系统源码研究
  4. 从源码看spring applicationContext在web容器中加载过程
  5. Redis和Memcached在功能、性能以及内存使用效率上的对比
  6. 服务器san 虚拟化安装系统,在Hyper-V中安装iSCSI SAN服务器(下)
  7. 浅议“全局变量”、“多线程”和“编译器陷阱”
  8. oracle 12g 无监听,Oracle 12.2监听无法启动解决一例
  9. 先有鸡还是先有蛋? 加拿大科学家揭开谜底
  10. 减速箱箱体尺寸是怎样计算的_皮带输送机减速机漏油、油温高可不能小觑,原因及处理方法教给你...