tdm-gcc下载 我这里的mingw用的是tdm-gcc封装的64位版本
下载后可随便修改安装位置
之后记得添加环境变量
PathTo/TDM-GCC64/bin
可选部分
根据所学的编译方式,除了gcc,g++,之外还有make工具,但是用在终端里面输入make -v
结果显示未找到make,该问题是是mingw编译器里的make
被命名为mingw32-make.exe
为了方便调用同时不会对编译器造成额外问题,复制mingw32-make.exe
将其另存为make.exe
这样就能在终端里面方便的调用make工具了
cmake 本人不怎么用,直接安装即可,因为win上一般用的是gui,所以无所谓添加环境变量
cmake 下载地址
opencv官网的官网比较操蛋,去opencv.org的source Forge页面下载会识别设备型号自动跳转到这个页面,但是这个玩意是MSVC编译的文件,mingw是无法使用的,只能采用编译安装,而OpenCV的源码挂在github下,下载源码可能需要科学上网之类的,不想各显神通我提供夸克网盘下载 这玩意不限速
链接在这
解压opencv 文件,新建一个build(你可以随意命名)文件夹用于存放cmake构建文件,在cmake-gui工具中选定source文件夹与build文件夹,点击configure会自动检测你的cpp编译器环境,直接采用默认编译器,等一会后配置结束
可选部分
配置里面有个选项
BUILD_opencv_world,该选项会把所有其他.dll封装为一个libopencv_world460.dll,后续调用时只需要调用这么一个动态链接即可,该动态链接较大,但是不点也行,只是后面调用需要调用多个动态链接,每个链接都比较小,可以个人化定制。
点击generate 即可生成build文件,耐心等一会
之后在你的build文件夹里打开终端,或者任意位置打开终端跳转到build文件里
# 如果你重命名了 mingw32-make
# 那么可以执行
# 否则用 mingw32-make 替代
make -j 8
# 这个 8 指的是你编译配置用的cpu核数量
make install
编译完成后的文件全部在 PathTo/build/install
内,opencv的其他文件已经不再需要了
可选部分
为了方便管理,我将install 文件夹剪切出来重命名为opencv460,460为版本号
在配置vscode 等编辑器之前,先用手动编译的方式来了解一下opencv的cpp文件编译器到底干啥了,测试文件如下
#include
#include
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0);
Mat img;
while (1)
{
cap >> img;
if (img.empty())
break;
namedWindow("img", WINDOW_NORMAL);
imshow("img", img);
if (27 == waitKey(20))
break;
}
return 0;
}
如果直接
g++ opencv_tst.cpp
结果报错找不到头文件
实际上在g++等编译时如果需要添加标准库以外的库函数时需要额外指定,方法时
g++ opencv_tst.cpp -I PathTo/opencv/include
那么继续手动编译
g++ .\opencv_tst.cpp -I D:\ProEnv\opencv460\include\
结果是已经定义了opencv的头文件,但是没有具体的方法实现,依旧报错
对于非标准的cpp库文件编译链接时又需要一个额外参数
g++ -L PathTo\opencv\lib -l opencv_core -l *****
这里的 -I
是指定库文件夹位置,-l
是链接动态库或者静态库
-l opencv_core
实际上是去链接 libopencv_core.a 或者libopencv_core.so文件
类型 | linux | win |
---|---|---|
静态链接 | .a | .lib |
动态链接 | .so | .dll |
但是mingw是在win上实现的g++编译器,所以很蛋疼的是目前编译出来的静态链接是.a文件
观察一下当前编译出来的全部文件
可以发现既有动态链接.dll文件(bin文件夹下)又有静态链接.a文件(lib文件夹下)
为了体验一下动态链接和静态链接有什么区别,两种链接方式都去试一试
链接那些文件呢?具体我其实不太清楚,如果有洁癖,一点点试一下,不想麻烦全连接了,或者勾选之前的选项,生成一个大的链接文件,只需要链接一个就可以了
那么链接时只需要链接opencv_modules core这两个链接
注意的是静态链接的名称是libopencv_core.dll.a
所以编译链接时需要
g++ .\opencv_tst.cpp -I D:\ProEnv\opencv460\include\ -L D:\ProEnv\opencv460\lib\ -l opencv_core460.dll -l opencv_video460.dll -l opencv_highgui460.dll -l opencv_videoio460.dll -o tst1.exe
经过测试 成功编译 为 tst1.exe
为了深入研究一下静态链接和动态链接的区别,再用动态链接编译一下试一试
g++ .\opencv_tst.cpp -I D:\ProEnv\opencv460\include\ -L D:\ProEnv\opencv460\bin\ -l opencv_core460 -l opencv_video460 -l opencv_highgui460 -l opencv_videoio460 -o tst2.exe
成功将其编译为tst2.exe
对比一下编译后的文件
明显两个文件大小相同,源文件也相同,几乎可以判定是同一个文件,运行这两个程序
结果都一样找不到.dll文件
理论上来说 链接静态库后库函数会被打包到.exe里,tst1.exe理论上可以独立运行,而动态库的则不会被打包进去,tst2.exe必须依赖.dll文件,对比一下静态文件和动态文件的体积,可以看到静态文件明显小于动态文件很多,个人理解是opencv偷了懒,将静态文件变成了对动态文件的查找
那么在自己电脑上如何去运行这些.exe文件呢,当前只需要让.exe找到.dll文件即可
两种方法
对于tool级别的代码,最理想的情况就是一键F5 编译运行
更具刚才的手动编译的教程,可以对vscode 的配置进行修改以达到当前目的
根据前面的 opencv配置原理再来配置一下其他的库,这里选图形库raylib和数值计算库eigen
eigen 是一个通用数值计算库,体积小,全平台通用
1. 下载安装
2. cmake build
3. 在build 文件下 make install 会编译安装到C:/program file(x86)/Eigen3
4. 注意如果权限不足需要先创建C:/program file(x86)/Eigen3
根据前面的教程,如果为了方便eigen版本管理,可以直接把C:/program file(x86)/Eigen3/eigen
里面的所有文件剪切出来放到一个特定的地方,在c_cpp_properties.json 添加头文件路径。eigen有个特点,他只有头文件,没有任何静态或者动态链接,编译时只需要g++ tst.cpp -I PathTo/Eigen/include
即可。
但是有没有更简便的方法? 不修改c_cpp_properties.json, 也不要-I PathTo/Eigen/include
?
当然可以,tmdgcc的编译器内置头文件、库文件也有默认位置,只需要将eigen的头文件丢到PathTo/TDM-GCC64/include
中即可
注意我们通常引用的头文件如下
#include
#include
using Eigen::MatrixXd;
using Eigen::VectorXd;
int main()
{
MatrixXd m = MatrixXd::Random(3,3);
m = (m + MatrixXd::Constant(3,3,1.2)) * 50;
std::cout << "m =" << std::endl << m << std::endl;
VectorXd v(3);
v << 1, 2, 3;
std::cout << "m * v =" << std::endl << m * v << std::endl;
}
所有应该是把C:/program file(x86)/Eigen3/include/eigen3
下的两个目录Eigen
和 unsupported
copy到D:\ProEnv\TDM-GCC64\include
下
后续即可直接g++ 编译该程序
raylib 是通用的c++ 图像库全平台通用,你可以去raylib官网 看看教程,下载是免费的
make
即可,或者mingw32-make
raylib.h
与libraylib.a
这两个文件-l raylib -l opengl32 -l gdi32 -l winmm
libraylib.a
丢到 PathTo\TDM-GCC64\lib
中raylib.h
丢到 PathTo\TDM-GCC\include
中-I
和-L
指令根据之前的教程,同样可以修改c_cpp_properties 和task.json文件
但是如果该文件夹下有时候想用opencv,有时候想用raylib难道还要重新打开文件夹吗,其实可以在task.json中和launch.json中配置多个任务,这样在调试中就有多个选项,依旧可以一键运行这里附上我的配置
c_cpp_properties.json
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"D:/ProEnv/TDM-GCC64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++",
"D:/ProEnv/TDM-GCC64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++/tr1",
"D:/ProEnv/TDM-GCC64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++/x86_64-w64-mingw32",
"D:/ProEnv/opencv460/include",
"D:/ProEnv/opencv460/include/opencv2"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "D:/ProEnv/TDM-GCC64/bin/g++.exe",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "opencv gdb",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "D:/ProEnv/TDM-GCC64/bin/gdb.exe",
"preLaunchTask": "opencv g++",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{
"name": "raylib gdb",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "D:/ProEnv/TDM-GCC64/bin",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "D:\\ProEnv\\TDM-GCC64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "raylib g++"
},
{
"name": "ege gdb",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "D:/ProEnv/TDM-GCC64/bin",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "D:\\ProEnv\\TDM-GCC64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "ege g++"
}
]
}
setting.json
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": true,
"editor.minimap.enabled": true,
"C_Cpp.autocomplete": "Default",
"[cpp]": {
"editor.quickSuggestions": true
},
"[c]": {
"editor.quickSuggestions": true
},
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"internalConsoleOptions": true,
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": false
}
],
"preLaunchTask": "Compile"
}
],
"cmake.configureOnOpen": false
}
task.json
{
"version": "2.0.0",
"tasks": [
{
"label": "opencv g++",
"type": "cppbuild",
"command": "g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-I",
"D:/ProEnv/opencv460/include",
"-L",
"D:/ProEnv/opencv460/bin",
"-l",
"opencv_calib3d460",
"-l",
"opencv_core460",
"-l",
"opencv_dnn460",
"-l",
"opencv_features2d460",
"-l",
"opencv_flann460",
"-l",
"opencv_gapi460",
"-l",
"opencv_highgui460",
"-l",
"opencv_imgcodecs460",
"-l",
"opencv_imgproc460",
"-l",
"opencv_ml460",
"-l",
"opencv_objdetect460",
"-l",
"opencv_stitching460",
"-l",
"opencv_photo460",
"-l",
"opencv_video460",
"-l",
"opencv_videoio460",
"-o",
"${fileBasenameNoExtension}.exe"
],
"problemMatcher": [],
"group": {
"kind": "test",
"isDefault": true
}
},
{
"type": "cppbuild",
"label": "raylib g++",
"command": "D:/ProEnv/TDM-GCC64/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-l",
"raylib",
"-l",
"opengl32",
"-l",
"gdi32",
"-l",
"winmm",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "D:/ProEnv/TDM-GCC64/bin"
},
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "调试器生成的任务。"
},
{
"type": "cppbuild",
"label": "ege g++",
"command": "D:/ProEnv/TDM-GCC64/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-l",
"graphics",
"-l",
"uuid",
"-l",
"msimg32",
"-l",
"gdi32",
"-l",
"imm32",
"-l",
"ole32",
"-l",
"oleaut32",
"-l",
"winmm",
"-l",
"gdiplus",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "D:/ProEnv/TDM-GCC64/bin"
},
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "调试器生成的任务。"
}
]
}
需要关注的是launch.json 中的 PreTask 的值一定与你的task.json的 label 的值对应
每个task.json中的args为编译时的参数
launch.json中的type必须为’cppdbg’ 这是vscode cpp 插件决定的
复制粘贴后有3个不同调试任务
里面的ege 是我自己安装了ege图形库,有兴趣可以自己安装验证一下