Qt Clion CMake 项目无法定位 qwindowsvistastyle.dll

本文最后更新于:2024年12月22日 凌晨

前情提要

众所周知,Qt6已经开始慢慢抛弃qmake了,开始皈依cmake

而且宇宙第一IDE - Clion,也是不支持qmake

所以,我们在Clion上只能采用cmake编译Qt项目

但是,很快我们就会发现,运行后的窗体非常地old fashion

style对比

这是为什么捏?

其实就是找不着qwindowsvistastyle.dll

该文件位于D:\Qt\5.15.2\msvc2019_64\plugins\styles(Qt安装目录的plugins目录下)

其实我们可以发现Clion自动生成的CMakeLists.txt"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"复制到了exe目录下

1
2
3
4
5
6
7
8
9
if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
endif ()

但却没有理睬qwindowsvistastyle.dll(可能是因为这不是必须文件吧)

修正:注意,Clion生成的针对Qt6的模板已经包含了这个dll

怎办

默认情况下,Windows 系统会按以下顺序查找 DLL 文件:

  1. 可执行文件所在的目录
  2. 系统目录(如 C:\Windows\System32)。
  3. 当前工作目录
  4. 环境变量 PATH 指定的目录

其实手动地复制一下就可以了(可执行文件所在目录)

注意路径是style\qwindowsvistastyle.dll or plugins\style\qwindowsvistastyle.dll

但是知其然而不知其所以然

为什么qmake编译的exe就可以正确定位该dll位置(not .lib)呢(即便我没有设置plugins的环境变量)

合理的推测是,在编译期将dll搜索目录写入了exe

但貌似cmake无法做到这一点(on Windows)?

[windows] cmake 如何设置 需要使用的 dll_cmake添加dll-CSDN博客

qmakecmake最终生成的都是Makefile,没道理出现这样的能力差异

Qt Creator CMake vs Clion CMake

而且而且,使用Qt Creator创建的CMake项目,是可以正确找到plugins文件夹的!

aaaaaaa

仙人指路

Qt官方文档指出:

在 Qt 中,当应用程序启动时,应用程序的可执行目录是 Qt 搜索插件的基本目录。

Qt 还会查找QLibraryInfo::path ( QLibraryInfo::PluginsPath ) 指定的目录,该目录通常位于QTDIR/plugins中; QTDIR是Qt的安装目录。如果您希望 Qt 查看其他位置,您可以通过调用QCoreApplication::addLibraryPath () 添加所需数量的路径。如果你想设置自己的路径,你可以使用QCoreApplication::setLibraryPaths ()。

或者,您可以使用qt.conf文件来覆盖编译到 Qt 库中的硬编码路径。有关更多信息,请参阅使用 qt.conf

另一种可能性是在运行应用程序之前设置QT_PLUGIN_PATH环境变量;可以使用系统路径分隔符分隔多个路径。设置后,Qt 在此变量中指定的路径中查找插件。

注意:请勿将QT_PLUGIN_PATH导出为系统范围的环境变量,因为它可能会干扰其他 Qt 安装

通过qApp->libraryPaths(),我们可以观察在不同编译系统下dll的搜索路径

qmake & Qt Creator cmake:

1
("D:/Qt/5.15.2/msvc2019_64/plugins", "D:/Qt/projects/Follower-v2.0-MSVC-Release/release")

Clion cmake:

1
("E:/Projects/cpp/QtCmakeTest-2/cmake-build-debug/plugins", "E:/Projects/cpp/QtCmakeTest-2/cmake-build-debug")

The default path list consists of a single entry, the installation directory for plugins. The default installation directory for plugins is INSTALL/plugins, where INSTALL is the directory where Qt was installed.

我们可以发现,在默认情况下,qmake的行为与官方文档一致,返回了 Qt安装目录下的plugins目录 & 可执行文件所在目录

但是cmake却返回了可执行文件目录下的plugins文件夹,这是为什么!

// 这也解释了前文说,为什么style\qwindowsvistastyle.dll or plugins\style\qwindowsvistastyle.dll都可以

好吧,也许Qt自己知道自己在哪里($QTDIR),而Clion不知道?

aaaaaa

Temp Solution

好吧,寄了,世界十大未解之谜

那么想要在Clion开发Qt怎么办捏

  1. 手动复制plugins\style\qwindowsvistastyle.dll

  2. 使用CMakeLists.txt自动化复制

  3. 使用qt.conf(最好放入资源文件嵌入exe)

  4. 使用QCoreApplication::addLibraryPath添加plugins目录

  5. Clion的运行配置中设置局部环境变量QT_PLUGIN_PATH(这样只会影响Clion的开发,不会影响全局)

    这个比较好,这样还可以删掉CMakeLists.txt中拷贝dll的部分

    Clion配置环境变量

当然,这些都是开发配置,对于项目发布,那肯定是要使用windeployqt.exe工具拷贝所有dll

详情请参见:Qt-windeployqt部署发布浅谈 - MrBeanC-Blog (cls.ink)

Peace

我焯,等一下

我突然发现,用Qt Creator创建的cmake项目,用Clion打开之后是可以正确搜索到plugins目录的

但是qDebug()就无法正常输出了,加上QT_ASSUME_STDERR_HAS_CONSOLE=1之后,也只能在debug模式输出

std::cout也只能在debug模式输出,aaaaa

Conclusion

CMake太恐怖了

补充:

真相了,默认情况下CMake项目生成的exe直接打开是包含命令行窗口的

需要加上set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE true)才能消除

Qt默认加上了这一行

但是这样做Clion就无法捕获输出了

所以最好是只在Release模式下加上这一行

1
2
3
if (CMAKE_BUILD_TYPE MATCHES "Release")
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE true) # 设置为窗口应用程序, 无控制台,同时会导致Clion无法捕获输出
endif ()

控制台意外换行 & 颜色

同时由于Clion貌似是直接1:1镜像了控制台中输出的内容

导致其甚至包括原本控制台宽度不够造成的额外换行

听说qDebug()默认是输出到stderr,所以Clion中显示的是红色的输出,非常刺眼

那么如何解决以上两个问题呢?

其实只要开启一个设置即可:在输出控制台中模拟终端

Clion-在输出控制台中模拟终端

这样,Clion的输出就完全正常了,无论是换行,还是颜色

等一下,兄弟们,再等一下

我又有新发现了

实际上的规则是:

如果可执行文件(exe)目录下存在Qt5Core.dll/Qt5Cored.dll,那么exe就会在本目录下搜索plugins

qApp->libraryPaths()也会是本目录下的plugins

但是,假如在exe同目录下没有Qt5Core.dll/Qt5Cored.dll,就会自动从Qt安装目录下搜索正确的plugins下的dll

qApp->libraryPaths()也会变成"D:/Qt/5.15.2/msvc2019_64/plugins",离子谱

WTF,Core是定位符吗?

所以实际上正确的处理方案是,删除Clion自动生成的CMakeLists.txt中的dll复制部分的代码

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
#if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
# set(DEBUG_SUFFIX)
# if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
# set(DEBUG_SUFFIX "d")
# endif ()
# set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
# if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
# set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
# if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
# set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
# endif ()
# endif ()
# if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E make_directory
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E copy
# "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
# endif ()
# foreach (QT_LIB Core Gui Widgets)
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E copy
# "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll"
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
# endforeach (QT_LIB)
#endif ()

aaaaaaaa

Ref

[windows] cmake 如何设置 需要使用的 dll_cmake添加dll-CSDN博客

c++ - Qt GUI主题看起来过时 - VoidCC — c++ - Qt GUI theme looks old-fashioned - Stack Overflow

使用 CLion 開發 Qt5. Build with CLion 2021.1 11.0.10 & Qt… | by Weikeup | Medium

Deploying Plugins | Qt 6.7

Qt程序pro中如何设置运行时库的位置_qt的pro设置库路径-CSDN博客


Qt Clion CMake 项目无法定位 qwindowsvistastyle.dll
https://mrbeancpp.github.io/2024/10/06/Qt-Cmake-project-lost-qwindowsvistastyle-dll/
作者
MrBeanC
发布于
2024年10月6日
许可协议