Qt5 CMake 使用指南
Qt5 CMake 使用指南
CMAKE_PREFIX_PATH的使用说明
CMAKE_PREFIX_PATH是CMake中一个重要的环境变量,它用于帮助CMake在配置项目时找到各种依赖项的位置。这个变量尤其在处理那些不在标准位置安装的库时显得非常有用。
作用
CMAKE_PREFIX_PATH指定了一系列的路径,CMake会在这些路径中搜索需要的包、库、工具等。当使用find_package、find_library、find_file等命令时,CMake会优先在CMAKE_PREFIX_PATH指定的路径中查找。
设置方法
CMAKE_PREFIX_PATH可以通过多种方式设置,包括在命令行中直接设置,或者在CMakeLists.txt文件中设置。
在命令行中设置
在命令行中设置CMAKE_PREFIX_PATH,可以在调用cmake命令时使用-D选项:
这种方法适用于临时指定某个依赖项的路径。
在CMakeLists.txt中设置
也可以在CMakeLists.txt文件中通过set命令设置CMAKE_PREFIX_PATH:
这种方法适用于项目中有固定依赖路径的情况,可以确保所有人在构建项目时使用相同的路径。
注意事项
CMAKE_PREFIX_PATH可以包含多个路径,路径之间使用分号(;)分隔。
CMake中使用find_package查找Qt5
find_package命令在CMake中用于查找并加载指定的包(在这里是Qt5)。这个命令会检查系统中是否安装了指定的包,并提供必要的变量和目标,以便在项目中使用这些包。
使用find_package查找Qt5
当你需要在你的CMake项目中使用Qt5时,可以通过find_package命令来查找Qt5及其组件。以下是一个示例,展示了如何查找Qt5的核心组件,包括Core、Gui、Widgets和Multimedia:
find_package(Qt5 REQUIRED COMPONENTS
Core
Gui
Widgets
Multimedia
)
参数解释
REQUIRED:这个参数指示如果找不到Qt5或指定的组件,CMake应该终止配置过程。
COMPONENTS:后面跟随的是你希望在项目中使用的Qt5组件列表。在这个例子中,我们指定了Core、Gui、Widgets和Multimedia。
配置项目使用Qt5
在使用find_package成功找到Qt5之后,你可以通过链接目标库的方式,将Qt5组件添加到你的目标(例如可执行文件或库)中:
# 假设你的项目是一个可执行文件
add_executable(my_app
main.cpp
# 其他源文件
)
# 链接Qt5库
target_link_libraries(my_app
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Multimedia
)
注意事项
确保在调用find_package之前,你的系统已经正确安装了Qt5,并且CMAKE_PREFIX_PATH环境变量已经设置为Qt5的安装路径。这样CMake才能正确找到Qt5。
如果你的项目中使用了Qt特有的代码(如MOC、UI文件等),还需要在CMakeLists.txt中相应配置,例如启用AUTOMOC或使用qt5_wrap_ui处理UI文件。
在CMake中设置WIN32_EXECUTABLE选项构建非控制台程序
在使用CMake构建Windows应用程序时,WIN32_EXECUTABLE选项用于指定生成的是一个Windows应用程序,而不是控制台应用程序。这个选项通常在调用add_executable函数时使用,以确保应用程序在没有控制台窗口的情况下运行。
使用WIN32_EXECUTABLE选项
当你希望你的应用程序作为一个GUI应用程序运行,而不是在命令行窗口中运行时,可以在add_executable命令中使用WIN32标志。对于CMake版本3.14及以上,可以使用WIN32_EXECUTABLE目标属性来更明确地控制这一行为。
cmake_minimum_required(VERSION 3.14)
project(MyApp)
# 设置源文件
set(SOURCE_FILES main.cpp)
# 添加一个可执行文件
add_executable(${PROJECT_NAME} WIN32 ${SOURCE_FILES})
# 对于CMake 3.14及以上版本,可以使用WIN32_EXECUTABLE目标属性
set_target_properties(${PROJECT_NAME} PROPERTIES
WIN32_EXECUTABLE ON
)
qt5 设置Windows应用程序图标
在CMake项目中,你可以通过指定资源文件来设置Windows应用程序的图标。这通常通过在项目的CMakeLists.txt
文件中设置一个变量来实现,该变量指向包含图标资源的.rc
文件。
以下是如何在CMake项目中设置Windows应用程序图标的示例:
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/icon.rc")
参数解释
APP_ICON_RESOURCE_WINDOWS
:这是一个自定义变量名,用于存储图标资源文件的路径。${CMAKE_CURRENT_SOURCE_DIR}
:这是一个CMake变量,指向当前处理的CMakeLists.txt
文件所在的目录。/icon.rc
:这是图标资源文件的相对路径和文件名。假设这个文件位于与当前CMakeLists.txt
文件同一目录下。
使用资源文件
在设置了包含图标资源的.rc
文件路径后,你需要将这个资源文件包含到你的应用程序中。这通常在添加可执行文件的命令中完成:
add_executable(${PROJECT_NAME}
${SOURCE_FILES}
${APP_ICON_RESOURCE_WINDOWS} # 包含图标资源文件
)
在这个示例中,${APP_ICON_RESOURCE_WINDOWS}
变量被用于add_executable
命令中,这样就将图标资源文件包含到了最终的应用程序中。
注意事项
- 确保
.rc
文件正确指向了你的应用程序图标文件。.rc
文件是一个资源脚本文件,通常包含了图标、菜单、对话框定义等资源的引用。
CMake中生成Qt UI头文件的两种方式
在使用CMake进行Qt项目的构建时,有两种主要方式来处理.ui
文件,从而生成相应的UI头文件。这些方法分别是启用CMAKE_AUTOUIC
选项和使用qt5_wrap_ui()
命令。
-
方法一:启用
CMAKE_AUTOUIC
选项通过设置
CMAKE_AUTOUIC
变量为ON
,CMake会自动处理.ui
文件,生成对应的UI头文件。这种方法简单且自动化,适用于大多数情况。set(CMAKE_AUTOUIC ON)
当
CMAKE_AUTOUIC
设置为ON
时,CMake会自动寻找与当前项目中的.cpp
文件同名的.ui
文件,并将它们转换为UI头文件。这意味着不需要手动指定.ui
文件,CMake会自动处理。 -
方法二:使用
qt5_wrap_ui()
命令如果出于某种原因需要禁用
CMAKE_AUTOUIC
变量,还可以手动处理.ui
文件。这可以通过使用qt5_wrap_ui()
命令来实现,该命令将.ui
文件转换为UI头文件,并将输出文件列表存储在指定的变量中。# 禁用CMAKE_AUTOUIC set(CMAKE_AUTOUIC OFF) # 手动处理.ui文件 qt5_wrap_ui(UI_HEADERS ${FORM_FILES}) # 在add_executable或add_library中包含生成的UI头文件 add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES} ${UI_HEADERS} # 包含生成的UI头文件 ${QT_RESOURCES} ${APP_ICON_RESOURCE_WINDOWS} ) # 添加 target_include_directories() 命令,生成的UI头文件所在的目录通常是当前构建目录 # 即CMAKE_CURRENT_BINARY_DIR,因此需要将该目录添加到包含目录中。 target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
在这种方法中,需要明确指定
.ui
文件,并通过qt5_wrap_ui()
命令生成UI头文件。然后,在add_executable
或add_library
命令中包含这些生成的头文件。
Qt5 UI 生成的头文件找不到自定义类所在的头文件的处理方法
在使用 Qt5 进行项目开发时,有时会遇到一个问题:通过 uic 工具自动生成的 UI 头文件无法找到项目中自定义类的头文件。这种情况通常发生在项目结构比较复杂,或者自定义类与 UI 类不在同一个目录下时。以下是解决这个问题的两种方法:
-
方法一:使用 target_include_directories
这种方法是通过在 CMakeLists.txt 文件中为目标项目添加包含目录来解决的。具体操作如下:在 CMakeLists.txt 文件中找到 target_include_directories 命令。
在该命令中添加包含自定义类头文件的目录路径。确保路径是相对于项目根目录的相对路径或者是一个绝对路径。
例如,如果自定义类的头文件位于项目的 include 目录下,可以这样写:这样,当 uic 工具生成 UI 头文件时,编译器就能够找到自定义类的头文件了。
-
方法二:取消勾选全局包含
在某些情况下,如果项目设置中勾选了全局包含(在 Qt Creator 中),可能会导致编译器在整个项目范围内搜索头文件,这可能会引起一些不必要的编译问题。取消这个选项可以让我们更精确地控制包含目录,避免潜在的冲突。打开 Qt Creator,导航到项目设置。
在构建设置中找到“全局包含”选项,并取消勾选。
明确指定需要包含的目录,如方法一所述。
qt5 部署 Windows 程序
在 Windows 平台上部署 Qt5 程序时,需要将 Qt5 运行时库(DLL 文件)一同打包到程序目录中,以确保程序能够在没有安装 Qt5 的计算机上正常运行。以下是部署 Qt5 程序到 Windows 的一般步骤:
自动部署依赖项
如果系统中安装了Qt,并且windeployqt.exe
工具可用,脚本会利用这个工具自动部署应用程序的依赖项。
检查windeployqt.exe
脚本首先检查windeployqt.exe
是否存在:
if (EXISTS "${CMAKE_PREFIX_PATH}/bin/windeployqt.exe")
message("windeployqt exists")
如果存在,使用windeployqt.exe
自动处理依赖项:
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND "${CMAKE_PREFIX_PATH}/bin/windeployqt.exe" "--compiler-runtime"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe"
)
手动部署依赖项
如果windeployqt.exe
不存在,手动部署依赖项:
- 设置调试后缀:根据构建类型(Debug/Release),设置相应的后缀。
- 确定Qt安装路径:尝试定位Qt的安装路径。
- 复制Qt插件:将必要的Qt插件复制到构建目录。
- 复制Qt库:将需要的Qt库(如
Qt5Core.dll
、Qt5Gui.dll
等)复制到构建目录。 - 处理MinGW依赖(如果使用MinGW):复制MinGW运行时库到构建目录。
MinGW部署
对于使用MinGW的项目,从指定路径复制MinGW运行时库:
if (MINGW)
set(MINGW_PATH "D:/Scoop/apps/msys2/current/ucrt64")
message("MINGW ENV: ${MINGW_PATH}")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libgcc_s_seh-1.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libstdc++-6.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libwinpthread-1.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMENT "Deploying mingw runtime libraries from ${MINGW_PATH}/bin"
)
endif ()
附:完整 CMakeLists.txt 示例
cmake_minimum_required(VERSION 3.24)
project(Qt5CMakeDemo)
message("PROJECT_NAME: ${PROJECT_NAME}")
find_package(Qt5 REQUIRED COMPONENTS
Core
Gui
Widgets
Multimedia
)
# ==================== set build options ====================
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if (WIN32)
if (MINGW)
message("GNU")
set(CMAKE_PREFIX_PATH "C:/Qt/5.15.2/mingw81_64")
elseif (MSVC)
message("MSVC")
set(CMAKE_PREFIX_PATH "C:/Qt/5.15.2/msvc2019_64")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif ()
elseif (APPLE)
# Add Apple specific settings here
else ()
endif ()
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Build Type not set, defaulting to Release...")
set(CMAKE_BUILD_TYPE Release)
endif ()
message(${PROJECT_NAME} " build type: " ${CMAKE_BUILD_TYPE})
message("CMAKE_PREFIX_PATH: " ${CMAKE_PREFIX_PATH})
message("CXX Compiler: " ${CMAKE_CXX_COMPILER})
message("CXX Standard: " ${CMAKE_CXX_STANDARD})
# ==================== set Project Source Files ====================
set(SOURCE_FILES
main.cpp
mainwidget.cpp
)
set(HEADER_FILES
mainwidget.h
)
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/icon.rc")
# 如果禁用 CMAKE_AUTOUIC 变量,还可以使用 qt_wrap_ui() 该命令手动处理 .ui 文件。
# qt5_wrap_ui(UI_HEADERS mainwidget.ui)
# 如果禁用 CMAKE_AUTORCC 变量,还可以使用 qt5_add_resources() 命令手动处理 .qrc 文件。
# 同时可以 使用 AUTORCC_EXECUTABLE 变量指定 rcc 可执行文件的路径。
# qt5_add_resources(QT_RESOURCES pic.qrc)
# ==================== set Project Target ====================
add_executable(${PROJECT_NAME}
${SOURCE_FILES}
${HEADER_FILES}
${APP_ICON_RESOURCE_WINDOWS}
# ${UI_HEADERS}
# ${QT_RESOURCES}
)
# target_include_directories(${PROJECT_NAME} PRIVATE
# ${CMAKE_CURRENT_SOURCE_DIR}
# # ${CMAKE_CURRENT_BINARY_DIR}
# )
target_link_libraries(${PROJECT_NAME}
Qt5::Core
Qt5::Gui
Qt5::Multimedia
Qt5::Widgets
)
# create a GUI application
if (CMAKE_BUILD_TYPE MATCHES "Release" OR CMAKE_CONFIGURATION_TYPES MATCHES "Release")
set_target_properties(${PROJECT_NAME} PROPERTIES
WIN32_EXECUTABLE ON
MACOSX_BUNDLE ON
)
endif ()
# ==================== Deployment ====================
# Handle Windows deployment
if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
message("WIN32 DEPLOYMENT")
# 如果存在 windeployqt.exe 工具,则自动部署依赖项
if (EXISTS "${CMAKE_PREFIX_PATH}/bin/windeployqt.exe")
message("windeployqt exists")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND "${CMAKE_PREFIX_PATH}/bin/windeployqt.exe" "--compiler-runtime"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe"
)
else ()
message(FATAL_ERROR "windeployqt.exe not found!")
# Set the debug suffix to copy the correct Qt libraries
set(DEBUG_SUFFIX)
if (CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_CONFIGURATION_TYPES MATCHES "Debug")
set(DEBUG_SUFFIX "d")
endif ()
# Set the path to the Qt installation
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 ()
message("QT_INSTALL_PATH: ${QT_INSTALL_PATH}")
# Copy the required Qt plugins to the build directory
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 ()
# Copy the required Qt libraries to the build directory
foreach (QT_LIB Core Gui Widgets Multimedia Network Svg)
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 ()
# MINGW deployment, copy the required MinGW libraries
if (MINGW)
if (NOT DEFINED ENV{UCRT64})
# message(FATAL_ERROR "UCRT64 environment variable not set!")
set(MINGW_PATH "D:/Scoop/apps/msys2/current/ucrt64")
message("MINGW ENV: ${MINGW_PATH}")
else ()
set(MINGW_PATH "$ENV{UCRT64}")
message("MINGW UCRT64 ENV: ${MINGW_PATH}")
endif ()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libgcc_s_seh-1.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libstdc++-6.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMAND ${CMAKE_COMMAND} -E copy "${MINGW_PATH}/bin/libwinpthread-1.dll" "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMENT "Deploying mingw runtime libraries from ${MINGW_PATH}/bin"
)
endif ()
endif () # End of windeployqt.exe check
endif ()