C/C++生态工具链——编译构建工具CMake/CMakeList初探

一,CMake简介

        CMake的全称是Cross-platform Make。我第一次参与Linux C++开发时使用的工具是Make,而后开始切换到CMake,一开始以为CMake是和C语言有关,原来开头的C表示它可以跨平台。

CMake的使用场景:

        跨平台编译运行,交叉编译。一般基于CMakeLists.txt文件定义的编译构建规则来生成目标文件和目标库。

CMakeLists.txt样例如下: 

#cmake最低版本需求
cmake_minimum_required(VERSION 3.13)
#项目名称
project(cmake_study)
#相关设置用set函数
set(CMAKE_CXX_STANDARD 11)
#生成的可执行文件的名称
add_executable(cmake_study src/main.cc)

在Linux环境使用CMake的构建和编译流程如下:

        step1. 编写CMake的配置文件——CMakeLists.txt。

        step2. 执行命令 cmake PATH 或者 ccmake PATH 构建生成 Makefile配置文件。PATH为CMakeLists.txt所在的目录。

        step3. 在Makefile文件所在的路径,执行make命令进行编译。

一般使用过程如下:

$ mkdir build
$ cd build/
$ cmake ..
$ make

        * 为了不让编译产生的中间文件污染项目的文件结构,专门创建build文件夹进行编译构建。

二,CMake与Make的区别

        CMake并不直接参与软件的构建和编译,而是生成用于构建的Makefile等配置文件。因此在完成同样的编译任务时,CMake比Make的用法更容易,且屏蔽了Makefile中的很多复杂的语法点。

三,CMakeLists.txt语法

        cmake的语法由函数名和参数构成,参数区分大小写,函数名不区分大小写(这个依据个人喜好,笔者习惯用小写,大写有点费眼睛+_+)。


(1) cmake_minimum_required

含义:设置项目所需的最低cmake版本以及更新策略

语法:

cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])

使用样例:

cmake_minimum_required(VERSION 2.8.0)


(2) project

含义:设置项目的名称、版本、编程语言等信息

语法:

project(<PROJECT-NAME>

           [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]

           [LANGUAGES <language-name>...])

使用样例:

project(Demo)


(3) set

含义:设置普通变量、缓存或环境变量的值

语法:

set(<variable> <value>... [PARENT_SCOPE])

set(<variable> <value>... CACHE <type> <docstring> [FORCE])

set(ENV{<variable>} [<value>])

使用样例:

set(CMAKE_CXX_COMPILER D:/MinGW/bin/g++)


(4) file

含义:定义对文件系统的文件和路径的操作,可以结合Linux指令对文件的操作去理解。

语法:

file(READ <filename> <out-var> [...])

file({WRITE | APPEND} <filename> <content>...)

file(MAKE_DIRECTORY [<dir>...])

使用样例:

file(WRITE test.txt "Test Write\n" )


(5) option

含义:提供用户可以选择的布尔选项。

语法:

option(<variable> "<help_text>" [value])

使用样例:

option(TEST_DEBUG "option for debug" OFF)


(6) if…else[if]…endif

含义:这个不用详细介绍了,用法同编程语言中的控制语句

语法:

if/else([<condition>])

使用样例:

if(WIN32)

  message(STATUS "in Windows System")

elseif(UNIX)

  message(STATUS "in Unix System")

endif()


(7) include_directories

含义:将指定目录添加到编译器的头文件搜索范围

语法:

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

使用样例:

include_directories(../src/com/include)


(8) link_directories

含义:添加需要链接的共享库(动态链接库)文件路径,相当于g++命令的-L参数,也相当于Linux环境变量设置LD_LIBRARY_PATH

语法:

link_directories([AFTER|BEFORE] directory1 [directory2 ...])

使用样例:

link_directories(${SOURCE_DIR}/lib)


(9) aux_source_directory

含义:查找指定目录中的所有源文件,将结果存进指定变量名

语法:

aux_source_directory(<dir> <variable>)

使用样例:

aux_source_directory(../src DIR_SRCS)


(10) add_custom_command

含义:添加自定义构建规则

语法:

add_custom_command(OUTPUT output1 [output2 ...]

                                    COMMAND command1 [ARGS] [args1...]

                                   [COMMAND command2 [ARGS] [args2...] ...])

使用样例:  

add_custom_command(

                  TARGET  ${_target}

                  POST_BUILD

                  COMMAND echo ${_command}

                  VERBATIM)


(11) add_compile_options

含义:设置编译选项

语法:

add_compile_options(<option> ...)

使用样例:

add_compile_options(-std=c++11)


(12) add_subdirectory

含义:将子目录添加到构建范围

语法:

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

使用样例:

add_subdirectory(utils)


(13) add_executable

含义:使用指定的源文件来生成目标可执行文件

语法:

add_executable(<name> [WIN32] [MACOSX_BUNDLE]

               [EXCLUDE_FROM_ALL]

               [source1] [source2 ...])

使用样例:

add_executable(main main.cpp)


(14) add_dependencies

含义:给编译目标添加依赖的target

语法:

add_dependencies(<target> [<target-dependency>]...)

使用样例:

add_dependencies(log com_log)


(15) add_library

含义:添加一个库到工程中,指定这个库的源文件

语法:

add_library(<name> [STATIC | SHARED | MODULE]

            [EXCLUDE_FROM_ALL]

            [<source>...])

使用样例:

add_library(opencv_core SHARED IMPORTED)


(16) configure_file

含义:将文件复制到另一个位置并修改其内容。

语法:

configure_file(<input> <output>

               [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |

                FILE_PERMISSIONS <permissions>...])

使用样例:

configure_file(CMakeLists.txt.in download/CMakeLists.txt)


(17) find_package

含义:查找依赖的包名

语法:

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]

             [REQUIRED] [[COMPONENTS] [components...]])

使用样例:

find_package(OpenSSL REQUIRED)


(18) find_library

含义:查找依赖的库

语法:

find_library (<VAR> name1 [path1 path2 ...])

使用样例:

find_library(LOG_LIB log)


(19) find_path

含义:搜索包含指定文件名的路径

语法:

find_path (<VAR> name1 [path1 path2 ...])

使用样例:

find_path(_ZeroMQ_ROOT NAMES include/zmq.h)


(20) target_link_libraries

含义:将之前打包的库链接到生成的目标上

语法:

target_link_libraries(<target> ... <item>... ...)

使用样例:

target_link_libraries(${THREAD_LIB_NAME} pthread)


(21) target_include_directories

含义:指定编译生成目标时,需要使用的目录

语法:

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]

  <INTERFACE|PUBLIC|PRIVATE> [items1...]

  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

使用样例:

target_include_directories(hello_library 

                                          PUBLIC 

                                          ${PROJECT_SOURCE_DIR}/include)


(22) target_sources

含义:指定构建目标或其依赖项时要使用的源文件

语法:

target_sources(<target>

  <INTERFACE|PUBLIC|PRIVATE> [items1...]

  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

使用样例:

target_sources(main  PRIVATE main.cpp)


(23) target_compile_definitions

含义:在编译目标文件时,指定要用到的编译选项

语法:

target_compile_definitions(<target>

  <INTERFACE|PUBLIC|PRIVATE> [items1...]

  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

使用样例:

target_compile_definitions(${PROJECTNAME} PUBLIC ARM7)


(24) message

含义:编译过程添加日志消息

语法:

message([<mode>] "message text" ...)

使用样例:

message(STATUS "sources into a library? ${LIBRARY}")


四,CMake常用的环境变量


--CMAKE_C_COMPILER

指定C编译器


--CMAKE_CXX_COMPILER

指定C++编译器


--CMAKE_BUILD_TYPE  

指定构建类型,例如Debug, Release


--CMAKE_C_FLAGS

指定C编译器配置


--CMAKE_CXX_FLAGS

指定C++编译器配置


--CMAKE_INSTALL_PREFIX

指定安装的路径前缀


--CMAKE_EXE_LINKER_FLAGS  

创建可执行文件时,定义链接器的配置


--CMAKE_MODULE_LINKER_FLAGS

创建模块时,定义链接器的配置


--CMAKE_BINARY_DIR

构建树顶层的完整路径


--PROJECT_BINARY_DIR

构建项目的完整路径


--CMAKE_SOURCE_DIR

源代码树顶层的完整路径


--PROJECT_SOURCE_DIR

当前项目的顶级源目录


--CMAKE_CURRENT_SOURCE_DIR

cmake 当前正在处理的源目录的完整路径


--EXECUTABLE_OUTPUT_PATH

生成的可执行文件路径


--LIBRARY_OUTPUT_PATH

生成的库路径


--BUILD_SHARED_LIBS

通过add_library构建“STATIC/SHARED”库


--CMAKE_CURRENT_LIST_FILE

当前正在处理的文件列表的完整路径


--CMAKE_CURRENT_LIST_LINE

当前正在处理的文件的行号


--CMAKE_MODULE_PATH

提供find_package搜索第三方库时使用的路径


五,开发场景中常见的CMakeList样例

场景一,简单应用

cmake_minimum_required(VERSION 3.1...3.24)#项目声明:项目名/版本号/编码语言
project(ModernCMakeExampleVERSION 1.0LANGUAGES C++)#把源代码添加进构建的目标库
add_library(MyLibExample simple_lib.cpp simple_lib.hpp)#生成可执行文件
add_executable(MyExample simple_example.cpp)#设置链接生成的库文件的名称
target_link_libraries(MyExample PRIVATE MyLibExample)

场景二,复杂工程--基于开源项目libjsonutils

cmake_minimum_required(VERSION 3.13...3.19 FATAL_ERROR)
project(libjsonutils VERSION 1.0.0 LANGUAGES CXX)#Make sure that custom modules like FindRapidJSON are found
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake)# Find system dependencies
set(MIN_BOOST_VERSION 1.65)
find_package(Boost ${MIN_BOOST_VERSION} REQUIRED COMPONENTS regex)set(MIN_RapidJSON_VERSION 1.1)
find_package(RapidJSON ${MIN_RapidJSON_VERSION} REQUIRED)# Create target and set properties
add_library(jsonutilssrc/json_utils.cppsrc/file_utils.h
)#Add an alias so that library can be used inside the build tree, e.g. when testing
add_library(JSONUtils::jsonutils ALIAS jsonutils)#Set target properties
target_include_directories(jsonutilsPUBLIC$<INSTALL_INTERFACE:include>$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>PRIVATE${CMAKE_CURRENT_SOURCE_DIR}/src
)target_compile_features(jsonutils PRIVATE cxx_auto_type)
target_compile_options(jsonutils PRIVATE$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:-Wall -Wextra -Wpedantic>)target_link_libraries(jsonutilsPUBLICBoost::headers RapidJSON::RapidJSONPRIVATEBoost::regex
)

场景三,交叉编译,嵌入式场景用的比较多,通过编写toolchain.cmake指定编译时的工具链

toolchain.cmake样例

#设定目标操作系统的名称
set(CMAKE_SYSTEM_NAME Windows)#设定编译器
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)#调整find命令的运行模式:在目标环境中搜索头文件和库
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)#在宿主机环境中搜索程序
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

        学习CMake时,直接对着语法看最枯燥且收获最小。CMake由于足够灵活,带来的问题就是晦涩难懂,笔者发现身边很多经验丰富的开发者在编写CMakeList.txt时一样头疼。所以不能指望像学习脚本语言一样看完一遍便可熟悉,而是应该像查字典一样在开发中学习。可以把一些开源项目下载到自己的编译环境,查看项目中的CMakeList的写法,然后尝试自己编译和修改,可以加深对CMake用法的理解。

参考教程: 

《CMake Cookbook》

https://www.hahack.com/codes/cmake/

https://doc.embedfire.com/linux/

https://github.com/Kitware/CMake

https://github.com/pabloariasal/modern-cmake-sample

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

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

相关文章

爬虫练习:获取某招聘网站Python岗位信息

一、相关网站 二、相关代码 import requests from lxml import etree import csv with open(拉钩Python岗位数据.csv, w, newline, encodingutf-8) as csvfile:fieldnames [公司, 规模,岗位,地区,薪资,经验要求]writer csv.DictWriter(csvfile, fieldnamesfieldnames)writer…

springboot262基于spring boot的小型诊疗预约平台的设计与开发

小型诊疗预约平台 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本小型诊疗预约平台就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理…

【PyTorch实战演练】深入剖析MTCNN(多任务级联卷积神经网络)并使用30行代码实现人脸识别

文章目录 0. 前言1. 级联神经网络介绍2. MTCNN介绍2.1 MTCNN提出背景2.2 MTCNN结构 3. MTCNN PyTorch实战3.1 facenet_pytorch库中的MTCNN3.2 识别图像数据3.3 人脸识别3.4 关键点定位 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理解&#xff…

DenseNet笔记

&#x1f4d2;from ©实现pytorch实现DenseNet&#xff08;CNN经典网络模型详解&#xff09; - 知乎 (zhihu.com) 是什么之 DenseBlock 读图&#xff1a; x0是inputH1的输入是x0 (input)H2的输入是x0和x1 (x1是H1的输出) Summary&#xff1a; 传统卷积网&#xff0c;网…

IDEA管理Git + Gitee 常用操作

文章目录 IDEA管理Git Gitee 常用操作1.Gitee创建代码仓库1.创建仓库1.点击新建仓库2.完成仓库信息填写3.创建成功4.管理菜单可以修改这个项目的设置 2.设置SSH公钥免密登录基本介绍1.找到.ssh目录2.执行指令 ssh-keygen3.将公钥信息添加到码云账户1.点击设置2.ssh公钥3.复制.…

[力扣 Hot100]Day50 二叉树中的最大路径和

题目描述 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root &…

ETL与抖音数据同步,让数据流动无阻

在当今数字化时代&#xff0c;数据的价值日益凸显&#xff0c;企业需要从各种渠道获取有关用户行为、市场趋势和竞争对手活动的数据。作为一家专注于数据集成和转换的领先平台&#xff0c;ETLCloud为企业提供了强大的数据同步和转换功能。而与此同时&#xff0c;抖音作为一款热…

Java中常见的“类”大全

Java 中有很多常见的类&#xff0c;它们提供了各种功能&#xff0c;从基本数据类型的封装到复杂的数据结构和算法。以下是一些常见的 Java 类&#xff1a; 1.Object 类&#xff1a; 所有类的超类&#xff0c;提供了一些通用的方法&#xff0c;如 toString()、equals()、hashCod…

论文解读:Meta-Baseline: Exploring Simple Meta-Learning for Few-Shot Learning

文章汇总 总体问题 通过对整体分类的训练(文章结构图中ClassifierBaseline)&#xff0c;即在整个标签集上进行分类&#xff0c;它可以得到与许多元学习算法相当甚至更好的嵌入。这两种工作之间的界限尚未得到充分的探索&#xff0c;元学习在少样本学习中的有效性仍然不清楚。…

Visual C++ 2010学习版安装教程

1. 创建项目 点击 “创建新项目”&#xff0c;创建一个项目。 2. 创建 helloworld.c ⽂件 3. 在弹出的编辑框中&#xff0c;选中 “C文件(.cpp)”&#xff0c;将 下方 “源.cpp” 手动改为要新创建的文件名。 如&#xff1a;helloWorld.c 。注意&#xff0c;默认 cpp 后缀名&am…

java SSM旅游景点与公交线路查询系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM旅游景点与公交线路查询系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系…

趣学前端 | Taro迁移完成之后,总结了一些踩坑经验

背景 四月份的时候&#xff0c;尝试将老的移动端项目改造成多端。因为老项目使用的React框架&#xff0c;综合考量&#xff0c;保障当前业务开发的进度同时&#xff0c;进行项目迁移&#xff0c;所以最后选择了Taro框架。迁移成本会低一些&#xff0c;上手快一些。 上个月&am…

CAN一致性测试:物理层测试之终端电阻测试

从本周开始结合工作实践&#xff0c;给大家总结CAN一致性相关的测试 包括&#xff1a;物理层、数据链路层、应用层三大块知识点 CAN一致性测试:物理层测试之终端电阻测试 试验目的&#xff1a; 测试控制器的 CANH 对地、CANL 对地、CANH 对 CANL 的内阻是否符合 ISO11898-2的…

读写算杂志《读写算》杂志社读写算杂志社2024年第7期目录

教育资讯 全国学生心理健康工作咨询委员会第一次全体会议召开 1 扩优提质 区域先行——基础教育高质量发展现场会在福州晋安召开 1-2 河北唐山曹妃甸&#xff1a;新学期抓好四项工作 2-3 崇红立志——江苏盐城亭湖7万学生争做新时代红色少年 3 习作选登 秋…

ubuntu設定QGC獲取pixhawk Mini4(PX4 Mini 4) 的imu信息

ubuntu20.04 QGC使用v4.3.0的版本 飛控pixhawk Mini4 飛控上只使用一條micro USB連接電腦&#xff0c;沒有其他線 安裝命令 sudo apt-get remove modemmanager -y sudo apt install gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-gl -y sudo apt install libf…

简单了解不同行业下4a的定义

工作中我们经常会听见4a这个词语&#xff0c;但大部分人对于4a的定义不是很了解&#xff0c;今天我们就来简单了解下不同行业下4a的定义。 简单了解不同行业下4a的定义 1、网络安全领域 4A指的是认证&#xff08;Authentication&#xff09;、授权&#xff08;Authorization…

ElasticSearch集群的备份和恢复

备份方式 官方建议采用snapshot方式进行备份与恢复。 单节点案例 单节点备份 首先我们看下单节点的情况下&#xff0c;我们首先需要在配置文件中配置好本地磁盘&#xff1a; path.repo:["/opt/elasticsearch-cluster/snapshot_repo"] 可以配置多个仓库&#xf…

python之数组,链表,栈,队列

1.数组 优点&#xff1a; 索引操作速度快&#xff1a;通过索引可以直接访问元素&#xff0c;因此索引操作的时间复杂度是 $O(1)$&#xff0c;即常数级 缺点&#xff1a; 插入、删除元素慢&#xff1a; 如果需要在中间或开始位置插入或删除元素&#xff0c;可能需要移动大量…

加密 / MD5算法 /盐值

目录 加密的介绍 MD5算法 盐值 加密的介绍 加密介绍&#xff1a;在MySQL数据库中, 我们常常需要对密码, 身份证号, 手机号等敏感信息进行加密, 以保证数据的安全性。 如果使用明文存储, 当黑客入侵了数据库时, 就可以轻松获取到用户的相关信息, 从而对用户或者企业造成信息…

程序员职业并不会彻底消失

目录 程序员职业在技术革新背景下面临着怎样的冲击与挑战? 程序员职业的核心能力及价值是否能被AI完全取代? 程序员的核心能力是什么?