CMake
是一組允許構建、測試及打包應用程序的工具。就像 Qt,它可用於所有主流開發平颱。它還被各種 IDE 所支持,包括
Qt Creator
.
此節將展示在 CMake 工程中,使用 Qt 的最基本方式。首先,創建基本控製颱應用程序。然後,將工程擴展成 GUI 應用程序使用 Qt Widgets .
若想要知道如何采用 Qt 構建現有 CMake 工程,見文檔編製 如何在命令行中采用 CMake 構建工程 .
要學習 CMake 快速入門基礎,接受 采用 Cmake 構建:CMake 和 Qt 快速入門 課程在 Qt 學院。
A
CMake
工程是以 CMake 語言編寫的文件定義。main 文件稱為
CMakeLists.txt
,通常放在實際程序源代碼的相同目錄下。
這裏是典型
CMakeLists.txt
文件用於使用 Qt 以 C++ 編寫的控製颱應用程序:
cmake_minimum_required(VERSION 3.16)
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core)
qt_standard_project_setup()
qt_add_executable(helloworld
main.cpp
)
target_link_libraries(helloworld PRIVATE Qt6::Core)
讓我們瀏覽一下內容。
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required()
specifies the minimum CMake version that is required to successfully configure the project. See
支持的 CMake 版本
for the minimum version required by Qt.
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
project()
設置工程名稱和默認工程版本。
LANGUAGES
自變量告訴 CMake 程序是以 C++ 編寫的。
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)
Qt 6 要求編譯器支持 C++ 第 2017 或更高版本。實施這是通過設置
CMAKE_CXX_STANDARD
,
CMAKE_CXX_STANDARD_REQUIRED
變量將使 CMake 打印錯誤,若編譯器太舊。
find_package(Qt6 REQUIRED COMPONENTS Core)
This tells CMake to look up Qt 6 and make the
Core
module available. There is no point in continuing if
CMake
無法定位模塊,因此,設置
REQUIRED
flag to let CMake abort in this case. For more information, see
使 Qt 可用於 CMake 工程
.
若成功,模塊將設置一些 CMake 文檔化變量在
模塊變量
。此外,它還導入
Qt6::Core
目標 (使用於下文)。
qt_standard_project_setup()
The qt_standard_project_setup command sets project-wide defaults for a typical Qt application.
除其它事情外,此命令設置
CMAKE_AUTOMOC
變量到
ON
,指導 CMake 自動設置規則,以便 Qt 的
MOC (元對象編譯器)
is called transparently, when required.
見 qt_standard_project_setup 參考瞭解細節。
qt_add_executable(helloworld
main.cpp
)
qt_add_executable()
告訴 CMake 想要構建的可執行文件 (因此不是庫) 稱為
helloworld
as a target. It is a wrapper around the built-in
add_executable()
command, and provides additional logic to automatically handle things like linking of Qt plugins in static Qt builds, platform-specific customization of library names, and so on.
應構建目標從 C++ 源文件
main.cpp
.
Typically, you do not list header files here. This is different from qmake ,需要明確列齣頭文件,以便處理它們通過 MOC (元對象編譯器) .
為創建庫,見 qt_add_library .
target_link_libraries(helloworld PRIVATE Qt6::Core)
最後,
target_link_libraries
告訴 CMake
helloworld
可執行文件利用
Qt Core
通過引用
Qt6::Core
目標,導入通過
find_package()
調用 (見上文)。這不僅將正確自變量添加到鏈接器,且還確保將正確包括目錄、編譯器定義傳遞給 C++ 編譯器。
PRIVATE
關鍵字對於可執行目標不是嚴格必要的,但指定它是良好實踐。若
helloworld
是庫而不是可執行文件,那麼
PRIVATE
or
PUBLIC
應該指定 (
PUBLIC
若庫提到的任何東西來自
Qt6::Core
在其頭中,
PRIVATE
否則)。
在 last section we showed the CMakeLists.txt file for a simple console application. We will now create a GUI application that uses the Qt Widgets 模塊。
這是完整工程文件:
cmake_minimum_required(VERSION 3.16)
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()
qt_add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
)
target_link_libraries(helloworld PRIVATE Qt6::Widgets)
set_target_properties(helloworld PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
讓我們迴顧一下所做的改變。
find_package(Qt6 REQUIRED COMPONENTS Widgets)
在
find_package
調用,我們替換
Core
with
Widgets
。這會定位
Qt6Widgets
模塊並提供
Qt6::Widgets
目標,我們稍後鏈接到。
qt_standard_project_setup()
除瞭
CMAKE_AUTOMOC
,
qt_standard_project_setup
設置
CMAKE_AUTOUIC
變量到
ON
。這會自動創建規則以援引 Qt 的
uic (用戶界麵編譯器)
on
.ui
源文件。
qt_add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
)
我們添加
Qt Widgets Designer
文件 (
mainwindow.ui
) 及其相應 C++ 源文件 (
mainwindow.cpp
) 到應用程序目標的源。
注意:
Another way to add
.ui
files to your project is to use the command
qt_add_ui
而不是
AUTOUIC
.
target_link_libraries(helloworld PRIVATE Qt6::Widgets)
在
target_link_libraries
命令,我們鏈接到
Qt6::Widgets
而不是
Qt6::Core
. Note that the application will still link against
Qt6::Core
,因為
Qt6::Widgets
從屬它。
set_target_properties(helloworld PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
最後,設置應用程序目標特性,效果如下:
見 CMake 文檔編製 for more information about these target properties.
Projects that contain more than just one target will benefit from a clear project file structure. We will use CMake's 子目錄特徵 .
由於我們計劃采用更多目標擴展工程,所以將應用程序源文件移到子目錄並創建新的
CMakeLists.txt
in there.
<project root>
├── CMakeLists.txt
└── src
└── app
├── CMakeLists.txt
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
└── mainwindow.ui
頂層
CMakeLists.txt
包含整體工程設置,
find_package
and
add_subdirectory
調用:
cmake_minimum_required(VERSION 3.16) project(helloworld VERSION 1.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Widgets) qt_standard_project_setup() add_subdirectory(src/app)
Variables that are set in this file are visible in subdirectory project files.
應用程序工程文件
src/app/CMakeLists.txt
包含可執行目標:
qt_add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
)
target_link_libraries(helloworld PRIVATE Qt6::Widgets)
set_target_properties(helloworld PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
Such a structure will make it easy to add more targets to the project such as libraries or unit tests.
注意: Add your project build directory to the list of excluded directories of any anti-virus application that runs on your system.
隨著工程增長,可能想要將部分應用程序代碼轉換成用於應用程序且可能單元測試的庫。此節展示如何創建這種庫。
我們的應用程序目前將業務邏輯直接包含在
main.cpp
。我們將代碼提取到的新靜態庫稱為
businesslogic
在子目錄
"src/businesslogic"
as explained in the
上一章節
.
為簡單起見,庫僅僅包含一個 C++ 源文件及其相應頭文件,頭文件包括在應用程序的
main.cpp
:
<project root>
├── CMakeLists.txt
└── src
├── app
│ ├── ...
│ └── main.cpp
└── businesslogic
├── CMakeLists.txt
├── businesslogic.cpp
└── businesslogic.h
讓我們查看一下庫工程文件 (
src/businesslogic/CMakeLists.txt
).
qt_add_library(businesslogic STATIC
businesslogic.cpp
)
target_link_libraries(businesslogic PRIVATE Qt6::Core)
target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
讓我們瀏覽一下內容。
qt_add_library(businesslogic STATIC
businesslogic.cpp
)
The
add_library
command creates the library
businesslogic
。稍後,將讓應用程序鏈接到此目標。
The
STATIC
keyword denotes a static library. If we wanted to create a shared or dynamic library, we would use the
SHARED
關鍵詞。
target_link_libraries(businesslogic PRIVATE Qt6::Core)
We have a static library and don't actually have to link other libraries. But as our library uses classes from
QtCore
,添加依賴鏈接到
Qt6::Core
。這會壓入必要
QtCore
include paths and preprocessor defines.
target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
The library API is defined in the header file
businesslogic/businesslogic.h
。通過調用
target_include_directories
,確保絕對路徑
businesslogic
directory is automatically added as an include path to all targets using our library.
This frees us in
main.cpp
from using relative paths to locate
businesslogic.h
。取而代之,可以僅僅編寫
#include <businesslogic.h>
最後,必須將庫的子目錄添加到頂層工程文件中:
add_subdirectory(src/app) add_subdirectory(src/businesslogic)
To use the library we created in the 上一章節 ,我們指導 CMake 鏈接到它:
target_link_libraries(helloworld PRIVATE
businesslogic
Qt6::Widgets
)
This ensures that
businesslogic.h
is found when main.cpp is compiled. Furthermore, the businesslogic static library will become a part of the
helloworld
可執行文件。
在 CMake 術語中,庫
businesslogic
specifies
usage requirements
(include 路徑) 庫 (應用程序) 的每個消費者都必須滿足。
target_link_libraries
command takes care of that.
We want to display some images in our application, so we add them using the Qt 資源係統 .
qt_add_resources(helloworld imageresources
PREFIX "/images"
FILES logo.png splashscreen.png
)
The qt_add_resources command automatically creates a Qt resource containing the referenced images. From the C++ source code, you can access the images by prepending the specified resource prefix:
logoLabel->setPixmap(QPixmap(":/images/logo.png"));
The qt_add_resources command takes as the first argument either a variable name or a target name. We recommend to use the target-based variant of this command as shown in the example above.
Translations of strings in a Qt project are encoded in
.ts
files. These
.ts
files are compiled into binary
.qm
files, which are then loaded by the Qt application at run time. See
Qt 國際化
瞭解細節。
This section describes how to add a German and French translation to the
helloworld
應用程序。
Specify both languages with qt_standard_project_setup :
qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES de fr)
Then call
qt_add_translations
on the target that shall load the
.qm
files:
qt_add_translations(helloworld)
On the first configuration, this command creates the files
helloworld_de.ts
and
helloworld_fr.ts
在
source directory
of the project. These files will contain the translated strings and are supposed to be put under version control.
The command also creates build system rules to automatically generate
.qm
files from the
.ts
files. By default, the
.qm
files are embedded into a resource and are accessible under the
"/i18n"
resource prefix.
To update the entries in the
.ts
file, build the
update_translations
目標:
$ cmake --build . --target update_translations
To trigger the generation of the
.qm
files manually, build the
release_translations
目標:
$ cmake --build . --target release_translations
對於更多信息有關如何影響處理
.ts
files and the embedding into a resource, see the
qt_add_translations documentation
.
The
qt_add_translations
command is a convenience wrapper. For more fine-grained control of how
.ts
files and
.qm
files are handled, use the underlying commands
qt_add_lupdate
and
qt_add_lrelease
.
官方 CMake 文檔編製 是使用 CMake 的寶貴資源。
官方 CMake 教程 covers common build system tasks.
書籍 專業 CMake:實踐指南 提供 CMake 最相關特徵的很好介紹。