天下苦C++已久!各位C++开发者们,大家说什么是现在的C++最大的痛点?
是内存管理吗?
是散乱无章的标准库吗?
是隐藏的很多语言层面的陷阱吗?
都不是!C++目前的最大的痛点就是没有统一的包管理器!以及编译构建混乱!各种轮子到处飞,但是很多都安不到自己的项目上去!
本文将采用CLION平台,配合使用MINGW/MSVC编译器进行统一的包管理和对OPENCV以及QT库、Boost库的导入。我将以自己两天的踩坑精力为C++开发者们铺平道路。
本文主要以MINGW64为主,MSVC配置也是同理的。
目录
一.Qt环境准备
Qt的安装很简单,我们进入Qt官网
选择download QT,然后根据自己的系统版本进行选择。
我们得到一个在线下载器

注册好账号进行登录
注意将QT放入到D盘下下载,因为体积比较大。


注意,比如在QT6.7.1中,你可以不勾选web assembly等一些工具,因为可能不太用得到,编译器有三种选择,MINGW,MSVC和LLVM。LLVM构建更加复杂,我的建议是下载MINGW64,当然了,如果你想利用VS搭建这个环境,采用VS+MSBUILD或者是VS+CMAKE的方式,你也可以选择MSVC。
- MSVC:是WINDOWS下的最强大的编译器,对C++提供最新支持,但是它不能跨平台
- MINGW:GNU的WINDOWS版本,可以在所有平台上运行,但是在windows上面构建比较麻烦,一些小的第三方的windows库可能不兼容mingw
- LLVM:性能很好,但是构建比较麻烦,尤其是在WIN平台上构建起来比MINGW还要复杂得多。不建议使用。
勾选上这些之后,我们开始下载,然后我们可以发现一个qt creator,这是一个QT自带的IDE工具。如果桌面上没有,就先在第一次下载完成之后启动,先固定到任务栏,然后再去寻找QT CREATOR的快捷方式。
至此为止,WINDOWS上面的QT环境算是搭好了,但是这还不够。因为有的人,比如我,不喜欢QT designer的界面风格,也不会把它当做自己的主要生产力工具,所以,我们选择CLION。
关于怎么在VS上部署QT的,可以参考别的文章。在VS2022这一系列的平台上部署QT环境比在CLION上其实要简单的多,这里就不多赘述。这里就贴一个链接。
VS2022+QT开发环境搭建_vs2022 qt-优快云博客
然后我们打开CLION,配置一下Qt的工具链
CLION-QT配置
我们先设置一下CLION的QT的工具链

这里是我已经配置好的。
我们点击加号,选择工具链

我们配置好工具链之后,应用并退出。
这个时候其实就基本配置完毕了,开始写CMAKE
CLION-QT的CMAKE测试
需要注意的是,QT CREATOR在项目里面set了很多变量,但是在CLION打开这个项目的时候我们是没有SET的。也就是说,这些变量需要我们自己去指定。
需要手动指定的变量
- CMAKE_CXX_STANDARD:C++标准版本,最好直接指定为17,不然容易出错
- QT_DIR:QT的不同编译器的CMAKE目录,自己指定
- 如果想在生成不同编译器的项目,可以这么写CMAKE
- if-else-endif ,在if的括号里面写上编译器名字,比如if(MSVC),然后写上对应的操作,然后用endif结束这个if语句。
- 如果想在生成不同编译器的项目,可以这么写CMAKE
- CMAKE_AUTOMOC:自动MOC
- MOC作用:
- moc 全称是 Meta-Object Compiler,也就是“元对象编译器”。Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件。如果它发现在一个头文件中包含了宏 Q_OBJECT,则会生成另外一个 C++ 源文件。这个源文件中包含了 Q_OBJECT 宏的实现代码。这个新的文件名字将会是原文件名前面加上 moc_ 构成。这个新的文件同样将进入编译系统,最终被链接到二进制代码中去。因此我们可以知道,这个新的文件不是“替换”掉旧的文件,而是与原文件一起参与编译。另外,我们还可以看出一点,moc 的执行是在预处理器之前。因为预处理器执行之后,Q_OBJECT 宏就不存在了。
- Qt 将源代码交给标准 C++ 编译器,如 gcc 之前,需要事先将这些扩展的语法去除掉。完成这一操作的就是 moc。
- MOC作用:
- CMAKE_AUTORCC:自动将图片和视频文件(qrc资源文件)转换为二进制资源文件
- CMAKE_AUTOUIC:将.ui文件自动转换为一个.h的头文件,这是非常重要的一个工具
- CMAKE_PREFIX_PATH:我们将QT的DIR,也就是QT_DIR转义输入即可,这是一个头文件和库文件的搜索路径。
cmake_minimum_required(VERSION 3.26)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
# 必须要求C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置QT的标准
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# 设置QT_DIR,也可以写在环境变量里面
set(QT_DIR D:/QT_6/6.7.1/mingw_64/lib/cmake)
# 设置头文件和库搜索路径,这包含
set(CMAKE_PREFIX_PATH
#QT
${QT_DIR};
)
# 设置参与构建的文件
set(PROJECT_FILES
main.cpp
)
# 项目信息
project(QT_VCPKG)
# 查找Qt6库
find_package(Qt6 COMPONENTS Core Gui Widgets REQUIRED)
# 添加可执行文件
add_executable(QT_VCPKG ${PROJECT_FILES})
# 链接Qt6库
target_link_libraries(QT_VCPKG PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets)
运行一个简单的程序
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QPushButton button("Hello world!", nullptr);
button.resize(200, 100);
button.show();
return QApplication::exec();
}
如果窗口显示正常,那么一切大吉。如果出现错误退出,请看看工作目录有没有选上。
把工作目录直接设置为QT的目录可以解决99%的QT库链接失败问题。
在CLION上面配置QT的工具
Designer(最重要的,一定要配置)
Designer就是QT的用来拖拽和设置控件的编辑窗口。
UIC(最重要的,一定要配置)
UIC就是把UI文件转换成C文件,也就是一个.h文件。总所周知,QT WIDGET最好的开发方式就是用代码来写。但是UIC有一个比较大的问题就是,用designer的.ui文件,一旦生成之后再次修改,你自己在这个.h文件中的修改会全部消失。
所以,最好的方式就是,在designer里面对窗口进行设置。
RCCBinary(建议配置)
将.qrc资源文件编译成二进制文件
RCCh(建议配置)
将.qrc资源文件转换为.h文件
我们点开外部工具

我们对这些工具进行如下设置




二.VCPKG环境准备
我们点击clion,上面自带一个vcpkg

如果没有,那它一定在这里

点开之后,我们新建一个,自己在里面新建一个目录,最好放在D盘,然后自动下载。
下载完毕如下

不同环境的选择
这里我们选择经典模式,我们有两种选择
- 手动指定下载的版本
- 在环境变量或者CMAKE中进行设置

比如我这里,配置了三个VCPKG,大家可以按照我的设置。我使用的是x64-mingw-dynamic,那么在经典模式下它就会默认安装这个。当然还有x64-windows,等等版本,请在VCPKG文档中自行检索。
CMake的设置
CMake也是同理
# 设置VCPKG的工具链文件和目标triplet
set(CMAKE_TOOLCHAIN_FILE "D:/vcpkg/scripts/buildsystems/vcpkg.cmake")
set(VCPKG_TARGET_TRIPLET "x64-mingw-dynamic")
我们在CMAKE中设置好工具链,就可以不用手动设置搜索目录了,使用VCPKG进行包管理(经典模式下),我们只需要进行两个操作(动态引入)
- 在add_executable()之前使用find_package()
- 在add_executable()之后使用target_link_libraries()
下面是一个案例
# 查找fmt库
find_package(fmt CONFIG REQUIRED)
# 添加可执行文件
add_executable(QT_VCPKG ${PROJECT_FILES})
# 链接fmt库
target_link_libraries(QT_VCPKG PRIVATE fmt::fmt)
三.导入包进行测试
不使用vcpkg的场景
自行管理OPENCV
假设我们有一个QT,不好用VCPKG做管理,那我们需要自己写CMAKE,关于QT的CMake我们写在了上面,接下来我来说说怎么在这个场景下引入OPENCV包。
关于如何用编译OPENCV,可以参考这篇文章
编译之后记得将用户环境变量设置好

我们需要写好这两个环境变量,这样使用就很方便了。使用什么平台的编译器,就要使用什么版本的编译文件。
然后是系统的环境变量(下面的那一个)

如此一来,OPENCV就配置好了。
然后我们需要添加OPENCV,就需要添加以下到CMakeLists中去。
# 设置头文件和库搜索路径
set(CMAKE_PREFIX_PATH
${QT_DIR};
${OPENCV_DIR};
)
# 查找opencv库
find_package(OpenCV REQUIRED)
add_executable(...)
# 链接Opencv库
target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS})
如此一来,我们只需要设置一个搜索路径,找包,然后在后面动态链接即可,也并没有特别麻烦。
使用vcpkg的场景
使用vcpkg管理fmt包
比如我们下一个fmt的包,我这里是MINGW64-dynamic版本。(fmt也可以无库,纯头文件来引入)
# 设置VCPKG的工具链文件和目标triplet
set(CMAKE_TOOLCHAIN_FILE "D:/vcpkg/scripts/buildsystems/vcpkg.cmake")
set(VCPKG_TARGET_TRIPLET "x64-mingw-dynamic")
# 查找fmt库
find_package(fmt CONFIG REQUIRED)
add_executable(...)
# 链接fmt库
target_link_libraries(QT_VCPKG PRIVATE fmt::fmt)
然后我们写一个文件测试一下
#include<fmt/core.h>
int main(){
std::string s="hello cmx";
fmt::print(s);
}
只要不出现错误代码退出就是库链接正常了,就OK了,一个函数能用就是整个库都能用。
VCPKG不支持下载的场景
当VCPKG不支持下载的时候,比如MINGW64的windows平台不支持BOOST库的某些组件,下载出现失败,会出现提示:用git pull升级VCPKG版本。
实际上,根本不是VCPKG的版本问题,而是有些代码仓库没有这个版本。
这个时候怎么做呢?我们换一个版本,比如静态编译版本。
使用VCKPG+CMAKE静态链接
比如大名鼎鼎的Boost::Asio模块,其实MINGW64没有dynamic版本,我们只需要下载static版本即可。
然后就是传统的静态链接,在add_executable之前添加即可
# 静态链接boost::Asio库
include_directories(D:/vcpkg/packages/boost-asio_x64-mingw-static/include)
# 通过手动添加一些windows下的socket库来使用Asio库
link_libraries(libgdi32.a libwsock32.a libws2_32.a)
注意asio是没有动态库的,它其实是需要winsock的库,但是没有提供库的文件。这里写链接winsock也行。
四.最终的环境测试
我写了一个代码,用于给大家做一个测试,看看自己的包安装的是否到位了,环境是否配置好了。
这是CMAKE
#############------------- 本CMakeLists适用于QT-MINGW-64的搭建,请选择构建CMake应用的时候将Qt的mingw64下的bin文件夹添加进工作目录 -------------#############
cmake_minimum_required(VERSION 3.26)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
# 必须要求C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置QT的标准
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# 设置QT_DIR,也可以写在环境变量里面
set(QT_DIR D:/QT_6/6.7.1/mingw_64/lib/cmake)
# 设置VCPKG的工具链文件和目标triplet
set(CMAKE_TOOLCHAIN_FILE "D:/vcpkg/scripts/buildsystems/vcpkg.cmake")
set(VCPKG_TARGET_TRIPLET "x64-mingw-dynamic")
# 设置头文件和库搜索路径,这包含
set(CMAKE_PREFIX_PATH
#QT
${QT_DIR};
#OPENCV
${OPENCV_DIR};
)
# 设置参与构建的文件
set(PROJECT_FILES
main.cpp
)
# 项目信息
project(QT_VCPKG)
# 查找fmt库
find_package(fmt CONFIG REQUIRED)
# 查找Boost库,指定需要的组件
find_package(Boost REQUIRED COMPONENTS thread chrono )
# 查找Qt6库
find_package(Qt6 COMPONENTS Core Gui Widgets REQUIRED)
# 查找opencv库
find_package(OpenCV REQUIRED)
# 静态链接boost::Asio库
include_directories(D:/vcpkg/packages/boost-asio_x64-mingw-static/include)
# 通过手动添加一些windows下的socket库来使用Asio库
link_libraries(libgdi32.a libwsock32.a libws2_32.a)
# 添加可执行文件
add_executable(QT_VCPKG ${PROJECT_FILES})
# 链接Qt6库
target_link_libraries(QT_VCPKG PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets)
# 链接fmt库
target_link_libraries(QT_VCPKG PRIVATE fmt::fmt)
# 链接Boost库
target_link_libraries(QT_VCPKG PRIVATE Boost::thread Boost::chrono)
# 链接Opencv库
target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS})
这是主函数,
注意自己手动修改一下图片的路径
#include "boost/thread.hpp"
#include <QApplication>
#include <QPushButton>
#include <boost/asio.hpp>
#include <fmt/core.h>
#include <opencv2/opencv.hpp>
#include <iostream>
// 使用 Boost.Asio 进行异步操作
void async_task(boost::asio::io_service& io_service) {
boost::asio::steady_timer timer(io_service, boost::asio::chrono::seconds(2));
timer.wait();
std::cout << "Async task completed." << std::endl;
}
// 使用 Boost 线程库创建线程
void thread_task() {
std::cout << "Thread task started." << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(1));
std::cout << "Thread task completed." << std::endl;
}
// 使用 OpenCV 进行图像处理
void process_image() {
std::string input_path = "D:/OPENCV_VCPKG/shen.jpg";
std::string output_path = "D:/OPENCV_VCPKG/processed_image.jpg";
cv::Mat image = cv::imread(input_path, cv::IMREAD_COLOR);
if (image.empty()) {
std::cerr << "Error opening image!" << std::endl;
return;
}
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
cv::imwrite(output_path, image);
std::cout << "Image processed and saved as " << output_path << "." << std::endl;
}
int main(int argc, char *argv[]) {
// 创建一个新的线程来运行线程任务
boost::thread t(thread_task);
// 使用 Boost.Asio 进行异步操作
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
boost::thread asio_thread(boost::bind(&boost::asio::io_service::run, &io_service));
io_service.post(boost::bind(async_task, boost::ref(io_service)));
// 启动 Qt 应用程序
QApplication app(argc, argv);
QPushButton button("Hello, World!");
QObject::connect(&button, &QPushButton::clicked, &app, &QApplication::quit);
button.show();
// 使用 fmt 库格式化字符串并输出
std::string formatted_string = fmt::format("This is a formatted number: {}", 42);
std::cout << formatted_string << std::endl;
// 使用 OpenCV 进行图像处理
process_image();
// 等待 Boost 线程完成
t.join();
io_service.stop();
asio_thread.join();
return app.exec();
}
如此,我们便自行配置了一个相当丰富的库的工作环境。
2540





