Qt5.15.2在之前選擇安裝模塊的時(shí)候,自動(dòng)幫我們勾選了CMake_64模塊,你也可以另外選擇勾選CMake_32模塊,所以QtCreator是支持CMake編譯方式的,而不僅僅只能使用QMake編譯。本人之前也手動(dòng)安裝了CMake3.20.0的版本,這些可以在QtCreator中的套件配置的cmake項(xiàng)看到:下面我們介紹一下Qt使用CMake編譯的兩種方式。首先,我們還是要使用QtCreator創(chuàng)建項(xiàng)目:helloworld。
<< 收起為什么要用 CMake 來構(gòu)建 Qt 的項(xiàng)目呢?Qt 不是有 qmake 嗎?這樣,豈不是多此一舉?
其實(shí),應(yīng)用 CMake 來構(gòu)建項(xiàng)目還是非常有必要的,特別是當(dāng)你的項(xiàng)目涉及到很多第三方庫的時(shí)候,CMake 的優(yōu)勢非常突出。
Qt5.15.2 在之前選擇安裝模塊的時(shí)候,自動(dòng)幫我們勾選了 CMake_64 模塊,你也可以另外選擇勾選 CMake_32 模塊,所以 QtCreator 是支持 CMake 編譯方式的,而不僅僅只能使用 QMake 編譯。
本人之前也手動(dòng)安裝了 CMake3.20.0 的版本,這些可以在 QtCreator 中的套件配置的 cmake 項(xiàng)看到:
下面我們介紹一下 Qt 使用 CMake 編譯的兩種方式。
QtCreator 新建工程時(shí),選擇 cmake 而不是默認(rèn)的 qmake 編譯方式,如下所示:
然后選擇 CMake 要編譯成的哪種編譯套件,是 MingW 還是 MSVC,這里選擇的是 Qt5.15.2 MinGW 64,創(chuàng)建運(yùn)行成功后:
可以看到 QtCreator 自動(dòng)幫忙生成了 CMakeLists.txt 文件,直接可以使用,其內(nèi)容如下:
cmake_minimum_required(VERSION 3.5)
project(HelloWorld LANGUAGES CXX)
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)
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package( ...) calls below.
#if(ANDROID)
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
# set(ANDROID_EXTRA_LIBS
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
# endif()
#endif()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(PROJECT_SOURCES
main.cpp
widget.cpp
widget.h
widget.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_ executable(HelloWorld
${PROJECT_SOURCES}
)
else()
if(ANDROID)
add_library(HelloWorld SHARED
${PROJECT_SOURCES}
)
else()
add_executable(HelloWorld
${PROJECT_SOURCES}
)
endif()
endif()
target_link_libraries(HelloWorld PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
QtCreator 也幫忙添加了 CMake Modules,來支持對 Qt5Core、Qt5Gui 等模塊的支持。
就是后續(xù)在工程中添加其它的類,比如 Form 類,不會(huì)自動(dòng)添加到 CMakeLists.txt 文件中,需要手動(dòng)添加:
set(PROJECT_SOURCES
main.cpp
widget.cpp
widget.h
widget.ui
#下面為手動(dòng)添加內(nèi)容
form.cpp
form.h
form.ui
)
需要添加額外的模塊,同理。
當(dāng)然自動(dòng)生成的 CMakeLists.txt 有些累贅的內(nèi)容,比如對 ANDROID 的配置,下面會(huì)介紹一下如何自己編寫 CMakeLists.txt 來創(chuàng)建工程。
你也可以自己手動(dòng)配置 CMakeLists.txt。
首先,我們還是要使用 QtCreator 創(chuàng)建項(xiàng)目:helloworld。項(xiàng)目中的文件列表如下:項(xiàng)目雖小,五臟俱全,該有的文件都有了(.h .cpp .qrc .ui .pro .png)。我把 .png 文件和 .qrc 文件放在了一個(gè)新建的 resources 資源文件夾中。
├── helloworld.pro
├── helloworld.pro.user
├── main.cpp
├── resources
│ ├── ico.png
│ └── resources.qrc
├── widget.cpp
├── widget.h
└── widget.ui
該項(xiàng)目中唯一需要添加代碼的地方是 widget.cpp 文件,因?yàn)槲覀冃枰砑右粋€(gè)圖標(biāo):
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 窗體標(biāo)題
this->setWindowTitle("Qt5.1 窗體應(yīng)用");
// 窗體 ICO 圖片,如圖不起別名,后綴直接寫圖片全名。
this->setWindowIcon(QIcon(":/new/prefix1/ico.png"));
}
Widget::~Widget()
{
delete ui;
}
接著在項(xiàng)目文件夾中手動(dòng)創(chuàng)建一個(gè) CMakeLists.txt 文件,添加到工程中,其內(nèi)容如下:
#設(shè)置cmake版本號(hào)
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)
#設(shè)置工程名稱(看情況修改)
project(helloworld)
# 添加C++11(非必須)
set(CMAKE_CXX_STANDARD 11)
#打開全局moc
set(CMAKE_AUTOMOC ON)
#打開全局uic
set(CMAKE_AUTOUIC ON)
#打開全局rcc,如果沒有使用qrc,此句可以去掉
set(CMAKE_AUTORCC ON)
#設(shè)置工程包含當(dāng)前目錄,使用*.ui文件時(shí),需要加上這句,否則找不到頭文件
set(CMAKE_INCLUDE_CURRENT_DIR ON)
#查找需要的Qt庫文件,最好每一個(gè)庫都要寫,Qt也會(huì)根據(jù)依賴關(guān)系自動(dòng)添加
find_package(Qt5 REQUIRED Widgets)
#創(chuàng)建工程文件
add_executable(helloworld main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)
#添加Qt5依賴項(xiàng)
target_link_libraries(helloworld Qt5::Widgets)
這是 CMakeLists.txt 編寫的第一種方法,全局控制:從 CMake 全局入手控制文件生成,非常簡便!后面會(huì)介紹另外兩種方法。
最后的項(xiàng)目組成如下:
├── CMakeLists.txt
├── CMakeLists.txt.user
├── helloworld.pro
├── helloworld.pro.user
├── main.cpp
├── resources
│ ├── ico.png
│ └── resources.qrc
├── widget.cpp
├── widget.h
└── widget.ui
關(guān)閉之前創(chuàng)建的 helloworld 項(xiàng)目,然后用 QtCreator 直接打開 CMakeLists.txt 文件,一開始會(huì)彈出一個(gè) configure 窗口,直接 configure 就可以實(shí)現(xiàn)項(xiàng)目配置,然后 cmake 該工程,就會(huì)添加 main.cpp、widget.h 等源文件到工程中。最后構(gòu)建運(yùn)行該項(xiàng)目報(bào)錯(cuò):
F:ProjectCMakehelloworldwidget.cpp:-1: error: undefined reference to `vtable for Widget'
在網(wǎng)上搜索發(fā)現(xiàn),跟 Qt 的 moc 機(jī)制有關(guān),也就是“元對象編譯器”,與之相關(guān)需要定義的宏 Q_OBJECT,與 CMakeLists.txt 中的set(CMAKE_AUTOMOC ON)
沖突,解決辦法就是注釋宏 Q_OBJECT。
moc 全稱是 Meta-Object Compiler,也就是“元對象編譯器”。Qt 程序在交由標(biāo)準(zhǔn)編譯器編譯之前,先要使用 moc 分析 C++ 源文件。如果它發(fā)現(xiàn)在一個(gè)頭文件中包含了宏 Q_OBJECT,則會(huì)生成另外一個(gè) C++ 源文件。這個(gè)源文件中包含了 Q_OBJECT 宏的實(shí)現(xiàn)代碼
修改后運(yùn)行成功,如下圖所示:
上面介紹了 CMakeLists.txt 編寫的第一種方法,全局控制,下面介紹另兩種方法。
方法二、目標(biāo)控制
#設(shè)置cmake版本號(hào)
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)
#設(shè)置工程名稱(看情況修改)
set(project_name helloworld)
project(${project_name})
# 添加C++11(非必須)
set(CMAKE_CXX_STANDARD 11)
#查找需要的Qt庫文件,最好每一個(gè)庫都要寫,Qt也會(huì)根據(jù)依賴關(guān)系自動(dòng)添加
find_package(Qt5 REQUIRED Widgets)
#設(shè)置目標(biāo)名稱
set(target_name ${project_name})
#創(chuàng)建工程文件
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc)
#添加Qt5依賴項(xiàng)
target_link_libraries(${target_name} Qt5::Widgets)
#設(shè)置目標(biāo)關(guān)聯(lián)的*.h, *.cpp 使用 Qt moc進(jìn)行編譯
set_target_properties(${target_name} PROPERTIES AUTOMOC ON)
#設(shè)置目標(biāo)關(guān)聯(lián)的*.ui 使用 Qt uic進(jìn)行編譯
set_target_properties(${target_name} PROPERTIES AUTOUIC ON)
#設(shè)置目標(biāo)關(guān)聯(lián)的*.qrc 使用 Qt uic進(jìn)行編譯
set_target_properties(${target_name} PROPERTIES AUTORCC ON)
#跳過不需要使用moc編譯的文件。如果覺得麻煩此句可以不寫,automoc能根據(jù)*.h,*.cpp代碼里面的宏(Q_OBJECT;Q_GADGET;Q_NAMESPACE)自動(dòng)判斷是否需要使用moc
set_source_files_properties(main.cpp PROPERTIES SKIP_AUTOMOC ON)
使用該方法,從目標(biāo)(可執(zhí)行或者庫)入手控制文件生成,可控力度更細(xì)一些。
上述兩種方法:
使用 CMake 官方 Auto 方法生成的 VS 工程,主要會(huì)修改三個(gè)地方:
TestWindow_autogeninclude_xxx
方法三、單個(gè)文件控制
#設(shè)置cmake版本號(hào)
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)
#設(shè)置工程名稱(看情況修改)
set(project_name helloworld)
project(${project_name})
# 添加C++11(非必須)
set(CMAKE_CXX_STANDARD 11)
#查找需要的Qt庫文件,最好每一個(gè)庫都要寫,Qt也會(huì)根據(jù)依賴關(guān)系自動(dòng)添加
find_package(Qt5 REQUIRED Widgets)
#包含當(dāng)前路徑,使用*.ui文件時(shí),需要加上這句,否則找不到頭文件
set(CMAKE_INCLUDE_CURRENT_DIR ON)
#需要生成的moc文件,輸出文件名稱放在變量 mocfiles中,必須在find QT5 package才能調(diào)用
qt5_wrap_cpp(mocfiles widget.h)
source_group("moc" FILES ${mocfiles})
#需要生成的ui文件,必須在find QT5 package才能調(diào)用
qt5_wrap_ui(uifiles widget.ui)
#打開全局rcc,如果沒有使用qrc,此句可以去掉
set(CMAKE_AUTORCC ON)
#設(shè)置目標(biāo)名稱
set(target_name ${project_name})
#添加生成的moc文件到目標(biāo)中
add_executable(${target_name} main.cpp widget.cpp widget.h widget.ui resources/resources.qrc ${mocfiles})
target_link_libraries(${target_name} Qt5::Widgets)
該方法從 源文件 入手控制文件生成,要稍微麻煩一些。
CMake 生成 VS 工程后,將 mainwindow.ui 的預(yù)處理命令放在 mainwindow.ui 屬性配置中,而 mainwindow.h 的預(yù)處理命令放在CMake Rules/moc_mainwindow.cpp.rule
的屬性配置中。源文件修改后,目標(biāo)文件會(huì)自動(dòng)生成。
參考:
用cmake構(gòu)建基于qt5.8.0的qt5項(xiàng)目
原創(chuàng)]Qt Creator構(gòu)建CMake項(xiàng)目
CMake學(xué)習(xí)(1)-Windows下安裝與使用
聯(lián)系客服