CMake教程——QT项目使用CMake

2023-05-16

文章目录

  • 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高频常用变量
  • 7. 在CMake里打印信息

转自 链接: https://www.jianshu.com/p/622d2ec351b5

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):

├── CMakeLists.txt
├── BasicUsageEnvironment
│ └── CMakeLists.txt
│ └── BasicHashTable.cpp
│ └── xxx.cpp
│ └── include
│ └── BasicHashTable.hh
│ └── xxx.hh
├── groupsock
│ └── CMakeLists.txt
│ └── GroupEId.cpp
│ └── xxx.cpp
│ └── include
│ └── GroupEId.hh
│ └── xxx.hh
├── liveMedia
│ └── CMakeLists.txt
│ └── AC3AudioRTPSink.cpp
│ └── xxx.cpp
│ └── include
│ └── GroupEId.hh
│ └── xxx.hh
├── mediaServer
│ └── CMakeLists.txt
│ └── DynamicRTSPServer.cpp
│ └── xxx.cpp
└── UsageEnvironment
└── CMakeLists.txt
└── HashTable.cpp
└── xxx.cpp
└── include
└── Boolean.hh
└── xxx.hh

其中,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的常用变量:

变量意义
CMAKE_SOURCE_DIR工程项目跟目录
CMAKE_CURRENT_SOURCE_DIRCMakeList.txt所在的目录
CMAKE_MODULE_PATH如果工程复杂,可能需要编写一些cmake模块,这里通过SET指定这个变量
LIBRARY_OUTPUT_DIR库最终存放目录
BINARY_OUTPUT_DIR可执行的最终存放目录
PROJECT_NAME当前CMakeList.txt里设置的project_name
CMAKE_PROJECT_NAME项目跟目录配置的project_name
# 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 错误, 终止所有处理过程

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake教程——QT项目使用CMake 的相关文章

  • 如果构建是源代码外的,CMake 无法找出标头依赖项?

    我一直在使用 CMake 来管理一个单独的小型 c 项目 基于 Unix Makefile 并决定将其转换为更有组织的源代码外构建 但是 当它超出源时 通过执行cmake 在 build 中 我的标头不再是其源文件的依赖项 如果我只是从顶层
  • 无法安装 R 包:CMake 错误

    我正在尝试安装factoextra 但我在 CMake 部分遇到了困难 特别是出现如下错误 CMake Error The source directory tmp does not exist 当我尝试安装其依赖项时也是如此 nloptr
  • CMake:不支持的 GNU 版本 - 不支持高于 8 的 gcc 版本

    在降级我的 GCC 之前 我想知道是否有一种方法可以确定我的机器中的哪些程序 框架或依赖项将被破坏 以及是否有更好的方法来安装 openpose 例如 更改 CMake 中的某些内容 有没有办法可以解决这个问题 而无需更改我的系统 GCC
  • 使用 cmake 和 Visual Studio 的一个解决方案中的多个项目

    我有一个 Visual Studio 2010 解决方案 其中包含 5 个项目 两个库和三个应用程序 依赖于库 我现在想将构建系统迁移到 CMake 也能够在 Linux 下编译 我已经了解了如何为一个项目编写 CMakeLists txt
  • CMake 64 位和 SFML 64 位

    我正在尝试使用适用于 Windows 的 CMake 64 位和 SFML 2 5 1 64 位构建 C 项目 当我在项目上运行 cmake 时 我收到一条错误消息 我能让它工作的唯一方法是改变CMAKE PREFIX PATH指向 SFM
  • 编辑 CMakeLists.txt 以使用 -fPIC 进行编译

    我正在尝试为名为 libnifalcon 的 NOVINT Falcon 安装驱动程序 我使用 cmake 创建 make 文件 但是当我运行 make 时出现错误 Linking CXX shared library lib libnif
  • 在cmake中检测项目语言

    我想检测当前的项目语言 例如 如果我有这样的东西 cmake minimum required VERSION 3 0 project foo VERSION 1 0 LANGUAGES CXX 我需要这样的东西 if project la
  • 来自库的 CMake link_directories

    我正在尝试使用 CMake 和 Xcode 从另一个库链接到一个库 这对任何图书馆来说都是一个问题 但为了让事情更容易传达 让我们使用zlib举个例子 这似乎适用于可执行文件 如下所示 LINK DIRECTORIES LIB DIR zl
  • 如何将脚本的依赖项添加到 CMake 中的目标?

    链接我的程序后 我需要对其执行一些后处理 我添加了一个add custom command TARGET 效果很好 但是 这个额外的自定义命令运行一个脚本 未生成 它已签入代码库 并且我希望如果该脚本发生更改 目标将被视为过时 以便正确重建
  • cmake 找不到 boost 库,因为它查找错误的文件名

    我根据文档在 Windows 8 1 机器上构建了 boost 1 56 库 作为共享库和静态库 他们全部出现在BOOST ROOT stage lib目录 文件名格式如下 boost thread vc120 mt 1 56 dll bo
  • 使用 target_link_libraries 以绝对路径作为库路径进行平台库名称扩展?

    在 CMake 中使用 target link libraries 仅使用库名称 例如 target link library myProject SomeLibrary 将根据平台将 SomeLibrary 扩展为 SomeLibrary
  • CMake 错误:CMake 无法找到与“MinGW Makefiles”对应的构建程序

    我正在尝试使用 cmake 为 c 构建 Box2D 库 当我运行 cmake gui 时出现错误 CMake Error CMake was unable to find a build program corresponding to
  • MySQL C++ 连接器未解决的依赖关系(VS 2015)

    我正在尝试在 Windows Visual Studio 2015 上编译 MySQL Connector C 我根据以下内容使用CMake生成了项目文件官方说明 https dev mysql com doc connector cpp
  • (如何)我可以抑制未找到包配置文件的警告吗?

    我正在尝试创建一个CMakeLists txt尝试查找的文件Qt5 如果失败 则尝试回退到Qt4安装 该脚本到目前为止有效 但如果出现以下情况我总会收到警告Qt5未安装 注意FindQt5 cmake是由提供Qt5并且仅当以下情况时才可用Q
  • CMake 和 Visual Studio:如何获得快速、安静的命令行构建?

    我有一个 cmake 项目 它成功地完成了我想要的一切 但我有大约 100 个文件 当我只需要重新编译一个文件时 我厌倦了每次看到生成的巨大输出 每个文件 30 行 明确地说 我正在编译cmake build 得到这个结果 我需要传递给编译
  • 如何从 CMake 构建目标仅生成目标文件 (*.o)?

    我正在尝试使用 CMake 构建一个对象文件 但我似乎无法让 CMake 构建除完整可执行文件之外的其他内容 我基本上是在寻找以下编译的结果 结果将加载到 VxWorks 目标上并然后链接 CC CFLAGS INC DIRS c src
  • CMake:用于Android交叉编译的FIND_PACKAGE(Threads)

    我正在使用 Android NDK 和 Cmake 生成项目的共享库 我正在将现有项目从 Ubuntu 移植到 Android 现在我需要移植一些可执行文件 我成功编译了所有需要的可执行文件Threads图书馆 在CMakeList txt
  • CMake:如何最好地构建多个(可选)子项目?

    想象一个包含多个组件的整体项目 basic io web app a app b app c 现在 假设 web 依赖于 io 而 io 又依赖于 basic 所有这些东西都在一个存储库中 并且有一个 CMakeLists txt 将它们构
  • CLion - 命令行程序参数

    当我分配给 运行 调试配置 程序参数 之类的 aaa bbb 然后打印它时 任何人都可以告诉我 JetBrains CLion 有什么问题吗 printf s n argv 1 我刚刚得到 aaa 而它必须是 aaa bbb 因为它们用双引
  • Haskell 项目可以使用 cmake 吗?

    我正在计划一个用 Haskell 编写的项目 也许也有一些部分是用 C 编写的 对于构建系统 我决定不选择 Haskell 程序 cabal 的常见选择 主要是因为我想了解其他语言的构建程序是如何工作的 我听说过 CMake 我认为这是一个

随机推荐

  • c++:DFS与BFS详解

    DFS xff08 深度优先搜索 xff09 xff1a 从某个状态开始 xff0c 不断转移状态到无法转移为止 xff0c 然后退回到前一步 xff0c 继续转移到其他状态 xff0c 不断重复 xff0c 直至找到最终的解 总是从最开始
  • 一文掌握OpenGL的shader内置函数

    OpenGL ES有大量的GLSL内置函数 xff0c 包括 xff1a 三角函数 指数函数 通用函数 浮点函数 几何函数 矩阵函数 矢量关系函数 纹理函数 原子函数 图像函数 插值函数等 目录 一 三角函数 1 radians degre
  • 安全可靠的SRT实时传输协议

    Secure Reliable Transport SRT 是安全 可靠 低延时的多媒体实时传输协议 SRT协议使用AES进行数据加密 xff0c 运用FEC进行前向纠错 xff0c 并且有流量控制 拥塞控制 类似于QUIC协议 xff0c
  • android端使用openCV实现车牌检测

    现在 xff0c 汽车的踪影无处不在 xff0c 公路上疾驰 xff0c 大街边临停 xff0c 小区中停靠 xff0c 车库里停泊 管理监控如此庞大数量的汽车是个头疼的问题 精明的人们把目光放在车牌上 xff0c 因为车牌是汽车的 身份证
  • android端使用openCV与深度学习实现车牌识别

    车牌识别的应用场景随处可见 xff1a 高速公路上超速抓拍 小区门口关卡 车库入口关卡 xff0c 甚至出现在车载设备上 它的工作原理大致这样 xff1a 使用摄像头充当 眼睛 xff0c 使用openCV与深度学习充当 大脑 实时车牌识别
  • FFmpeg音频处理——音频混合、拼接、剪切、转码

    接触FFmpeg有一段时间了 xff0c 它是音视频开发的开源库 xff0c 几乎其他所有播放器 直播平台都基于FFmpeg进行二次开发 本篇文章来总结下采用FFmpeg进行音频处理 xff1a 音频混合 音频剪切 音频拼接与音频转码 采用
  • Android三种方式截取任意界面屏幕

    一 使用MediaProjectionManager Android5 0之后 xff0c 开放截取屏幕的API xff0c 也就是利用MediaProjectionManager创建VirtualDisplay xff0c 传入与Imag
  • ijkplayer基于rtsp直播延时的深度优化

    现在ijkPlayer是许多播放器 直播平台的首选 xff0c 相信很多开发者都接触过ijkPlayer xff0c 无论是Android工程师还是iOS工程师 我曾经在Github上的ijkPlayer开源项目上提问过 xff1a 视频流
  • C++ 程序编译过程

    前言 C语言的编译链接过程要把我们编写的一个c程序 xff08 源代码 xff09 转换成可以在硬件上运行的程序 xff08 可执行代码 xff09 xff0c 需要进行编译和链接 编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程
  • 自旋锁实现机理 spin_lock

    自旋锁的概念 自旋锁 xff08 spin lock xff09 是一种典型的对临界资源进行互斥访问的手段 xff0c 它是基于系统原子操作为基础 xff0c 自旋锁最多只能被一个可执行线程持有 xff0c 如果一个执行线程试图获得一个被已
  • 数据结构:图之DFS与BFS的复杂度分析

    BFS的复杂度分析 BFS是一种借用队列来存储的过程 xff0c 分层查找 xff0c 优先考虑距离出发点近的点 无论是在邻接表还是邻接矩阵中存储 xff0c 都需要借助一个辅助队列 xff0c v个顶点均需入队 xff0c 最坏的情况下
  • python中的os.path.dirname(__file__)的使用

    os path dirname file 返回脚本的路径 xff0c 但是需要注意一下几点 1 必须是实际存在的 py文件 xff0c 如果在命令行执行 xff0c 则会引发异常NameError name 39 file 39 is no
  • 北斗模块学习之初

    BD定义 xff1a 北斗卫星导航系统 xff08 BeiDou xff08 COMPASS xff09 NavigationSatellite System xff09 是中国正在实施的自主发展 独立运行的全球卫星导航系统 系统建设目标是
  • 关于Boost库和STL标准模板库

    一 关于STL 首先 xff0c 关于stl xff0c 最近也看了不少关于stl的博客 往大概的讲 xff0c stl即一种标准的模板库 xff0c 同时 xff0c 它也是静态库 xff0c 它存在的目的即是为了实现代码的服用性 xff
  • c语言char* 转char[]方法

    vector lt char gt splite by delim char host name char a 1000 strcpy a host name char p 61 strtok a split vector lt char
  • STL常用容器对比

    STL的常用容器大致有以下8个 xff1a 1 vector vector是一种动态数组 xff0c 在内存中具有连续的存储空间 xff0c 支持快速随机访问 由于具有连续的存储空间 xff0c 所以在插入和删除操作方面 xff0c 效率比
  • C 语言 stm32 无符号8位转换为int类型 uchar 转换为 int

    我做的是一个无线鼠标 xff0c stm32用nRF24L01无线传输模块发送数据时 xff0c 是传输无符号8位 uchar 三个数据是角度值 xff0c 有正负 直接使用无符号数据的话负数会出错 xff0c 在接收端要把数据恢复为整数
  • 常见IMU的性能比较

    型号gyr零偏稳定性gyr量程acc零偏稳定性acc量程HZ价格其他说明 EG320N xff08 epson xff09 http www canalgeomatics com wp content uploads 2020 06 oem
  • strcat函数用法的一点看法

    最近在刷题时碰到了strcat这个函数 xff0c 一开始没怎么理解它的用法 xff0c 出了错 xff0c 现在写点自己的理解吧 首先来看两个小程序 代码一 xff1a include lt iostream gt using names
  • CMake教程——QT项目使用CMake

    文章目录 1 Basic Cmake Based Project2 Executable VS Library3 Every module has its own CMakeList txt in its folder3 1 不推荐的做法