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_executableadd_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不存在,手动部署依赖项:

  1. 设置调试后缀:根据构建类型(Debug/Release),设置相应的后缀。
  2. 确定Qt安装路径:尝试定位Qt的安装路径。
  3. 复制Qt插件:将必要的Qt插件复制到构建目录。
  4. 复制Qt库:将需要的Qt库(如Qt5Core.dllQt5Gui.dll等)复制到构建目录。
  5. 处理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 ()

posted @ 2024-07-24 19:54  comsoi  阅读(23)  评论(0编辑  收藏  举报