由于工作需要,同时也为了方便以后的集成升级,希望将之前用Qt creator qmake开发的项目移植到cmake项目中,并使用Visual Studio 进行后续开发,本文主要用以记录该过程中的常规步骤和遇到的特殊情况。
在一开始,为了降低开发难度以及快速完成业务开发,我们使用Qt Creator原生编译器以及qmake来进行软件界面研发。编写pro文件来生成makefile,makefile将用于指导后续的各种编译器生成可执行文件。(关于makefile的介绍可以参考这篇文章添加链接描述)
下面我们大致介绍一下该项目原本的pro文件。其中我删减了部分无关紧要的内容,只保留将被转换为cmake工程所需要的东西。
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
# 添加xml文件读写功能
QT+=xml
CONFIG += c++11
include(D:/software/QT5.14.0/package/VTK-8.2.0/VTK-8.2.0.pri)
# 如果要使用VTKACtorToOSG功能 需要引入 osg库
INCLUDEPATH +=D:/BaiduNetdiskDownload/install/include
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losg
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgViewer
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgViewerd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgDB
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgDBd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -lOpenThreads
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -lOpenThreads
SOURCES += \
customUnit/dockwidget.cpp \
customUnit/mycustomslider.cpp \
...
HEADERS += \
customUnit/dockwidget.h \
customUnit/mycustomslider.h \
...
FORMS += \
customUnit/dockwidget.ui \
...
其中包含了Qt的几个模块功能库,vtk库,以及osg库中的几个模块。
VTK库中仅包含了MSVC编译的release版本。
OSG库也是用的MSVC编译的release版本。
Qt库使用MSVC编译的包含debug版本和release版本。
编译器使用对应的MSVC 编译器。
这里有个遗留问题,开发设备上原本的Qt creator只有Mingw的编译器,为了让其支持MSVC编译,我们在Visual Studio 中下载了MSVC2017版本来使用,但Qtcreator无法自动识别该编译器,我们手动配置一个自定义的编译器选项去查找到它(这个问题在后续的移植工作中会在导入库的时候再次出现)。
为了方便,我们先使用Qtcreator创建了一个cmake工程,让它帮我们先生成一部分cmakelist.txt代码。
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX COMPILER WORKS 1)
project(Window_cmake_version )
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
if(ANDROID)
add_library(Window_cmake_version SHARED
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
else()
add_executable(Window_cmake_version
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
endif()
target_link_libraries(Window_cmake_version PRIVATE Qt5::Widgets)
其中自动包含了Qt的库的引入。
我们一一对应将pro中的内容转为cmakelist.txt中的内容。
qmake
QT += core gui
QT += widgets
QT+=xml
cmake
find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt5 COMPONENTS Xml REQUIRED)
find_package(Qt5 COMPONENTS Gui REQUIRED)
target_link_libraries(Window_cmake_version PRIVATE Qt5::Widgets)
target_link_libraries(Window_cmake_version PRIVATE Qt5::Xml)
target_link_libraries(Window_cmake_version PRIVATE Qt5::Gui)
qmake
//为了便于引入库,我们在vtk库中编写了pri文件,实际上它只是简化了导入lib和头文件的过程
include(D:/software/QT5.14.0/package/VTK-8.2.0/VTK-8.2.0.pri)
cmake
//这里我们使用cmake查找包的方式来导入vtk库
find_package(VTK REQUIRED)
if(VTK_FOUND)
message(STATUS "found VTK_DIR")
else(VTK_FOUND)
message(FATAL_ERROR "VTK not found. Please set VTK_DIR")
endif(VTK_FOUND)
include(${VTK_USE_FILE})
target_link_libraries(Window_cmake_version
PRIVATE optimized ${VTK_LIBRARIES})
qmake
# 如果要使用VTKACtorToOSG功能 需要引入 osg库(只使用部分库,不需要全引入) 这里实际上只用到了release版本
INCLUDEPATH +=D:/BaiduNetdiskDownload/install/include
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losg
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgViewer
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgViewerd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgDB
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -losgDBd
win32:CONFIG(release, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -lOpenThreads
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/BaiduNetdiskDownload/install/lib/ -lOpenThreads
cmake
# 查找OSG 库 该方式也适用于vtk库的导入
target_include_directories(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/include)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osg.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osgViewer.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osgDB.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/OpenThreads.lib)
qmake
SOURCES += \
customUnit/dockwidget.cpp \
customUnit/mycustomslider.cpp \
...
HEADERS += \
customUnit/dockwidget.h \
customUnit/mycustomslider.h \
...
FORMS += \
customUnit/dockwidget.ui \
...
cmake
set(HEADERS
customUnit/dockwidget.h
customUnit/mycustomslider.h
...
)
set(UI
customUnit/dockwidget.ui
...
)
set(SOURCES
customUnit/dockwidget.cpp
customUnit/mycustomslider.cpp
...
)
add_executable(Window_cmake_version
${SOURCES} ${UI} ${HEADERS} )
到这里我们大致上就实现了pro文件到cmakelist.txt文件的迁移。
最终生成的cmakelist.txt文件
cmake_minimum_required(VERSION 3.5)
#set(CMAKE_PREFIX_PATH "D:/software/QT5.14.0/5.14.0/mingw73_64")
project(Window_cmake_version)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
#set (CMAKE_CXX COMPILER WORKS 1)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt5 COMPONENTS Xml REQUIRED)
find_package(Qt5 COMPONENTS Gui REQUIRED)
set(HEADERS
customUnit/dockwidget.h
customUnit/mycustomslider.h
...
)
set(UI
customUnit/dockwidget.ui
...
)
set(SOURCES
customUnit/dockwidget.cpp
customUnit/mycustomslider.cpp
...
)
# 查找 VTK 库
#find_package(VTK REQUIRED PATHS D:/software/QT5.14.0/package/VTK-8.2.0/lib/cmake/vtk-8.2)
find_package(VTK REQUIRED)
if(VTK_FOUND)
message(STATUS "found VTK_DIR")
else(VTK_FOUND)
message(FATAL_ERROR "VTK not found. Please set VTK_DIR")
endif(VTK_FOUND)
include(${VTK_USE_FILE})
add_executable(Window_cmake_version
${SOURCES} ${UI} ${HEADERS} )
# 查找OSG 库
target_include_directories(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/include)
#add_executable(untitled11)
#add_executable(untitled11 main.cpp )
target_link_libraries(Window_cmake_version PRIVATE Qt5::Widgets)
target_link_libraries(Window_cmake_version PRIVATE Qt5::Xml)
target_link_libraries(Window_cmake_version PRIVATE Qt5::Gui)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osg.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osgViewer.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/osgDB.lib)
target_link_libraries(Window_cmake_version PRIVATE D:/BaiduNetdiskDownload/install/lib/OpenThreads.lib)
target_link_libraries(Window_cmake_version
PRIVATE optimized ${VTK_LIBRARIES})
实际运行后我们遇到了几个问题:
cmakelist find_find_package() 方式找包机制找到了环境中的vtk8.1的包,这并不是我们想要的8.2的包,同样qt库也出现了一样的问题,找到了Mingw的版本库,这必然是无法接受的,目前的解决方案是去CMakeSettings.json中手动修改它自动寻找填充的项。应该有更好的解决方案,希望不吝赐教。
使用MSVC release版本编译后,dll链接错误(无法定义到入口xxx等问题),这和qt打包应用程序类似,需要把相关dll都收集过来扔到可执行程序目录下即可解决,如果有更好的解决方案,也希望评论留言交流一下。
相关库dll都收集完后依然运行时报错:
This application failed to start because it could not find or load the Qt platform plugin “windows”
Reinstalling the application may fix this problem.
解决办法:
QT为了简化生成发布版本,特别提供了工具 “windeployqt.exe”,这个工具在 "…\Qt5.8.0\5.8\msvc2017_64\bin"的 目录下,通过该命令,可以解决上述错误。
打开控制台窗口
设置搜索路径以便系统可以搜索到 “windeployqt.exe”
在windeployqt.exe目录下,运行 “windeployqt.exe sample.exe”, 所需要的QT运行库就自动拷贝到目标程序目录了。如果运行报错,重新输入为:./windeployqt.exe sample.exe