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::Core
    Qt6::Qml
    Qt6::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.cpp
	myitem.cpp
	myscene.cpp
	setpro.cpp
)

#添加所有的头文件
SET(Minesweeper_HEADERS 
	dialog.h
	mainwindow.h
	minemap.h
	myitem.h
	myscene.h
	setpro.h
)

#添加所有的.ui文件
SET(Minesweeper_FORMS 
	dialog.ui
	mainwindow.ui
	setpro.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_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
        qcustomplot.cpp
        qcustomplot.h
        heyplot.cpp
        heyplot.h
)
 
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
 
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(HeyPlot
        MANUAL_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 PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)
 
install(TARGETS HeyPlot
    BUNDLE 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_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
        qcustomplot.cpp
        qcustomplot.h
        heyplot.cpp
        heyplot.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(HeyPlot
        MANUAL_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 PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

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

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

install(TARGETS HeyPlot
    BUNDLE 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.mfbz.cn/a/132330.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mac安装与配置eclipse

目录 一、安装Java&#xff1a;Mac环境配置&#xff08;Java&#xff09;----使用bash_profile进行配置&#xff08;附下载地址&#xff09; 二、下载和安装eclipse 1、进入eclipse的官网 (1)、点击“Download Packages ”​编辑 (2)、找到macOS选择符合自己电脑的框架选项…

人工智能基础_机器学习023_理解套索回归_认识L1正则---人工智能工作笔记0063

然后上一节我们说了L1,L2正则是为了提高,模型的泛化能力, 提高泛化能力,实际上就是把模型的公式的w,权重值,变小对吧. 然后我们这里首先看第一个L1正则,是怎么做到把w权重变小的 可以看到最上面是线性回归的损失函数,然后 L1可以看到,这个正则,就是在损失函数的基础上给损失…

轻松按需缩放图片像素——批量处理图片,满足不同需求!

在图片使用过程中&#xff0c;我们经常需要按照不同的要求调整图片的像素大小。如果一张一张地手动调整&#xff0c;不仅耗时而且容易出错。这款软件可以帮助您轻松实现批量处理图片&#xff0c;按需缩放图片像素&#xff0c;让您的图片管理更加高效、便捷&#xff01; 第一步…

Vuex持久化插件

Vuex数据默认是存储在内存中的&#xff0c;当然我们也可以将它存储在Local Storage&#xff0c;也可以指定某些数据存储在Local Storage 这样我们就用到了Vuex持久化插件vuex-persistedstate 安装vuex-persistedstate插件 npm install vuex-persistedstate --save 案列&#x…

MPSO-WPA

MPSO-WPA算法 DCAP means ’ discretized Cauchy’s argument principle’ 辅助信息 作者未提供代码

数据结构线性表——带头双向循环链表

前言&#xff1a;小伙伴们好久不见啦&#xff0c;上篇文章我们一起学习了数据结构线性表其一的单链表&#xff0c;了解了单链表的不少好处&#xff0c;但是不可能有完美的数据结构&#xff0c;就算是单链表&#xff0c;也会有很多缺点。 那么今天这篇文章&#xff0c;我们就来…

node插件MongoDB(五)—— 库mongoose 的模块化(五)

文章目录 一、使用mongoose 模块化的原因二、准备工作2. 启动mongo.exe 和mongod.exe 两个程序连接数据库 三、基本模块的拆分1、基本逻辑2、代码3、代码图示说明 四、在index.js 中进一步的拆分1.拆分原因2.新建model文件夹存储文档的结构对象3.代码4.代码实际演示和注意点 一…

用volta管理不同项目node版本

1 什么是volta volta是一个node.js的版本管理工具&#xff0c;你的电脑上安装了很多个node版本&#xff0c;volta可以让你在不同的项目中使用不同版本的node.js,并且可以切换node.js版本 Volta会自动将安装的Node.js版本与该项目绑定&#xff0c;使得您在该项目中执行 node、np…

Linux centos系统中添加磁盘

为了学习与训练文件系统或磁盘的分区、格式化和挂载/卸载&#xff0c;我们需要为虚拟机添加磁盘。根据需要&#xff0c;可以添加多块不同大小的磁盘。具体操作讨论如下&#xff0c;供参考。 一、添加 1.开机前 有两个地方&#xff0c;可选择打开添加硬盘对话框 (1)双击左侧…

2024“点点点”测试员如何上岸测试开发岗?附完整学习路线

有很多人员会不断问自己&#xff0c;自己到底要不要学测试&#xff0c;或者要不要坚持做测试&#xff0c;测试的职业发展到底怎么样&#xff1f;如果你还在迷茫&#xff0c;在到处找各种大牛问类似的问题&#xff0c;我希望这篇文章&#xff0c;你看完能够结束你的这个烦恼&…

iPad系列将在2024年全面更新!

今年还会有新iPad发布吗&#xff1f;答案是否定的。因为早在前几天的季度电话会议上&#xff0c;苹果公司CEO蒂姆・库克就已经宣布&#xff0c;今年不会推出任何新的iPad产品。 这也意味着&#xff0c;今年将是苹果公司自2010年推出首款iPad设备以来&#xff0c;第一次没有发布…

模块化之CJS, AMD, UMD 和 ESM

[[toc]] 模块化优点 防止命名冲突代码复用高维护性CJS, AMD, UMD 和 ESM 历史 ES6之前,JS一直没有自己的模块体系后来社区出现了CommonJS和AMD,CommonJS 主要用于服务器(Node)AMD 主要用于浏览器ES6引入了ESM到此,JS终于有了自己的模块体系,基本上可以完全取代CJS和AMD…

Java基础-面向对象进阶-多态, 包, final, 权限修饰符,代码块

Java基础-面向对象进阶-多态, 包, final, 权限修饰符,代码块 多态多态的概述多态中调用成员的特点多态的优势和弊端多态练习 包final权限修饰符代码块来源Gitee地址 多态 多态的概述 多态: 对象的多种形态多态的前提 有继承/实现关系有父类引用指向子类对象有方法的重写 多态…

ScrollView 与 SliverPadding 的关系

基本页面布局 Scaffold 中有个 ListView&#xff0c;ListView 中有 100 个高 50 的 Container 用作辅助观看&#xff0c;ListView 中第三个元素是一个 GridView&#xff0c;GridView 的滑动效果被禁止。 class GiveView extends GetView<GiveController> {const GiveVi…

【Unity之UI编程】编写一个面板交互界面需要注意的细节

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【Java】基于SpringBoot创建Web页面并热更新

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍基于SpringBoot创建Web页面并热更新。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…

低价寄快递寄件微信小程序 实际商用版,对接了低价快递渠道,运营平台赚取差价,支持市面上全部主流快递

盈利模式 快递代下CPS就是用户通过线上的渠道&#xff08;快递小程序&#xff09;&#xff0c;线上下单寄快递来赚取差价&#xff0c;例如你的成本价是5元&#xff0c;你在后台比例设置里面设置 首重利润是1元&#xff0c;续重0.5元&#xff0c;用户下1kg的单页面显示的就是6元…

前端和空字符串、零比较时请务必使用===

在前端开发中遇到一个问题&#xff0c;以下两条语句的结果都是true。 console.log(0 ""); console.log(false ""); 这就导致了editingId为0的时候&#xff0c;if分支并没有执行&#xff0c;而我的本意是当editingId不是空也不是空字符串的时候执行分支…

SpringBoot 缓存之 @Cacheable 详细介绍

一、简介 1、缓存介绍 Spring 从 3.1 开始就引入了对 Cache 的支持。定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术。并支持使用 JCache&#xff08;JSR-107&#xff09;注解简化我们的开发。&#xfeff; 其…

Unity中Shader的间接光的产生Meta Pass

文章目录 前言Unity中Shader的间接光的产生Meta Pass&#xff0c;这也是属于全局光照 GI 的内容。主要实现像现实生活中&#xff0c;光线照到有颜色的物体后&#xff0c;该物体有反射出该颜色的光的效果。 一、我们先使用Unity自带的Shader看看间接光效果1、先按照如下设置搭建…
最新文章