CMake教程--QT项目使用CMake

CMake教程--QT项目使用CMake

  • Chapter1 CMake教程--QT项目使用CMake
    • 1. Basic Cmake Based Project
    • 2. Executable VS Library
    • 3. Every module has its own CMakeList.txt in its folder
      • 3.1 不推荐的做法:
      • 3.2 推荐的做法
    • 4. 强制以Debug, Release, RelWithDebInfo, MinSizeRel其中一种作为编译方式
      • 方法一:
      • 方法二:
    • 5. CMake高频常用变量
    • 6. 在CMake里区分操作系统
    • 7. 在CMake里打印信息
  • Chapter2 使用CMake构建Qt项目
    • 1.Qt中的qmake
    • 2.CMake中的构建
    • 3.具体构建过程
    • 4.结尾
  • Chapter3 CMake+QT使用教程
  • Chapter4 解析QT6自动生成的CMake文件
    • 1 新建基于CMake的QT6项目
    • 2 解析CMake文件
      • 2.1 定义CMake以及项目版本号
      • 2.2 启用QT资源自动编译选项
      • 2.3 定义使用到的C++标准
      • 2.4 查找并加载外部依赖包
      • 2.5 导入项目文件
      • 2.6 创建可执行文件
      • 2.7 链接动态库并设置可执行文件属性
      • 2.8 安装目标可执行文件到指定的目录
      • 2.9 进行最后的可执行文件处理


Chapter1 CMake教程–QT项目使用CMake

原文链接

1. Basic Cmake Based Project

# Qt对cmake版本的最小要求(但测试发现低一点的版本似乎也没问题)
cmake_minimum_required(VERSION 3.16.0)# 项目命名
# VERSION 1.0.0 LANGUAGES CXX: 是可选的
project(helloworld VERSION 1.0.0 LANGUAGES CXX)# 如果采用非Qt Creator开发,需要通过告知Qt的安装路径,建议把Qt的安装路径设置到环境变量
# 例如:QT_DIR=D:\Qt\6.1.2\msvc2019_64
set(CMAKE_PREFIX_PATH $ENV{QT_DIR})# 有些项目会动态生成头文件,项目中需要引入它,因此需要将output目录也include进来
# 等同于INCLUDE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_INCLUDE_CURRENT_DIR ON)# Qt6 对C++版本推荐至少17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# Qt特有的编译器需要打开,默认是关闭的
set(CMAKE_AUTOMOC ON) # Meta-Object Compiler
set(CMAKE_AUTORCC ON) # Resource Compiler
set(CMAKE_AUTOUIC ON) # User Interface Compiler# 寻找Qt的库
# Qt6 COMPONENTS Widgets:寻找Qt库中的Widget模块
# REQUIRED: 意味着找不到报错并不会继续下去
find_package(Qt6 COMPONENTS Core Qml Quick LinguistTools REQUIRED)# 集成源码以及资源并打包
set(TS_FILES TestApp_zh_CN.ts TestApp_en_US.ts)
aux_source_directory(src SRC_LIST)
qt6_add_resources(QML_QRC qml_module_a.qrc qml_module_b.qrc)
set(PROJECT_SOURCES ${SRC_LIST} ${TS_FILES} ${QML_QRC})# 这里如果不加WIN32,会导致编译的可执行文件运行时候会同时弹出一个命令行终端
# 这是Windows的特性,对于其它平台得去掉WIN32
add_executable(${CMAKE_PROJECT_NAME} WIN32 ${PROJECT_SOURCES})qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})# cmake本身有四种编译模式:`Debug`, `Release`, `RelWithDebInfo`, `MinSizeRel`
# 此操作将`Debug`和`RelWithDebInfo`归类于QML的debug,即这两种模式下QML运行会保留debug信息
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)# 链接库到当前项目
# PRIVATE:项目私有内部链接,只有在开发Library对外公开时候才会使用PUBLIC
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Qt6::CoreQt6::QmlQt6::Quick)# 加入新qml文件能自动扫描到并集成到项目
qt_import_qml_plugins(${CMAKE_PROJECT_NAME})

2. Executable VS Library

# 将${SRC_LIST}将编译成可执行文件,如果没有main函数会报错
add_executable(${CMAKE_PROJECT_NAME} ${SRC_LIST})# 将${SRC_LIST}编译为library,library的类型可选择,默认是静态库
add_library(${CMAKE_PROJECT_NAME} [STATIC|SHARED|MODULE] ${SRC_LIST})

3. Every module has its own CMakeList.txt in its folder

3.1 不推荐的做法:

aux_source_directory(. DIR_SRCS1)
aux_source_directory(. DIR_SRCS2)
aux_source_directory(. DIR_SRCS3)add_executable(${CMAKE_PROJECT_NAME} ${DIR_SRCS1} ${DIR_SRCS2} ${DIR_SRCS3})

这种做法会导致项目里即便改了一处代码,也会编译所有代码,导致编译时间较长,不能很好利用增量编译,再说C/C++本身编译就很慢

3.2 推荐的做法

以下以一个开源项目live555改版成为cmake项目作为推荐的项目代码组织结构的案例,虽然最终目标是编译成Library给外部使用,但内部同时也包含了打包成可执行文件的模块(mediaServer):
在这里插入图片描述
其中,BasicUsageEnvironment, groupsock, liveMedia, UsageEnvironment都是live555项目的子模块,mediaServer是集成所有子模块打包成为可执行文件的部分。

作为项目入口,推荐的CMakeList.txt可以如下:

cmake_minimum_required(VERSION 3.15)
project(live555 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# add all sub folders as modules
ADD_SUBDIRECTORY(UsageEnvironment)
ADD_SUBDIRECTORY(BasicUsageEnvironment)
ADD_SUBDIRECTORY(groupsock)
ADD_SUBDIRECTORY(liveMedia)
ADD_SUBDIRECTORY(mediaServer)

模块内部CMakeList.txt推荐如下:

# 这里指定当前模块名,这里推荐用文件名作为模块名
project(BasicUsageEnvironment)# 因为当前模块cpp里使用里其他模块的头文件,因此需要把它们include进来
include_directories(../UsageEnvironment/include)
include_directories(../groupsock/include)# 当前模块的头文件肯定要include进来
include_directories(./include)# 当前模块下的cpp跟CMakeList.txt在同级目录
aux_source_directory(./ SRC_LIST)# 当前只是模块,最终需要把所有的模块合并构建,因此当前需要指定编译对象为STATIC
# ${PROJECT_NAME}的值即为当前模块名,需要注意的是不能用${CMAKE_PROJECT_NAME},因为那是跟目录下CMakeList.txt指定的名字,那是整个项目的名字,即:live555
add_library(${PROJECT_NAME} STATIC ${SRC_LIST})

作为目标是编译为可执行文件的CMakeList.txt如下:

project(mediaServer)include_directories(../UsageEnvironment/include)
include_directories(../groupsock/include)
include_directories(../liveMedia/include)
include_directories(../BasicUsageEnvironment/include)# 当前目录下也有代码
aux_source_directory(. SRC_LIST)# 当前模块是main入口,最终目标是编译出live555的可执行文件,因此不再用add_library()
add_executable(${PROJECT_NAME} ${SRC_LIST})# 链接所有其他模块到当前模块
target_link_libraries(${PROJECT_NAME} PRIVATE liveMedia groupsock BasicUsageEnvironment UsageEnvironment)   

4. 强制以Debug, Release, RelWithDebInfo, MinSizeRel其中一种作为编译方式

方法一:

在工程build目录下执行
cmake … -DCMAKE_BUILD_TYPE=Debug|Release|MinSizeRel|RelWithDebInfo

方法二:

或者在顶级CMakeList.txt里加入:

set(CMAKE_BUILD_TYPE Debug|Release|MinSizeRel|RelWithDebInfo)

5. CMake高频常用变量

变量的引用方式是使用${},在IF中,不需要使用这种方式,直接使用变量名亦可
自定义变量:SET(OBJ_NAME xxxx),调用自定义变量: $ {OBJ_NAME}
设置环境变量: SET(ENV{NAME} value), 需要注意的是这里ENV没有$; 调用环境变量: $ENV{NAME}
CMAKE的常用变量:
在这里插入图片描述

6. 在CMake里区分操作系统

if(CMAKE_SYSTEM_NAME MATCHES "Linux")  // 注意区分大写message(STATUS "Linux platorm!")
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
if(CMAKE_CL_64)message(STATUS "Windows Win64 platform!")else()message(STATUS "Windows Win32 platform!")endif(CMAKE_CL_64)
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")message(STATUS "FreeBSD platform!")
else()message(STATUS "other platform!")
endif(CMAKE_SYSTEM_NAME MATCHES "Linux")

简化版亦可:

if (WIN32)message(STATUS "Now is windows")
elseif (APPLE)message(STATUS "Now is Apple systens.")
elseif (UNIX)message(STATUS "Now is UNIX-like OS's.")
endif ()

7. 在CMake里打印信息

message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)() = 重要消息
STATUS = 非重要消息
WARNING = CMake 警告, 会继续执行
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤
FATAL_ERROR = CMake 错误, 终止所有处理过程

一般用于排错打印日志,或者打印编译过程信息及步骤

Chapter2 使用CMake构建Qt项目

原文链接:https://blog.csdn.net/qq_40181592/article/details/101623231

由于要做新的GUI设计加入更多的功能,在windows上已经安装了QtCreator,不想在Ubuntu下再装一个,于是采用在windows下开发,拿到Linux下编译运行,故使用CMake构建Qt项目。

1.Qt中的qmake

  • qmake可以利用源文件、头文件、qt的ui文件等生成各种不同类型的工程和工程需要的Makefile文件。
  • pro文件,添加各种源文件,还可以设定平台相关的不同源文件,设置各种规则,利用qmake命令生成工程。

QT中编译三步走:

  • qmake -project (用于创建.pro文件,将所有的文件编译成一个与平台无关的工程文件)
  • qmake (读取本身的Qt设置,生成与库一致的相应的Makefile)
  • make (根据生成的Makefile,将文件编译为二进制可执行程序)

2.CMake中的构建

  • CMake中使用的参数代表指CMakeLists.txt文件所在的目录。这个CMakeLists.txt文件控制了整个编译的过程。为了更彻底地理解它,我们用以下这个图来看看整个编译的流程。下面这张图表明用户编写的文件(源代码,头文件,.ui文件,.qrc文件)在编译过程中是如何被Qt的工具进行处理,并整合到整个编译流程中的。因为qmake是用于处理这个流程的,它隐藏了这个流程中的很多细节。

在这里插入图片描述

  • Qt 不是使用的“标准的” C++ 语言,而是对其进行了一定程度的“扩展”。这里我们从Qt新增加的关键字就可以看出来:signals、slots 或者 emit。所以有人会觉得 Qt 的程序编译速度慢,这主要是因为在 Qt 将源代码交给标准 C++ 编译器,如 gcc 之前,需要事先将这些扩展的语法去除掉。完成这一操作的就是 moc。

  • Qt中,如果一个类要使用信号/槽功能,就必须在其中声明Q_OBJECT。只有加入了Q_OBJECT,你才能使用QT中的signal和slot机制。

这时候,就必须在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:

class MyMainWindow : public QWidget
{
Q_OBJECT
…
}
  • moc是QT的预编译器,用来处理代码中的slot,signal,emit,Q_OBJECT等。moc文件是对应的处理代码,也就是Q_OBJECT宏的实现部分

  • 在头文件中如果有使用Q_OBJECT宏的话,则这个文件需要被moc进行处理,.ui文件也必须要由uic处理,.qrc文件需要由rcc程序处理。

3.具体构建过程

  • 下面是我在windows下写的扫雷程序文件(包含.ui .qrc)
    在这里插入图片描述

  • 下面是CMakeList.txt的内容。

#cmake版本
cmake_minimum_required(VERSION 3.5.1)#项目名称
project(Minesweeper)#让cmake自动去寻找Qt5
FIND_PACKAGE(Qt5 COMPONENTS Widgets REQUIRED)#采用C++11标准
set(CMAKE_CXX_STANDARD 11)#添加所有的源文件
SET(Minesweeper_SOURCES dialog.cpp	main.cpp mainwindow.cpp minemap.cppmyitem.cppmyscene.cppsetpro.cpp
)#添加所有的头文件
SET(Minesweeper_HEADERS dialog.hmainwindow.hminemap.hmyitem.hmyscene.hsetpro.h
)#添加所有的.ui文件
SET(Minesweeper_FORMS dialog.uimainwindow.uisetpro.ui
)#添加资源文件
SET(Minesweeper_RESOURCES img.qrc
)
#调用预编译器moc,需要使用 QT5_WRAP_CPP宏
QT5_WRAP_CPP(Minesweeper_HEADERS_MOC ${Minesweeper_HEADERS})
#使用uic处理.ui文件
QT5_WRAP_UI(Minesweeper_FORMS_HEADERS ${Minesweeper_FORMS})
#使用rcc处理.qrc文件
QT5_ADD_RESOURCES(Minesweeper_RESOURCES_RCC ${Minesweeper_RESOURCES})#这些生成的中间文件都会在build目录下,这样的话,编译器则不能定位由uic程序产生的诸如_ui_mainwindow.h等文件。所以,我们需要把build目录添加到包含目录中
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})#生成可执行文件
ADD_EXECUTABLE(Minesweeper ${Minesweeper_SOURCES} ${Minesweeper_HEADERS_MOC} ${Minesweeper_FORMS_HEADERS}${Minesweeper_RESOURCES_RCC} 
)#为target添加需要链接的共享库
TARGET_LINK_LIBRARIES(Minesweeper ${Qt5Widgets_LIBRARIES})
  • 下面是build的结果:

在这里插入图片描述

  • 下面是运行之后的结果:
    在这里插入图片描述

4.结尾

有了上面的构建,也可以完成其他资源的添加,结合新的底层就可以开发出好的界面和功能了。

Chapter3 CMake+QT使用教程

原文链接

Chapter4 解析QT6自动生成的CMake文件

原文链接

1 新建基于CMake的QT6项目

打开qt-creator,新建一个基于CMake的QT项目,编辑器将自动生成以下CMake文件。

cmake_minimum_required(VERSION 3.5)project(HeyPlot VERSION 0.1 LANGUAGES CXX)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets PrintSupport)set(PROJECT_SOURCESmain.cppwidget.cppwidget.hwidget.uiqcustomplot.cppqcustomplot.hheyplot.cppheyplot.h
)INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(HeyPlotMANUAL_FINALIZATION${PROJECT_SOURCES})
else()if(ANDROID)add_library(HeyPlot SHARED${PROJECT_SOURCES})else()add_executable(HeyPlot${PROJECT_SOURCES})endif()
endif()target_link_libraries(HeyPlot PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::PrintSupport)set_target_properties(HeyPlot PROPERTIESMACOSX_BUNDLE_GUI_IDENTIFIER my.example.comMACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)install(TARGETS HeyPlotBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(HeyPlot)
endif()

可以看到QT生成的CMake文件和普通项目还是有所不同的,多了挺多奇怪的函数,这里对QT默认生成的CMake脚本文件做一下解析。

2 解析CMake文件

接下来我们按照先上代码,后上解析的方式对CMake文件进行解析。

2.1 定义CMake以及项目版本号

# 设置所需的最低CMake版本为3.5。
cmake_minimum_required(VERSION 3.5)
# 设置项目名称为"HeyPlot",版本号为0.1,使用的编程语言为C++。
project(HeyPlot VERSION 0.1 LANGUAGES CXX)

首先是一些比较基础的东西。配置文件先设置所需的最低CMake版本为3.5,设置项目名称为"HeyPlot",版本号为0.1,使用的编程语言为C++。

2.2 启用QT资源自动编译选项

# 启用自动UI编译(AUTOUIC)
set(CMAKE_AUTOUIC ON)
# 自动元对象编译(AUTOMOC)
set(CMAKE_AUTOMOC ON)
# 自动资源编译(AUTORCC)
set(CMAKE_AUTORCC ON)

然后,就到了比较奇怪的地方了,配置文件分别设置了CMAKE_AUTOUIC、CMAKE_AUTOMOC、CMAKE_AUTORCC三个参数为ON,这些参数都是QT编译时独有的参数。

2.2.1 CMAKE_AUTOUIC

CMAKE_AUTOUIC参数用于启用自动处理Qt User Interface (UI) 文件的功能。当我们使用Qt进行GUI应用程序开发时,通常会创建UI文件(以.ui扩展名结尾),这些文件描述了用户界面的布局和组件。为了将UI文件与应用程序的代码连接起来,我们需要将它们转换为相应的C++代码。通过将CMAKE_AUTOUIC设置为 ON ,CMake将自动在构建过程中查找并处理项目中的UI文件。 具体而言,当我们启用CMAKE_AUTOUIC后,CMake会在构建过程中自动调用uic工具(UI编译器),将UI文件转换为对应的C++代码,并将生成的C++文件添加到构建系统中,以便编译器将其编译为最终的可执行文件。这样,我们就不需要手动执行uic工具来转换UI文件,CMake会在构建时自动完成这个步骤,简化了项目的配置和构建过程。

2.2.2 CMAKE_AUTOMOC

CMAKE_AUTOMOC参数用于启用自动处理启用自动处理Qt元对象编译(MOC)的功能。Qt的元对象编译器(Meta Object Compiler,MOC)是一个工具,用于处理Qt中的特殊C++扩展,例如信号和槽、动态属性和反射机制。MOC会解析源代码中的这些扩展,并生成额外的C++代码,用于支持这些特性的运行时行为。当我们使用到Qt进行应用程序开发时,一般会使用到信号和槽、Q_OBJECT宏或其他需要MOC处理的Qt特性,我们需要确保这些代码被MOC处理后再进行编译。通过将CMAKE_AUTOMOC设置为ON,我们告诉CMake自动查找需要MOC处理的源文件,并在构建过程中自动调用MOC来生成相应的额外C++代码。具体而言,启用CMAKE_AUTOMOC后,CMake会在构建过程中自动检测源文件中的需要MOC处理的特殊Qt扩展,并为这些源文件生成对应的MOC输出文件。然后,这些生成的MOC输出文件将被添加到构建系统中,以便编译器将其编译为最终的可执行文件。

2.2.3 CMAKE_AUTORCC

CMAKE_AUTORCC参数用于启用自动处理Qt资源文件的功能。Qt资源文件(.qrc)是一种用于将非代码资源(如图像、字体、样式表等)集成到应用程序中的方式。资源文件可以在运行时被动态加载和使用,使应用程序的资源管理更加方便和灵活。通过将CMAKE_AUTORCC设置为ON,我们将告诉CMake自动查找并处理项目中的Qt资源文件。 具体而言,启用CMAKE_AUTORCC后,CMake会在构建过程中自动查找项目中的资源文件(.qrc文件),并调用rcc工具(资源编译器)来将这些资源文件编译为二进制数据。然后,生成的二进制资源数据将被添加到构建系统中,以便在应用程序中使用。这样,我们就无需手动调用rcc工具来处理资源文件,CMake会在构建时自动处理这些步骤,简化了项目的配置和构建过程。当我们在代码中使用Qt的资源管理相关函数(如QResource)时,这些资源数据将被加载和使用。

2.3 定义使用到的C++标准

# 设置C++标准为C++17,并要求编译器支持此标准。
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

这和普通的CMake一致,这里直接跳过。

2.4 查找并加载外部依赖包

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets PrintSupport)

接下来时两个连续的find_package。这是一个很奇怪的构建方式,起初并不明白为什么使用两个连续的find_package来查找和加载外部依赖包,后面发现这两个find_package其实各有用处。

在第一个find_package函数中,CMake尝试查找并加载Qt6,如果找不到再尝试Qt5,同时CMake将要求同时加载Widgets和PrintSupport这两个模块,REQUIRED关键字确保这些模块是必需的,如果找不到任何一个模块,将会导致CMake错误并停止构建过程。在这个过程中,CMake将对QT_VERSION_MAJOR变量进行赋值告诉我们使用到的QT版本是什么。

在第二个find_package函数中,根据第一个find_package函数中找到的QT版本来引用具体的模块。这样连续的两个find_package,确保了之后的构建过程中使用到的模型能够和先前找到的Qt版本匹配。

2.5 导入项目文件

# 定义项目的源文件列表
set(PROJECT_SOURCESmain.cppwidget.cppwidget.hwidget.uiqcustomplot.cppqcustomplot.hheyplot.cppheyplot.h
)
# 包含源文件目录
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})

首先,我们先定义了项目的源文件列表,这个和普通的CMake文件一样没什么好说的。然后我们包含了根目录为头文件搜索路径,在QT默认生成的项目中是没有INCLUDE_DIRECTORIES($ {PROJECT_SOURCE_DIR})这个步骤的,但是我认为这是十分错误的决定。没有INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})步骤意味着CMake编译UI文件后生成的ui_xxxxx.h文件将无法和上述定义的项目源文件联系在一起。导致如果我们希望在qt-creator中对某个空间进行提升操作时无法找到对应的头文件,因此这里我把这句话加上。

2.6 创建可执行文件

# 如果Qt的主要版本号大于等于6,则使用"qt_add_executable"来创建可执行文件。否则,根据目标平台选择创建动态库(Android)或可执行文件。
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(HeyPlotMANUAL_FINALIZATION${PROJECT_SOURCES})
else()if(ANDROID)add_library(HeyPlot SHARED${PROJECT_SOURCES})else()add_executable(HeyPlot${PROJECT_SOURCES})endif()
endif()

接下来时创建可执行文件,这里的qt_add_executable函数其实不是QT6独有的。从Qt 5.14版本开始,QT推荐使用

  • qt_add_executable命令代替add_executable,以更好地集成Qt的构建系统。其主要区别如下:

  • qt_add_executable命令在内部自动处理了与Qt相关的构建步骤,例如自动生成moc文件(元对象编译),处理Qt资源文件(qrc),并将这些步骤与目标可执行文件的构建过程进行了整合。这样,可以更简化和统一Qt项目的构建过程,减少手动配置的需求。

  • qt_add_executable命令在生成目标可执行文件时使用了更好的默认设置,例如自动添加预定义宏和链接Qt的模块。

2.7 链接动态库并设置可执行文件属性

# 将Qt模块链接到目标可执行文件或动态库。
target_link_libraries(HeyPlot PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::PrintSupport)# 设置目标可执行文件的属性,如MacOSX的Bundle标识符、版本号和短版本字符串,以及在Windows下作为可执行文件运行。
set_target_properties(HeyPlot PROPERTIESMACOSX_BUNDLE_GUI_IDENTIFIER my.example.comMACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)

这个部分负责将Qt模块链接到目标可执行文件或动态库,同时也设置了目标可执行文件的属性,如MacOSX的Bundle标识符、版本号和短版本字符串,以及在Windows下作为可执行文件运行。

2.8 安装目标可执行文件到指定的目录

install(TARGETS HeyPlotBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

和普通CMake文件一致,这里略过

2.9 进行最后的可执行文件处理

# 如果使用的是Qt 6,则使用"qt_finalize_executable"进行最后的可执行文件处理。
if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(HeyPlot)
endif()

qt_finalize_executable是一个CMake宏,用于在构建Qt应用程序时进行最后的可执行文件处理。在使用Qt6的情况下,qt_add_executable命令会生成一个中间目标文件,该文件需要经过最后的处理步骤才能成为可执行文件。这个处理步骤包括添加额外的Qt相关链接项、处理资源文件等。 qt_finalize_executable宏负责执行这些最后的处理步骤,将中间目标文件转换为最终的可执行文件。它会添加必要的链接库、处理资源文件,并进行其他必要的操作,以确保可执行文件包含了所有所需的Qt组件和功能。在CMake脚本中,通常会在qt_add_executable之后紧接着调用qt_finalize_executable来完成构建过程。需要注意的是,qt_finalize_executable宏仅在使用Qt 6时才需要调用。对于旧版本的Qt,不需要调用此宏,因为构建过程会自动完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/138279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[游戏中的图形学实时渲染技术] Part1 实时阴影技术

原理篇&#xff1a; 常见的渲染方程如下&#xff1a; &#xfffd;&#xfffd;(&#xfffd;,&#xfffd;&#xfffd;) &#xfffd;&#xfffd;(&#xfffd;,&#xfffd;&#xfffd;) ∫Ω&#xfffd;&#xfffd;(&#xfffd;,&#xfffd;&#xfffd;)&#xf…

Hls学习(一)

1&#xff1a;CPU、DSP、GPU都算软件可编程的硬件 2&#xff1a;dsp在递归方面有所减弱&#xff0c;在递归方面有所增强&#xff0c;比如递归啊等&#xff0c;GPU可以同时处理多个进程&#xff0c;对于大块数据&#xff0c;流处理比较适用 3&#xff1a;为了提高运算量处理更多…

暖手宝+充电宝设计方案 可实现快速升温和充电 低成本充电电流可选

充电暖手宝因为它的便携性&#xff0c;既能供暖又能当充电宝使用而备受人们喜爱。是冬天暖手供暖的必备神器。 目前&#xff0c;市场常见的暖手宝大致有三个类型&#xff0c;分别是加热水的热水袋、通过化学反应放热的铁粉袋子和锂电供电的智能暖手宝。与常见的暖手宝不同&…

巨好用又实用的18款3dMax插件!

3dMax是一款功能强大的 3D 软件&#xff0c;具有建模、动画、粒子动力学等许多强大功能。但并不是每个人都能有效地利用max的每一个功能&#xff0c;例如&#xff0c;很多人发现3dmax粒子流太难使用&#xff0c;3ds max蒙皮工具也是如此。 这让我们一些专业的开发公司或个人和…

Python学习笔记--自定义类型的枚举

三、自定义类型的枚举 但有些时候我们需要控制枚举的类型&#xff0c;那么我们可以 Enum 派生出自定义类来满足这种需要。通过修改上面的例子&#xff1a; #!/usr/bin/env python3 # -*- coding: UTF-8 -*- from enum import Enum, uniqueEnum(Month, (Jan, Feb, Mar, Apr, M…

配置cuda和cudnn出现 libcudnn.so.8 is not a symbolic link问题

cuda版本为11.2 问题如图所示&#xff1a; 解决办法&#xff1a; sudo ln -sf /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcudnn_adv_train.so.8.1.1 /usr/local/cuda-11.2/targets/x86_64-linux/lib/libcudnn_adv_train.so.8 sudo ln -sf /usr/local/cuda-11.2/targ…

时间序列预测(1) — 时间序列预测研究综述

目录 1 什么是时间序列预测? 2 时间序列预测的应用场景与分类 3 时间序列数据的特性 4 时序预测评价指标 5 基于深度学习的时间序列预测方法 5.1 卷积神经网络 5.2 循环神经网络 5.3 Transformer类模型 1 什么是时间序列预测? 时间序列&#xff1a;指对某种事物发展…

计算机网络期末复习-Part3

1、rdt1.0&#xff0c;rdt2.0&#xff0c;rdt3.0的底层信道模型 RDT 1.0: 完全可靠的底层信道&#xff0c;没有比特差错&#xff0c;也没有分组丢失。 RDT 2.0: 具有比特差错的底层信道&#xff0c;有比特差错&#xff0c;但没有分组丢失。 RDT 3.0: 具有差错和丢包的底层信道…

Python爬虫——入门爬取网页数据

目录 前言 一、Python爬虫入门 二、使用代理IP 三、反爬虫技术 1. 间隔时间 2. 随机UA 3. 使用Cookies 四、总结 前言 本文介绍Python爬虫入门教程&#xff0c;主要讲解如何使用Python爬取网页数据&#xff0c;包括基本的网页数据抓取、使用代理IP和反爬虫技术。 一、…

RedisDesktopManager连接不上redis的解决方法

RedisDesktopManager连接不上redis的解决方法 RedisDesktopManager是一款连接redis数据库的客户端。 当连接不上redis的时候&#xff0c;解决方案&#xff1a; 第一步&#xff1a;在自己的本机外面试下&#xff0c;能不能连接上虚拟机 打开cmd,使用ping 虚拟机ip地址。如果…

ElasticSearch7.x - HTTP 操作 - 索引操作

创建索引 对比关系型数据库,创建索引就等同于创建数据库 在 Postman 中,向 ES 服务器发 PUT 请求 :http://192.168.254.101:9200/shopping 说明 {"acknowledged"【响应结果】: true, # true 操作成功"shards_acknowledged"【分片结果】: true, # 分片操…

Apache RocketMQ - 概述

2022年&#xff0c;RocketMQ 5.0的正式版发布&#xff0c;相比于4.0版本而言&#xff0c;架构走向云原生化&#xff0c;并且覆盖了更多的业务场景。 如何从互联网时代演进到云时代&#xff1f; 1. 消息队列演进史 操作系统、数据库、中间件是基础软件的三驾马车&#xff0c;…

《QT从基础到进阶·二十》QThreadPool线程池的使用

什么情况下比较适合用线程池&#xff1f; 比如我有上百个任务要同时处理&#xff0c;难道开上百个线程&#xff1f;NO&#xff01;&#xff01;&#xff01; 有了线程池的加持&#xff0c;自动给任务分配线程处理&#xff0c; 多线程不再是真爱~ 线程池创建&#xff1a; 1、自…

常见排序算法之插入排序类

插入排序&#xff0c;是一种简单直观的排序算法&#xff0c;工作原理是将一个记录插入到已经排好序的有序表中&#xff0c;从而形成一个新的、记录数增1的有序表。在实现过程中&#xff0c;它使用双层循环&#xff0c;外层循环对除了第一个元素之外的所有元素&#xff0c;内层循…

7-Zip的介绍和【阿里云盘】的使用

7zip从入门到入坑 前言一、7-zip的介绍和安装1、基本介绍1&#xff09;7-Zip 主要特征2&#xff09;支持格式3&#xff09;基础功能4&#xff09;安装环境需求 2、基本操作&#xff08;1&#xff09;简便的界面&#xff08;2&#xff09;发生的问题 二、阿里云盘的使用1、“exe…

GZ038 物联网应用开发赛题第2套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 (第2套卷) 工位号:______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具,操作安全规范; 2、竞赛过程中如有异议,可向现场考评人员反映,不得扰乱赛场秩序; 3、遵守赛场纪律,尊重考评人员,…

京东数据分析:2023年9月京东笔记本电脑行业品牌销售排行榜

鲸参谋监测的京东平台9月份笔记本电脑市场销售数据已出炉&#xff01; 9月份&#xff0c;笔记本电脑市场整体销售下滑。鲸参谋数据显示&#xff0c;今年9月份&#xff0c;京东平台上笔记本电脑的销量将近59万&#xff0c;环比下滑约21%&#xff0c;同比下滑约40%&#xff1b;销…

vivo 数据库降本实践:探索成本效益最优的数据库解决方案

vivo 自 2022 年开始调研、测试 OceanBase 至今&#xff0c;现已上线 17 个业务系统&#xff0c;涵盖日志类、分析类、交易类业务&#xff0c;实现了总资源节省 80%&#xff0c;开发、运维工作大幅简化。vivo 体系与流程 IT 部门数据库高级工程师廖光明在本文中&#xff0c;详细…

SQL 算数函数

AVG() 求数值列的平均值。 具体计算过程&#xff1a;其通过对表中行数计数并计算特定数值列的列值之和&#xff0c;求得该列的平均值。 语法&#xff1a; SELECT AVG(column_name) FROM table_name; 当参数 column_name 列中的数据均为空时&#xff0c;结果会返回 NULL。 …

Hadoop学习总结(使用Java API操作HDFS)

使用Java API操作HDFS&#xff0c;是在安装和配置Maven、IDEA中配置Maven成功情况下进行的&#xff0c;如果Maven安装和配置不完全将不能进行Java API操作HDFS。 由于Hadoop是使用Java语言编写的&#xff0c;因此可以使用Java API操作Hadoop文件系统。使用HDFS提供的Java API构…