【CMake】15分钟带你入门CMake

这篇具有很好参考价值的文章主要介绍了【CMake】15分钟带你入门CMake。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持!
博主链接

本人就职于国际知名终端厂商,负责modem芯片研发。
在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。


博客内容主要围绕:
       5G/6G协议讲解
       算力网络讲解(云计算,边缘计算,端计算)
       高级C语言讲解
       Rust语言讲解




【CMake】15分钟带你入门CMake,cmake

一、CMake的工作原理

【CMake】15分钟带你入门CMake,cmake

在上图所示的配置过程中,CMake可以生成多种构建工具对应的构建文件,默认情况下会生成“Unix Makefiles”构建文件。我们可以使用-G命令来设置CMake在配置过程中生成对应的构建文件,下图所示是CMake(version 3.22.1)支持的构建工具:

【CMake】15分钟带你入门CMake,cmake
完成配置和构建之后,会在指定的build文件夹中生成很多文件,其中值得注意的是一个名为CMakeCache.txt的文件,如下图所示:
【CMake】15分钟带你入门CMake,cmake
这里缓存了整个项目在配置过程中检测到的所有信息,例如工具链配置、自定义的带有cache属性的宏、系统环境等,其部分内容如下所示:

【CMake】15分钟带你入门CMake,cmake
CMakeCache.txt文件存在的意义是提升之后的构建速度。第一次构建项目时会经历上述“配置+构建”流程,如果在上次构建项目后没有修改CMakeLists.txt或者与CMake相关的其它文件(例如,CMakePresets.txt、CMakeCache.txt等),则会直接进入构建流程,缩短项目整体的构建时间。


二、CMake语法入门

2.1 基本的CMakeLists.txt结构

# 定义要求的最小CMake版本
cmake_minimum_required(VERSION 3.26)

# 定义项目名称和使用的语言
project(cmake_share C)

set(CMAKE_C_STANDARD 11)

# 定义一个可执行文件cmake_share,并声明其依赖的源文件
add_executable(cmake_share main.c)

2.2 变量和列表

2.2.1 变量

CMake中可以使用set()定义和unset()删除一个变量,并使用${<variable-name>}访问一个变量的值。注意,在CMake中是区分大小写的。

下面是一个定义和删除变量的示例:

# 定义变量CSRS
set(CSRS "congshanruoshui")

# 输出变量CSRS的值
message(STATUS "The content of CSRS is ${CSRS}")

# 删除变量CSRS
unset(CSRS)

# 输出变量CSRS的值,此时为空
message(STATUS "The content of CSRS is ${CSRS}")

输出如下:

【CMake】15分钟带你入门CMake,cmake

2.2.2 列表

使用set() 命令可以定义一个列表,其中所有的列表元素可以通过双引号括起并使用分号隔离,也可以不使用双引号括起,直接使用空格隔离即可,例如下面的代码所示:

set(CSRS this is a good blogger)
message(STATUS "The content of CSRS is ${CSRS}")

set(CSRS "this;is;a;good;blogger")
message(STATUS "The content of CSRS is ${CSRS}")

输出内容如下:
【CMake】15分钟带你入门CMake,cmake

如果要在列表中追加、查找、获取一个元素,需要使用list()命令。下面是一个示例:

# 使用关键词APPEND向列表尾部追加元素
list(APPEND CSRS "!")
message(STATUS "The content of CSRS is ${CSRS}")

list(FIND CSRS "blogger" BLOGGER_INDEX)

# 如果没有查找到,则BLOGGER_INDEX的值为-1
if(${BLOGGER_INDEX} LESS 0)
    message(STATUS "Not find \"blogger\" in CSRS")
else()
    message(STATUS "Find \"blogger\" in CSRS at index ${BLOGGER_INDEX}")
endif()

# 根据索引值获取列表中的对应元素
list(GET CSRS ${BLOGGER_INDEX} BLOGGER)
message(STATUS "The word in CSRS at index ${BLOGGER_INDEX} is ${BLOGGER}")

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

列表中元素的索引值是从0开始的。

2.3 条件判断和循环

2.3.1 条件判断

CMake条件判断的基本结构如下所示:

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

其中condition是由各种关键字组成的,包括:

  • 常用一元运算符:
    • COMMAND:检查提供的值是否为一个命令,如果是则为true;
    • EXISTS: 检查一个文件或者路径是否存在;
    • DEFINED: 检查提供的值是否被定义,如果定义则为 true;
    • IS_DRRECTORY: 检查提供的路径是否为一个日录,如果是则为 true;
    • IS_ABSOLUTE: 检查提供的路径是否为一个绝对路径,如果是则为 true;
  • 常用二元运算符:
    • LESS、 GREATER、 EQUAL、 LESS EQUAL 和 GREATER EQUAL:用于数值之间的比
      较;
    • STRLESS、 STREQUAL、 STRGREATER、 STRLESS EQUAL 和 STRGREATER EQUAL:
      用字符串之间的比较;
    • MATCHES:用于匹配一个正则表达式;
  • 常用逻辑运算符:
    • AND、 OR:逻辑与和或;
    • NOT:逻辑非

下面是一个示例:

set(TEST_IF ON)
if(DEFINED TEST_IF)
    message(STATUS "TEST_IF is ON")
endif()

set(MONTH 12)
if(${MONTH} EQUAL 12)
    message(STATUS "MONTH is 12")
endif()

set(CSRS "CongShanRuoShui")
if(${CSRS} STREQUAL "CongShanRuoShui")
    message(STATUS "CSRS is CongShanRuoShui")
endif()

if((${MONTH} EQUAL 12) AND (${CSRS} STREQUAL "CongShanRuoShui"))
    message(STATUS "MONTH is 12")
    message(STATUS "CSRS is CongShanRuoShui")
endif()

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

2.3.2 循环

循环结构有两种,分别while和foreach,它们的结构如下所示。

while(<condition>)
  <commands>
endwhile()

对于while循环来说,其condition与if中的condition是一样的,例如下面的代码示例:

set(test_while 5)
while(${test_while} GREATER 0)
    message(STATUS "test_while is ${test_while}")
    math(EXPR test_while "${test_while}-1")
endwhile()

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

foreach(<loop_var> <items>)
  <commands>
endforeach()

对于foreach循环来说,items可以是一组元素、一个列表或者一个数值范围,例如下面的代码所示:

set(test_while 5)
while(${test_while} GREATER 0)
    message(STATUS "test_while is ${test_while}")
    math(EXPR test_while "${test_while}-1")
endwhile()

set(test_foreach a b c d e)
foreach(item IN LISTS test_foreach)
    message(STATUS "item is ${item}")
endforeach()

foreach(item IN ITEMS a b c d e)
    message(STATUS "item is ${item}")
endforeach()

foreach(month RANGE 1 12)
    message(STATUS "month is ${month}")
endforeach()

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

2.4 函数与宏

2.4.1 函数

CMake的函数定义,是通过关键字function()endfunction()完成的,其结构如下所示:

function(<name> [<arg1> ...])
  <commands>
endfunction()

注意,CMake中的变量也是有生命周期的,函数内定义的变量只能在函数范围内访问(除非定义了PARENT_SCOPE属性)。下面是一个函数的例子:

function(test_function name year)
    message(STATUS "${name} is ${year} years old")
endfunction()

test_function(CSRS 18)

其运行结果如下:
【CMake】15分钟带你入门CMake,cmake

2.4.2 宏

宏定义的结构如下所示:

macro(<name> [<arg1> ...])
  <commands>
endmacro()

宏的概念和函数类似,但是不同的是宏不会创建一个新的作用域,而且宏的参数必须使用花括号访问,下面是一个示例代码:

macro(test_macro name year)
    message(STATUS "${name} is ${year} years old")
endmacro()
test_macro(CSRS 18)

其运行结果如下:
【CMake】15分钟带你入门CMake,cmake

2.5 执行外部程序

有些时候我们需要执行一些外部指令,例如编译外部项目、获取项目git信息等,可以通过下面的几个命令来实现。

2.5.1 在配置阶段执行命令

execute_process()命令会在项目的配置阶段执行,例如可以检查项目依赖的子项目是否已经下载、当前的git分支是否正确等。 execute_process()的常用结构如下所示:

execute_process(
	# 要执行的命令
	COMMAND <custom command>
	# 执行命令的目录
	WORKING_DIRECTORY <dir>
	# 命令结果输出
	OUTPUT_VARIABLE var
	# 剔除输出尾部的空格
	OUTPUT_STRIP_TRAILING_WHITESPACE
	# 发送错误时停止执行
	ERROR_QUIET
)

下面是一个例子:

execute_process(
        COMMAND ls -al
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        OUTPUT_VARIABLE result
        OUTPUT_STRIP_TRAILING_WHITESPACE
        ERROR_QUIET
)
message(STATUS "result is ${result}")

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

2.5.2 在配置阶段执行命令

add_custom_command()命令可以在配置阶段执行客制化的命令,配置阶段又细分为编译前(PRE_BUILD)、链接前(PRE_LINK)和编译后(POST_BUILD),其通用结构如下所示:

add_custom_command(
	TARGET <target>
	PRE_BUILD | PRE_LINK | POST_BUILD
	COMMAND command1 [ARGS] [args1...]
)

大部分情况都是在编译后执行客制化的命令,例如检查编译生成的文件是否正确等。下面是一个例子,将编译后的可执行文件改名:

add_executable(cmake_share main.c)


add_custom_command(
        TARGET cmake_share
        POST_BUILD
        COMMAND mv cmake_share cmake_share_test
)

结果如下所示:
【CMake】15分钟带你入门CMake,cmake

2.6 查找外部库

有些时候我们需要使用外部库,这种情况尤其发生在交叉编译时,可以使用下面的命令查找一个库:

pkg_search_module(<prefix>
				[REQUIED] [QUIET]
				<moduleSpec> [<moduleSpec>...])

pkg_search_module()函数会查找满足<moduleSpec>的库文件,并将查找结果保存到以<prefix>开头的关键字中,例如下面的代码:

include(FindPkgConfig)
find_package(PkgConfig REQUIRED)

pkg_search_module(OPENSSL REQUIRED openssl)

if(OPENSSL_FOUND)
    message(STATUS "openssl is found")
endif()

输出结果如下:
【CMake】15分钟带你入门CMake,cmake

ubuntu可以通过apt命令安装 libssl-dev

上面的代码首先include对应的库文件FindPkgConfig,然后检查pkg-config程序是否存在,因为pkg_search_module函数依赖pkg-config程序,所以使用前建议使用上面的命令检查本地是否安装了pkg-config程序。

上面代码表示在搜索路径中查找名字为"openssl"的库,如果不存在则终止配置过程,如果存在则将查找结果保存到以"OPENSSL_"开头的关键字中。下面介绍几个常用的关键字:

  • <xxx>_FOUND:如果当前的库找到了,则为1;
  • <xxx>_LIBRARIES:查找到的库的名称(没有-l)(小写L);
  • <xxx>_LINK_LIBRARIES:查找到的库的名称,带有绝对路径;
  • <xxx>_LIBRARY_DIRS:查找到的库所在的目录(没有-L);
  • <xxx>_LDFLAGS:查找到的库相关的依赖选项;
  • <xxx>_INCLUDE_DIRS:查找到的库对应的头文件所在的目录(没有I)(大写i);
  • <xxx>_CFLAGS:查找到的库对应的cflags;

对于交叉编译来说,可能需要将对应的库所在的路径添加到CMake变量CMAKE_PREFIX_PATH或者环境变量PKG_CONFIG_PATH中。

2.7 静态、动态和可执行文件

通常一个项目包含一些子模块,为这些子模块编写单独的CMakeLists.txt并将其编译成库(静态、动态)有助于项目的管理和维护。

我们在项目里添加一个utils目录,并将目录中的文件编译成一个utils库,目录结构如下:
【CMake】15分钟带你入门CMake,cmake

2.7.1 静态库

下面我们编译一个示例,将utils编译成静态库:

# 加入utils目录,这样可以找到头文件
include_directories("utils")

# add_library()在默认情况下会将库编译成静态库
add_library(utils
        utils/test_library.c
)

编译的静态库utils如下:
【CMake】15分钟带你入门CMake,cmake

2.7.2 动态库

下面的代码将上述utils库编译成动态库:

include_directories("utils")
add_library(utils SHARED
        utils/test_library.c
)

# 对于SHARED和MODULE来说,CMake会自动开启PIC选项
# set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ON)

编译的动态库utils如下:
【CMake】15分钟带你入门CMake,cmake

2.7.3 可执行文件

编译一个可执行程序的命令是add_executable(),其结构如下所示:

add_executable(<name>
				[source1]
				[source2...])

下面是一个例子:

add_executable(cmake_share main.c)

# 声明cmake_share依赖的库
target_link_libraries(cmake_share utils)

无论我们编译的是静态库、动态库还是可执行程序,有时我们都需依赖一些外部库,此时可以使用下面的命令target_link_libraries(),其结构如下所示:

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

其中<target>是库或者可执行程序的名称,<item>是依赖库。

三、总结

上面介绍了CMake的工作原理,以及一些基本的语法操作,掌握上述语法之后,可以简单的阅读一些项目的CMakeLists.txt。下面给出了上述例子的项目地址,感兴趣的童鞋可以下载运行一下。

cmake-share



【CMake】15分钟带你入门CMake,cmake文章来源地址https://www.toymoban.com/news/detail-743903.html

到了这里,关于【CMake】15分钟带你入门CMake的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 15 分钟带你感受 CSS :has() 选择器的强大

    最近看到了许多关于 :has() 选择器的知识点,在此总结下来。 MDN 对 :has() 选择器 的解释是这样的: CSS 函数式伪类  :has()  表示一个元素,如果作为参数传递的任何相对选择器在锚定到该元素时,至少匹配一个元素。这个伪类通过把可容错相对选择器列表作为参数,提供了一

    2024年03月24日
    浏览(31)
  • 【无标题】visual studio2019+Qt5.15.2+PCL1.12.1+vtk9.1.0+cmake3.22.2

    安装VS------安装Qt-------安装PCL------安装cmake-----安装VTK-----环境配置 安装用了两天时间 1环境搭建 1.1 Visual Studio 2019 (PCL所需版本) https://my.visualstudio.com/Downloads?q=visual%20studio%202019wt.mc_id=o msft vscom~older-downloads 1.2 Qt安装 https://download.qt.io/archive/online install 选择online install ●选择安装

    2024年02月16日
    浏览(43)
  • windows下cmake的小白级入门使用教程(hello world)

    想学习cmake,基于惯性思维,想先跑通一个“hello world”的例子,奈何网上教程一大把,有用的教程破费功夫寻找。大部分教程都没有从新电脑(重装系统后的电脑)的角度讲述步骤。 为了得到干净的电脑环境,研究了一段时间VMware虚拟机,并写了几篇文章,感兴趣的读者可移步

    2024年02月14日
    浏览(43)
  • CMake入门教程【高级篇】编译选项target_compile_options

    target_compile_options 命令允许用户为特定目标(如可执行文件或库)指定编译器选项,这对于优化构建过程和确保代码兼容性至关重要。

    2024年01月15日
    浏览(40)
  • VSCODE+MSVC+CMAKE配置实践入门:简单编写EXE、LIB和DLL

    目录 EXE: HelloWorld 设置运行环境  编写运行 免设置运行环境的方法 LIB: 加法函数 Add C语言LIB 编译:命令行/task 测试Add.lib DLL: 乘法函数 Mul C语言DLL  编译DLL 测试Mul.dll 生成预编译文件 使用预编译文件 CMAKE 安装CMAKE 使用CMAKE         像VS这样的IDE帮我们包办了很多的事情,同

    2024年02月02日
    浏览(41)
  • 从零开始 TensorRT(5)C++ 篇:g++、CMake、VS Code 环境入门

    学习资料: B站视频:基于 VSCode 和 CMake 实现 C/C++ 开发 B站视频:Cherno C++ 教程   从本文开始,正式进入 C++ 部分。由于个人 C++ 零基础,仅了解一些 Python,所以学习时的痛点更偏向于 C++ 的基础,例如 VS Code、CMake、C++ 语法等,TensorRT 的部分和在 Python 中使用大同小异。  

    2024年02月22日
    浏览(43)
  • 【CMake 入门与进阶(3)】 CMakeLists.txt 语法规则基础及部分常用指令(附使用代码)

            在上两篇中,笔者通过几个简单地示例向大家演示了 cmake 的使用方法,由此可知,cmake 的使用方法其实还是非常简单的,重点在于编写 CMakeLists.txt,CMakeLists.txt 的语法规则也简单,并没有 Makefile 的语法规则那么复杂难以理解!本文我们来学习CMakeLists.txt 的语法规

    2024年02月11日
    浏览(40)
  • CMake入门教程【基础篇】4.target_include_directories包含指定文件夹头文件

    target_include_directories包含指定文件夹头文件 target_include_directories() 指定目标包含的头文件路径  |-📁prj3   |-- 🎴CMakeLists.txt   |-📁include    |-- 📄Hello.h   |-📁src    |-- 📄Hello.cpp    |-- 📄main.cpp

    2023年04月09日
    浏览(34)
  • CMake入门教程【高级篇】CPack打包项目Linux的deb和windows的msi

    😈 「CSDN主页」 :传送门 😈 「Bilibil首页」 :传送门 😈 「动动你的小手」 : 点赞 👍 收藏 ⭐️ 评论 📝

    2024年02月02日
    浏览(42)
  • 一分钟带你入门Selenium入门!【建议收藏】

    欢迎阅读Selenium入门讲义,本讲义将会重点介绍Selenium的入门知识以及Selenium的前置知识。 在Selenium的课程以前,我们先回顾一下软件测试的基本原理,为我们进一步完成Selenium自动化测试做好准备。 G.J.Myers在其经典的著作《软件测试艺术》(The Art of Software Testing)一书中,给

    2024年04月23日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包