CMakeLists 学习整理笔记

本文详细介绍了CMake的安装方法,项目中的二进制目录和源目录概念,以及如何构建静态库和动态库。还涵盖了添加工程子目录、指定目标保存目录、自定义安装规则、设置生成库属性、调用外部库、查询系统信息、设置版本要求、配置文件、函数和宏的使用。此外,讲解了foreach循环、条件判断指令和math指令的用法,以及列表操作的各种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


近期,跟着 B站—小刘老赖学习了相关Cmake 语法,整理如下:

01. CMake的安装

   视频介绍的是 Windows 的CMake安装方法,此处,扩展整理 ubuntu 环境下的命令行安装cmake 方法。

04. CMake项目的二进制目录和源目录

  CMake 会为每个项目的二进制目录、源目录隐式生成两个变量: <project_name>_BINARY_DIR 、<project_name>_SOURCE_DIR

  • <project_name>_BINARY_DIR = PROJECT_BINARY_DIR 执行 cmake命令所在的目录;
  • <project_name>_SOURCE_DIR = PROJECT_SOURCE_DIR 对应源文件的目录,即CMakeLists.txt对应的目录。
      建议使用 PROJECT_xxxx,不会随着项目名称改变而改变。

05. CMake构建静态库和动态库

   命令add_library 生成静态库/动态库

05.1 格式

add_library(lib_name [SHARE|STATIC|MODULE] [EXCLUDE_FROM_ALL] src1 src2)

参数说明

  • lib_name:指定生成库名称
  • SHARED:动态库
  • STATIC: 静态库
  • MODULE: 使用dyld(苹果的动态链接器)的系统有效,如不支持dyld,则为SHARED
  • EXCLUDE_FROM_ALL: 指定此参数,则该库默认不被构建,有其他组件用到该库或手动构建时才被构建
  • src1、src2…:用于构建库的源文件的

05.2 案例

05.2.1 文件结构
.
├── CMakeLists.txt
├── HelloLibrary.cpp
├── HelloLibrary.h
└── Main.cpp

05.2.2 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.8)		#检测CMake最低版本,最低版本3.8
project(HelloLibrary)					#项目工程名称

add_library(hello_library SHARED HelloLibrary.cpp) 	#指定库名为hello_library,因指明生成 SHARED(动态库),实际生成库文件名称为 libhello_library.so ,用于生成该库的源文件为 HelloLibrary.cpp
#add_library(hello_library STATIC HelloLibrary.cpp)	#指定库名为hello_library,因指明生成 STATIC(静态库),实际生成库文件名称为 libhello_library.a ,用于生成该库的源文件为 HelloLibrary.cpp
include_directories(${PROJECT_SOURCE_DIR}) 			#添加包含头文件的路径。此处,把项目源文件添加到包含头文件的路径中

add_executable(hello_main Main.cpp)					#指定生成可执行文件,生成的可执行文件名为 hello_main ,所需源文件为 Main.cpp

target_link_libraries(hello_main hello_library)		#指定某个目标的生成所依赖的库。此处,生成可执行文件hello_main要依赖hello_library库,即add_library指令生成的库

06. CMake添加工程子目录

   命令add_subdirectory 用于向当前工程添加子目录,并可指定中间二进制和目标二进制文件存放的位置,还可将指定目录排除出编译过程。

06.1 格式

add_subdirectory(src_dir [bin_dir] [EXCLUDE_FROM_ALL])

参数说明

  • src_dir:把src_dir 子目录加入工程
  • bin_dir:指定编译输出(包含编译的中间结果)的目录为bin_dir,如不指定默认输出目录为src_dir,即与src_dir的同名目录。指定本质是将src_dir重命名bin_dir
  • EXCLUDE_FROM_ALL: 指定此参数,将给定的目录从编译中排除,即不编译该指定目录,如,一些示例的目录,需等工程构建完后再单独构建。

06.2 案例

06.2.1 文件结构
.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp
06.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(SubDirectory)
#add_subdirectory(src)				#指定源文件子目录为src,编译输出(包含编译的中间结果)的目录命名为src
add_subdirectory(src bin)			#指定源文件子目录为src,编译输出(包含编译的中间结果)的目录命名为bin
  • src 子目录路径下 CMakeLists.txt
add_executable(sub_directory main.cpp)

07. CMake指定目标保存目录

   虽命令add_subdirectory可用于指定编译输出目录,但无法将编译中间文件与目标文件分隔开,需要结合set设置EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 来指定最终目标二进制文件存放的位置与编译中间结果分隔开。

07.1 格式

set(EXECUTABLE_OUTPUT_PATH <dir>)
set(LIBRARY_OUTPUT_PATH <dir>)

参数说明

  • EXECUTABLE_OUTPUT_PATH:最终可执行文件存放的目录
  • LIBRARY_OUTPUT_PATH:最终库文件(静态、动态库)存放的目录

07.2 案例

07.2.1 文件结构
.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── Main.cpp
    ├── SayHello.cpp
    └── SayHello.h
07.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(OutputPath)
add_subdirectory(src)
  • src 子目录路径下 CMakeLists.txt
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)	#把可执行文件生成于项目编译目录下的bin目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)		#把库文件生成于项目编译目录下的lib目录

add_library(SayHello SayHello.cpp)	#指定库名为 SayHello,默认采用STATIC(静态库)编译,实际生成库文件名称为 libSayHello.a ,用于生成该库的依赖源文件为 SayHello.cpp
include_directories(${PROJECT_SOURCE_DIR}/src)	#将源文件所在目录加入包含头文件目录中,如不加,会找不到SayHello.h该头文件
add_executable(OutputPath Main.cpp)
target_link_libraries(OutputPath SayHello)

08. CMake自定义安装

   命令INSTALL用于自定义安装规则,并配合CMAKE_INSTALL_PREFIX变量来指定安装的路径,自定义安装规则内容可以是可执行二进制文件、动态库(共享库)、静态库、普通文件、目录、非目标可执行文件(如脚本)、安装时执行cmake脚本等。

08.1 格式

08.1.1 二进制目标文件(可执行、动态库(共享库)、静态库)的安装
INSTALL(TARGRTS targets... [ARCHIVE|LIBRARY|RUNTIME] 
[DESTINATION <dir>] [PERMISSIONS permisssions...] 
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component> [OPTIONAL][...])

参数说明

  • TARGRTS : 后跟的 targets 即为add_executableadd_library定义的目标二进制可执行文件、目标二进制库
  • ARCHIVE|LIBRARY|RUNTIME : 分别指静态库、动态库(共享库)、可执行二进制文件
  • DESTINATION <dir> : 定义安装的路径,结合 CMAKE_INSTALL_PREFIX,路径为${CMAKE_INSTALL_PREFIX}/DESTINATION, 如 /开头,则直接从根目录开始, 此时CMAKE_INSTALL_PREFIX 路径无效,一般<dir>写相对路径
  • CONFIGURATIONS : 指定权限
  • COMPONENT : 指定版本

二进制目标文件示例

INSTALL(TARGETS exe sharedlib staticlib
	RUNTIME DESTINATION bin
	LIBRARY DESTINATION lib
	ARCHIVE DESTINATION static_lib)

   此句含义:

  • exe 安装到 ${CMAKE_INSTALL_PREFIX}/bin路径下
  • sharedlib 安装到 ${CMAKE_INSTALL_PREFIX}/lib路径下
  • staticlib 安装到 ${CMAKE_INSTALL_PREFIX}/static_lib路径下
08.1.2 普通文件的安装
INSTALL(FILES files... [DESTINATION <dir>]
[PERMISSIONS permisssions...] 
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] 
[RENAME <name>][OPTIONAL])

参数说明
   用于安装普通文件,可指定访问权限,文件名是此指令所在路径下的相对路径如不指定PERMISSIONS,安装后的权限为644权限

08.1.3 非目标可执行程序(如脚本)的安装
INSTALL(PROGRAMS files... [DESTINATION <dir>]
[PERMISSIONS permisssions...] 
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] 
[RENAME <name>][OPTIONAL])

参数说明
   类似安装普通文件,只是默认权限不一样安装后的权限为755权限

08.1.4 目录的安装
INSTALL(DIRECTORY dirs...  
[FILE_PERMISSIONS permisssions...] 
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] 
[[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS permissions...]]
[...])

参数说明

  • DIRECTORY : 后跟的是所在源目录的相对路径, 目录后有无/区别很大!! dir 是将 dir 这个目录安装为目录路径下的 dir , 而 dir/ 是将 dir目录下的内容安装到目标目录.但不包含dir目录本身/
  • ARCHIVE|LIBRARY|RUNTIME : 分别指静态库、动态库(共享库)、可执行二进制文件
  • DESTINATION <dir> : 定义安装的路径,结合 CMAKE_INSTALL_PREFIX,路径为${CMAKE_INSTALL_PREFIX}/DESTINATION, 如 /开头,则直接从根目录开始, 此时CMAKE_INSTALL_PREFIX 路径无效,一般<dir>写相对路径
  • PATTERN : 使用正则表达式进行过滤
  • PERMISSIONS : 用于指定 PATTERN 过滤后的文件权限

目录安装示例

INSTALL(DIRECTORY samples modules/ DESTINATION share
	PATTERN "TXT" EXCLUDE
	PATTERN "modules/*" 
	PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)

   此句含义:

  • samples 目录安装到 ${CMAKE_INSTALL_PREFIX}/share路径下
  • modules/ 目录中的内容安装到 ${CMAKE_INSTALL_PREFIX}/share路径下,不包含目录名为 TXT 的目录,并对 modules/ 目录下的文件赋予750权限
08.1.5 安装时执行cmake脚本
INSTALL([[SCRIPT <file>] [CODE <code]] [...])

参数说明

  • SCRIPT : 用于在安装时调用 cmake 脚本文件,即 xxxx.cmake 文件
  • CODE : 执行 cmake 指令,要用双引号
INSTALL(CODE "MESSAGE(\"Sample install message.\")")

08.2 案例

08.2.0 操作方法
  • a) 命令归纳
cmake -DCMAKE_INSTALL_PREFIX=/tmp ..
make
make install
  • b) 操作打印
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ cmake -DCMAKE_INSTALL_PREFIX=/tmp ..
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/gene/00_CMakeLists/cmake-master/08_CustomizeInstall/build
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ make
Scanning dependencies of target customize_install
[ 50%] Building CXX object bin/CMakeFiles/customize_install.dir/Main.cpp.o
[100%] Linking CXX executable customize_install
[100%] Built target customize_install
gene@gene:~/00_CMakeLists/cmake-master/08_CustomizeInstall/build$ make install
[100%] Built target customize_install
Install the project...
-- Install configuration: ""
-- Up-to-date: /tmp/CustomizeInstall/copyright
-- Up-to-date: /tmp/CustomizeInstall/readme
-- Up-to-date: /tmp/CustomizeInstall/bin/run_customize_install.sh
-- Up-to-date: /tmp/CustomizeInstall/share/doc
-- Up-to-date: /tmp/CustomizeInstall/share/doc/customize_install_doc.txt
-- Installing: /tmp/CustomizeInstall/bin/customize_install

08.2.1 文件结构
.
├── CMakeLists.txt
├── copyright
├── doc
│   └── customize_install_doc.txt
├── readme
├── run_customize_install.sh
└── src
    ├── CMakeLists.txt
    └── Main.cpp
08.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)         # 指定最小CMake版本
project(CustomizeInstall)                   # 指定项目工程名称
add_subdirectory(src bin)                   # 将 src 源文件子目录加入项目中
install(FILES copyright readme DESTINATION CustomizeInstall)    # 将 copyright, readme 这两个文件安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall下
install(PROGRAMS run_customize_install.sh DESTINATION CustomizeInstall/bin) # 将 run_customize_install.sh 脚本文件安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/bin下
install(DIRECTORY doc/ DESTINATION CustomizeInstall/share/doc)  # 将 doc/ 目录下所有文件(不包含该目录本身)安装到目录/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/share/doc下

  • src 子目录路径下 CMakeLists.txt
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)               #设置二进制目标可执行文件存放路径

add_executable(customize_install Main.cpp)                          #生成二进制目标可执行文件

install(TARGETS customize_install DESTINATION CustomizeInstall/bin) #指定该可执行二进制文件要安装的路径,此处为:/${CMAKE_INSTALL_PREFIX}/CustomizeInstall/bin

09. CMake设置生成库的属性

   命令set_target_properties可用于设置目标的属性, get_target_properties可用于获得目标的属性。

09.1 格式

09.1.1 设置属性
set_target_properties(target1 target2... properties prop1 value1 prop2 value2 ...)

参数说明

  • target1 target2:指定要设置属性的目标
  • prop1 value1:指定要设置属性名与属性值,如,OUTPUT_NAME, VERSION, SOVERSION
  • 09.1.2 获得属性

get_target_property(VAR target prop)

参数说明

  • VAR:获取的属性存放的变量
  • target:目标
  • prop:要获取的属性名

09.2 案例

09.2.1 文件结构
.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── linear.cpp
    └── linear.h
09.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(LibraryProperty)
add_subdirectory(src)
  • src 子目录路径下 CMakeLists.txt
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  # 设置生成库的存放目录,为编译目录的 lib 子目录

add_library(linear SHARED linear.cpp)               # 添加生成动态库目标,目标名为 linea          
add_library(static_linear STATIC linear.cpp)        # 添加生成静态库目标,目标名为 static_linea 

set_target_properties(static_linear PROPERTIES OUTPUT_NAME "linear")    # 设置静态库目标输出名为 linear

get_target_property(OUTPUT_VALUE static_linear OUTPUT_NAME)         # 获取 static_linear 属性值(OUTPUT_NAME)保存至 OUTPUT_VALUE 变量中
message(STATUS "OUTPUT_NAME = ${OUTPUT_VALUE}")                     # 将 OUTPUT_VALUE 变量中的值打印出来 (打印结果:OUTPUT_NAME = linear)

get_target_property(UNDEFINE_VALUE static_linear UNDEFINE_NAME)     # 获取 static_linear E未定义属性值(UNDEFINE_NAM)保存至 OUTPUT_VALUE 变量中
message(STATUS "UNDEFINE_NAME = ${UNDEFINE_VALUE}")                 # 将 UNDEFINE_VALUE 变量中的值打印出来,作对比(打印结果:UNDEFINE_NAME = UNDEFINE_VALUE-NOTFOUND)

set_target_properties(linear PROPERTIES VERSION 1.0 SOVERSION 1)    # 设置动态库版本号(VERSION)  API号(SOVERSION)

install(TARGETS linear static_linear LIBRARY DESTINATION lib ARCHIVE DESTINATION lib/${PROJECT_NAME}) # 动态库安装到<perfix>/lib 静态库安装到<prefix>lib/${PROJECT_NAME}
install(FILES linear.h DESTINATION include/${PROJECT_NAME})         # 头文件安装到<perfix>/include/${PROJECT_NAME}

10. CMake调用外部库

   命令target_link_libraries 用于调用外部库,为目标添加需要链接的库,命令link_libraries 用于为目标添加需要链接的库的目录,二者结合使用,前者指定具体库名称,后者指定库路径所在目录路径。include_directories 用于添加头文件搜索路径。link_directories 用于添加非系统(非标准)的库搜索路径。。

10.1 格式

命令汇总

target_link_libraries(target lib1 <debug | optimized> lib2 ...)
include_directories([AFTER | BEFORE] [SYSTEM] dir1 dir2 ...)
link_directories(dir1 dir2 ...)
link_libraries([item1 [item2 [...]]] 
	[[debug | optimized | general] <item>])

10.1 .1 添加链接库
target_link_libraries(target lib1 <debug | optimized> lib2 ...)

参数说明

  • target:目标二进制文件
  • lib1:库名称

添加需要链接外部库示例

target_link_libraries(main linear)
target_link_libraries(main liblinear.so)
target_link_libraries(main liblinear.a)

   该句含义:

  • 目标 main 链接到 linear 动态库
  • 目标 main 链接到 linear 动态库
  • 目标 main 链接到 linear 静态 库
10.1 .2 添加头文件搜索路径
include_directories([AFTER | BEFORE] [SYSTEM] dir1 dir2 ...)

说明

  • 多个路径用空格分开,如路径有空格,路径用双引号引起来;
  • 默认添加到搜索路径的后面,可通过 AFTERBEFORE 来控制添加到前面还是后面
  • CMake 变量 CMAKE_INCLUDE_DIRECTORIES_BEFORE设置为on 也可把路径添加至前面
10.1 .3 添加非系统(非标准)的库搜索路径
link_directories(dir1 dir2 ...)

说明
   此命令要放在add_executable目标之前, 如, 要放在 add_executableadd_library 之前

10.1 .4 添加链接库目录
link_libraries([item1 [item2 [...]]]
	[[debug | optimized | general] <item>])

说明
   此命令要放在目标之前, 如, 要放在 add_executableadd_library 之前, 指定的库要全称

10.2 案例

10.2.1 文件结构
  • 工程文件结构
.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── Main.cpp
  • 外部库文件结构
.
├── liblinear.so -> liblinear.so.1
├── liblinear.so.1 -> liblinear.so.1.0
├── liblinear.so.1.0
└── LibraryProperty
    └── liblinear.a
10.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(ExternalLibrary)
add_subdirectory(src)
  • src 子目录路径下 CMakeLists.txt
# 版本1 使用link_libraries 添加动/静态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)   # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录
link_libraries(/tmp/lib/liblinear.so)                 # 添加(动态)链接库,注意:全路径, 一定在 add_executable 前面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)
# link_libraries(/tmp/lib/LibraryProperty/liblinear.a)    # 添加(静态)链接库,注意:全路径, 一定在 add_executable 前面 (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)
add_executable(ExternalLibrary Main.cpp)                # 添加二进制目标,依赖 Main.cpp 
include_directories(/tmp/include/LibraryProperty)       # 添加对应头文件的目录  (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)

#版本2 使用target_link_libraries链接静态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)   # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录

link_directories(/tmp/lib/LibraryProperty)            # 添加静态库对应的目录,注意:在 add_executable前面!!(因该路径下只有静态库,虽 target_link_libraries 指定动态库,实际结果也会是静态库)
# link_directories(/tmp/lib)                              # 添加动态库对应的目录,注意:在 add_executable前面!!(虽该路径下有含静态库的目录LibraryProperty,但依旧会报错,即此时 target_link_libraries 链接不到静态库)
add_executable(ExternalLibrary Main.cpp)                # 添加二进制目标,依赖 Main.cpp 
include_directories(/tmp/include/LibraryProperty)       # 添加对应头文件的目录  (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)
target_link_libraries(ExternalLibrary liblinear.a)    # 添加链接(静态),注意:在 add_executable后面  (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)



#版本3 使用target_link_libraries链接动态库
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)   # 设置二进制目标文件输出的存放目录,为编译目录的bin子目录

link_directories(/tmp/lib)                              # 添加动态库对应的目录,注意:在 add_executable前面!!
add_executable(ExternalLibrary Main.cpp)                # 添加二进制目标,依赖 Main.cpp 
include_directories(/tmp/include/LibraryProperty)       # 添加对应头文件的目录  (无此句,会报"No such file or directory ..." 错误,即没找到对应头文件)
target_link_libraries(ExternalLibrary liblinear.so)      # 添加链接(动态),注意:在 add_executable后面  (无此类似句,会报" undefined reference to `linear_fit()' ... " 错误,即没找到要链接的库)

11. CMake查询主机系统特定信息

   命令cmake_host_system_information可用于查询主机系统特定信息。

11.1 格式

cmake_host_system_information(RESULT Value QUERY [OPTIONS] ...)

参数说明

  • Value:将查询的参数保存至此变量
  • OPTIONS:指定要查询主机的哪些参数

11.2 案例

11.2.1 文件结构
.
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── Main.cpp
11.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(HostSystemInfo)
add_subdirectory(src)
  • src 子目录路径下 CMakeLists.txt
cmake_host_system_information(RESULT NumberOfLogicalCores QUERY NUMBER_OF_LOGICAL_CORES)    # 查询 NUMBER_OF_LOGICAL_CORES, 逻辑核心数
message(STATUS "NUMBER_OF_LOGICAL_CORES = ${NumberOfLogicalCores}")
cmake_host_system_information(RESULT NumberOfPhysicalCores QUERY NUMBER_OF_PHYSICAL_CORES)  # 查询 NUMBER_OF_PHYSICAL_CORES, 物理核心数      
message(STATUS "NUMBER_OF_PHYSICAL_CORES = ${NumberOfPhysicalCores}")

cmake_host_system_information(RESULT HostName QUERY HOSTNAME FQDN)  # 查询 HOSTNAME FQDN, 主机名 主机域名全称
message(STATUS "HOSTNAME,FQDN = ${HostName}")

cmake_host_system_information(RESULT VirtualMemory QUERY TOTAL_VIRTUAL_MEMORY AVAILABLE_VIRTUAL_MEMORY) # 查询 TOTAL_VIRTUAL_MEMORY AVAILABLE_VIRTUAL_MEMORY, 总虚拟内存 可用虚拟内存
message(STATUS "TOTAL_VIRTUAL_MEMORY,AVAILABLE_VIRTUAL_MEMORY = ${VirtualMemory}")

cmake_host_system_information(RESULT PhysicalMemory QUERY TOTAL_PHYSICAL_MEMORY AVAILABLE_PHYSICAL_MEMORY)  # 查询 TOTAL_PHYSICAL_MEMORY AVAILABLE_PHYSICAL_MEMORY, 总物理内存 可用物理内存
message(STATUS "TOTAL_PHYSICAL_MEMORY,AVAILABLE_PHYSICAL_MEMORY = ${PhysicalMemory}")

cmake_host_system_information(RESULT Is64Bit QUERY IS_64BIT)    # 查询是否为64位机器 IS_64BIT 返回值: 64位机器 ---> 1;64位机器 ---> 0
message(STATUS "IS_64BIT = ${Is64Bit}")

cmake_host_system_information(RESULT HasFPU QUERY HAS_FPU)      # 查询处理器是否有浮点运算单元 HAS_FPU 返回值: 有 ---> 1;---> 0
message(STATUS "HAS_FPU = ${HasFPU}")

cmake_host_system_information(RESULT MMX QUERY HAS_MMX HAS_MMX_PLUS)   # 查询处理器是否支持 多媒体扩展指令集(HAS_MMX) 加强版多媒体扩展指令集(HAS_MMX_PLUS) 返回值: 支持 ---> 1; 不支持 ---> 0 
message(STATUS "HAS_MMX,HAS_MMX_PLUS = ${MMX}")

cmake_host_system_information(RESULT SSE QUERY HAS_SSE HAS_SSE2 HAS_SSE_FP HAS_SSE_MMX) # 查询 HAS_SSE HAS_SSE2 HAS_SSE_FP HAS_SSE_MMX 与SSE指令集相关信息
message(STATUS "HAS_SSE,HAS_SSE2,HAS_SSE_FP,HAS_SSE_MMX = ${SSE}")

cmake_host_system_information(RESULT AMD3DNow QUERY HAS_AMD_3DNOW HAS_AMD_3DNOW_PLUS)   # 查询处理器是否支持 3DNOW指令集(HAS_AMD_3DNOW) 3DNOW+指令集(HAS_AMD_3DNOW_PLUS) 

cmake_host_system_information(RESULT IA64 QUERY HAS_IA64)    # 查询英特尔安腾架构(Intel Itanium Architecture)处理器是否支持仿真X86 
message(STATUS "HAS_IA64 = ${IA64}")

cmake_host_system_information(RESULT SerialNumber QUERY HAS_SERIAL_NUMBER PROCESSOR_SERIAL_NUMBER)  # 查询 处理器是否有序列号(HAS_SERIAL_NUMBER) 及 有则打印处理器的序列号(PROCESSOR_SERIAL_NUMBER)
message(STATUS "HAS_SERIAL_NUMBER,PROCESSOR_SERIAL_NUMBER = ${SerialNumber}")

cmake_host_system_information(RESULT Processor QUERY PROCESSOR_NAME PROCESSOR_DESCRIPTION)  # 查询 处理器名称(PROCESSOR_NAME) 及 处理器全描述(PROCESSOR_DESCRIPTION)
message(STATUS "PROCESSOR_NAME,PROCESSOR_DESCRIPTION = ${Processor}")

cmake_host_system_information(RESULT OS QUERY OS_NAME OS_RELEASE OS_VERSION OS_PLATFORM)    # 查询 OS_NAME OS_RELEASE OS_VERSION OS_PLATFORM 等操作系统相关信息
message(STATUS "OS_NAME,OS_RELEASE,OS_VERSION,OS_PLATFORM = ${OS}")

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(HostSystemInfo Main.cpp)

12_13. CMake设置版本最低要求

   命令cmake_minimum_required可用于设置版本最低使用要求。命令cmake_policy可用于设置策略行为。
注意

    1. 在顶层 CMakeLists.txt 最开始调用,优于 project() 调用,即一开始建立版本策略,从而对一些受策略影响的指令比较友好。
    1. 如在 function()里调用,受函数域的限制,不能在全局调用

12.1 格式

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

参数说明

  • VERSION :版本号格式为 major.minor[.patch[.tweak]]
  • … <max> : 三个点被认为是版本号组成的各部分分隔符,因此,如CMake版本小于 3.12,则 ...<max> 部分会被忽略,于是对应的策略行为会保持 3.12 之前的基于 <min> 的形式
  • FATAL_ERROR :CMake版本高于等于2.6,参数忽略

12.2 案例

  自己的CMake 版本:cmake version 3.10.2 , cmake版本太低,policy 未实现,没有升级cmake, 实现此具体细节

12.2.1 文件结构
.
└── CMakeLists.txt
12.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
# cmake_minimum_required(VERSION 3.15)    # 错误打印结果:CMake 3.15 or higher is required.  You are running version 3.10.2
cmake_minimum_required(VERSION 3.10.2)    # 设置此时我的电脑最高版本
#cmake_policy(VERSION 3.7...3.17)
cmake_policy(SET CMP0095 NEW)
cmake_policy(SET CMP0102 NEW)
cmake_policy(GET CMP0081 CMP0081)  # 3.13
cmake_policy(GET CMP0095 CMP0095)  # 3.16
cmake_policy(GET CMP0102 CMP0102)  # 3.17
message(STATUS "CMP0081 = ${CMP0081}")
message(STATUS "CMP0095 = ${CMP0095}")
message(STATUS "CMP0102 = ${CMP0102}")

project(Policy)

14. CMake配置文件

   命令configure_file用于复制一个文件到指定位置,并可以修改该文件的内容,即,配置文件。修改内容为输入文件中以 @VAR${VAR}指定的CMake变量占位符,占位符被相应变量的内容替换。

14.1 格式

configure_file(<input> <output> 
	[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
	[NEWLINE_STYLE [UNIX | DOS | WIN32 | LF | CRLF]])

参数说明

  • <input> :要复制的文件,如是相对路径,则基于 CMAKE_CURRENT_DIR目录
  • <output> :复制的文件到的目标,可指定文件名、目录。如是已存在目录,则用<input>的文件名;如是相对路径,则基于 CMAKE_CURRENT_DIR目录
  • COPYONLY :原封不动复制文件,不做任何变量替换
  • ESCAPE_QUOTES :回避反斜杠转义,即C风格转义
  • @ONLY :只替换 @VAR@的变量${VAR}不做替换
  • NEWLINE_STYLE :输出文件中换行的方式: UNIX和LF 以 \n 换行; DOS、WIN32、CRLF 以 \r\n 换行,因输出文件与输入文件有内容变动,故不能与 COPYONLY一起用。

替换说明

  • 输入文件内容为:#cmakedefine VAR ... ,如 var 被定义,替换的内容为**#define VAR …** ;如 var 未被定义,替换的内容为 */*#undef VAR /
  • 输入文件内容为:#cmakedefine01 VAR ,如 var 被定义,替换的内容为**#define VAR 1**;如 var 未被定义,替换的内容为 #define VAR 0
  • ESCAPE_QUOTES的使用:输入文件中内容为 @QUOTE@,CMakeLists.txt 有定义:set(QUOTE "\"bb\""), 如 不使用ESCAPE_QUOTES,则输入文件中的占位符被替换为**“bb"使用ESCAPE_QUOTES,则输入文件中的占位符被替换为"\“bb\”"**

14.2 案例

14.2.1 文件结构
.
├── CMakeLists.txt
└── input.h
14.2.2 CMakeLists.txt 文件
  • 工程路径下 CMakeLists.txt
#cmake_minimum_required(VERSION 3.8)
project(ConfigureFile)

set(VAR1 123)       # 定义 VAR1 ,注意:未定义 VAR
set(VAR3 "abc")     # 定义 VAR3 ,注意:未定义 VAR4

set(NAME "haha")    # 定义 NAME
set(NEW_NAME "new haha")

set(QUOTE "\"bb\"") # 定义 QUOTE
set(my_print "print_something")

# 按参数分别输出不同的配置文件
configure_file(input.h input_default.h)     # 默认
configure_file(input.h input_copyonly.h COPYONLY)   # COPYONLY
configure_file(input.h input_escape_quotes.h ESCAPE_QUOTES) # ESCAPE_QUOTES
configure_file(input.h input_at_only.h @ONLY)               # @ONLY
configure_file(input.h input_newline_style_dos.h NEWLINE_STYLE DOS) # NEWLINE_STYLE
configure_file(input.h input_newline_style_unix.h NEWLINE_STYLE LF) # NEWLINE_STYLE

  • 配置文件(输入文件) input.h
#cmakedefine VAR 3.14               // cmakedefine 的替换
#cmakedefine VAR1 "Good"
#cmakedefine01 VAR3                 // cmakedefine01 的替换
#cmakedefine01 VAR4
#cmakedefine NAME "@NAME@"          // 变量替换 @类型
#cmakedefine NEW_NAME "${NEW_NAME}" // 变量替换 ${VAR}类型
#cmakedefine QUOTE "@QUOTE@"        // ESCAPE_QUOTES 替换

#include <iostream>

void ${my_print}() {
    std::cout << "print something" << std::endl;
}

15. CMake函数

   命令function用于指定函数名称、参数名称,命令endfunction用于结束函数的定义,可以传入与 function指令中同样的函数名称作为参数,也可不传参数,两个指令之间为函数要执行的命令,调用函数不区分大小写。

15.1 格式

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

函数的参数

  • ARGC:参数个数
  • ARGV0,ARGV1,… :第N个参数的值
  • ARGV :所有传入参数值的列表
  • ARGN :如在定义函数时,显式指定两个参数,在调用时传入五个参数,则后三个参数存于此变量

函数变量的作用域

  • 1.在函数中调用set(var xxxx), 则var在函数中的作用域内的值为xxxx ,如 var在函数的父层作用域有定义,值为yyyy,则出了此函数作用域var值仍为yyyy
  • 2.在函数中调用set(var xxxx PARENT_SCOPE), 在函数中的父层作用域中设置则var的值为xxxx 。如在函数调用之前,var存在,值为yyyy,则此函数中var值仍为yyyy,不会变成xxxx,函数调用之后,var的值变成为xxxx;如在函数调用之前,var不存在,则在函数内var的值也不存在

15.2 案例

  • CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(Function)

function(func1)
	message(STATUS "func1 called")
endfunction(func1)

message(STATUS "==========")
func1()					# 调用函数 不区分大小写
FUNC1() 


set(Var1 "Var1: init")	#设置变量 Var1 		注意:未设置变量 Var2

function(func2)
	set(Var1 "Var1: value in func2")
	message(STATUS ${Var1})
endfunction()

message(STATUS "==========")
message(STATUS "Var1 before call func2: ${Var1}")
func2()
message(STATUS "Var1 after call func2: ${Var1}")

function(func3)
	set(Var1 "Var1 : value in func3" PARENT_SCOPE)
	message(STATUS ${Var1})
	set(Var2 "Var2: init in func3" PARENT_SCOPE)
	message(STATUS ${Var2})
endfunction()

message(STATUS "==========")
message(STATUS "Var1 before call func3: ${Var1}")
message(STATUS "Var2 before call func3: ${Var2}")
func3()
message(STATUS "Var1 after call func3: ${Var1}")
message(STATUS "Var2 after call func3: ${Var2}")

function(func4 arg1 arg2)
	message(STATUS "arg1 = ${arg1}")
	message(STATUS "arg2 = ${arg2}")

	message(STATUS "ARGC = ${ARGC}")
	message(STATUS "${ARGV0} - ${ARGV1}")
	message(STATUS "ARGV = ${ARGV}")
	message(STATUS "ARGN = ${ARGN}")
	message(STATUS "ARGV2 = ${ARGV2}")
endfunction()

message(STATUS "==========")
func4("aaa" "bbb" "ccc" "ddd")

   cmake 后结果:

-- ==========
-- func1 called
-- func1 called
-- func1 called
-- ==========
-- Var1 before call func2: Var1: init
-- Var1: value in func2
-- Var1 after call func2: Var1: init
-- ==========
-- Var1 before call func3: Var1: init
-- Var2 before call func3: 
-- Var1: init
-- 
-- Var1 after call func3: Var1 : value in func3
-- Var2 after call func3: Var2: init in func3
-- ==========
-- arg1 = aaa
-- arg2 = bbb
-- ARGC = 4
-- aaa - bbb
-- ARGV = aaa;bbb;ccc;ddd
-- ARGN = ccc;ddd
-- ARGV2 = ccc

16. CMake宏

   命令macro用于指定宏名称,命令endmacro用于结束宏的定义,两个指令之间为宏要执行的命令,调用宏不区分大小写。

16.1 格式

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

函数的参数

  • ARGC:参数个数
  • ARGV0,ARGV1,… :第N个参数的值
  • ARGV :所有传入参数值的列表
  • ARGN :如在定义函数时,显式指定两个参数,在调用时传入五个参数,则后三个参数存于此变量

宏与函数的区别

  • 相同点:调用方式相同,不区分名称大小写,参数的引用同样可用,如,$(ARGC)$(ARGV#)$(ARGCN)
  • 不同点:CMake的宏与C语言类似,原地替换。宏的参数相关引用,并不是真实变量,而函数中对参数的引用是真实变量。函数有自身的域,而宏没有。

16.2 案例

  • CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(Macro)

function(print_line)
	message(STATUS "==========")
endfunction()


macro(macro1)
	message(STATUS "This macro1 test.")
	message(STATUS "macro1 called")
endmacro(macro1)

print_line()
macro1()	# 调用宏不区分大小写
MACRO1()

set(Var1 "Var1: init")	#设置变量 Var1

macro(macro2)
message(STATUS "This macro2 test.")
	set(Var1 "Var1: set Var1 in macro2")		#在宏2中修改变量 Var1 值
	message(STATUS "Var1 in macro2 = ${Var1}")
endmacro()

print_line()
message(STATUS "before call macro2: Var1 = ${Var1}")
macro2()
message(STATUS "after call macro2: Var1 = ${Var1}") #因宏原地替换并会一直保留,故调用宏后,此处 Var1 值为宏2内 Var1设置值

macro(macro3 arg1 arg2)
	message(STATUS "This macro3 test.")
	message(STATUS "arg1 = ${arg1}")
	message(STATUS "arg2 = ${arg2}")
	message(STATUS "number of arguments = ${ARGC}")
	message(STATUS "arg0 = ${ARGV0}, arg1 = ${ARGV1}")
	message(STATUS "arguments list = ${ARGV}")
	message(STATUS "ARGN = ${ARGN}")
	message(STATUS "ARGV2 = ${ARGV2}")
endmacro()

print_line()
macro3("aaa" "bbb" "ccc" "ddd")


function(func4)
	message(STATUS "This func4 test.")
	if(ARGV1)
		message(STATUS "ARGV1 = ${ARGV1}")
	endif()
	if(DEFINED ARGV2)
		message(STATUS "ARGV2 = ${ARGV2}")
	endif()
	if(ARGC GREATER 2)
		message(STATUS "ARGC GREATER 2")
	else()
		message(STATUS "ARGC NOT GREATER 2")
	endif()
	foreach(var IN LISTS ARGN)					# 循环打印 参数列表中的值
		message(STATUS "var = ${var}")
	endforeach()
endfunction(func4)


print_line()
func4("aaa" "bbb" "ccc" "ddd")

macro(macro4)
	message(STATUS "This macro4 test.")
	message(STATUS "macro4 ARGC=${ARGC}")
	if(ARGV1)
		message(STATUS "ARGV1 = ${ARGV1}")
	endif()
	if(DEFINED ARGV2)
		message(STATUS "ARGV2 = ${ARGV2}")
	endif()
	if(ARGC GREATER 2)
		message(STATUS "ARGC GREATER 2")
	else()
		message(STATUS "ARGC NOT DEFINED")
	endif()
	foreach(var IN LISTS ARGN)
		message(STATUS "var = ${var}")
	endforeach()
	set(list_var "${ARGN}")  # 将ARGN转成列表,再用 foreach
	foreach(var IN LISTS list_var)
		message(STATUS "var in list_var = ${var}")
	endforeach()
endmacro()

print_line()
macro4("aaa" "bbb" "ccc" "ddd")


macro(macro5)
	message(STATUS "This macro5 test.")
	
	message(STATUS "macro5 ARGC=${ARGC}")
	if(ARGC GREATER 2)
		message(STATUS "ARGC GREATER 2")
	else()
		message(STATUS "ARGC NOT DEFINED")
	endif()

	foreach(arg IN LISTS ARGN)
		message(STATUS "arg = ${arg}")
	endforeach()
endmacro()

function(func5)
	message(STATUS "This func5 test.")
	macro5(xx yy zz)	# 函数中调用宏,并传入三个参数,宏中调用传入的三个参数是未定义的,并没有使用
endfunction()

print_line()
func5("aa" "bb" "cc" "dd")	#函数里参数应用有时真实变量,而在宏中,参数引用并不是变量。因此,在宏中, ARGC、ARGV、ARGN,ARGV# 都是未定义的, 此处,函数传入的三个参数被宏使用了

   cmake 后结果:

-- ==========
-- This macro1 test.
-- macro1 called
-- This macro1 test.
-- macro1 called
-- ==========
-- before call macro2: Var1 = Var1: init
-- This macro2 test.
-- Var1 in macro2 = Var1: set Var1 in macro2
-- after call macro2: Var1 = Var1: set Var1 in macro2
-- ==========
-- This macro3 test.
-- arg1 = aaa
-- arg2 = bbb
-- number of arguments = 4
-- arg0 = aaa, arg1 = bbb
-- arguments list = aaa;bbb;ccc;ddd
-- ARGN = ccc;ddd
-- ARGV2 = ccc
-- ==========
-- This func4 test.
-- ARGV1 = bbb
-- ARGV2 = ccc
-- ARGC GREATER 2
-- var = aaa
-- var = bbb
-- var = ccc
-- var = ddd
-- ==========
-- This macro4 test.
-- macro4 ARGC=4
-- ARGC NOT DEFINED
-- var in list_var = aaa
-- var in list_var = bbb
-- var in list_var = ccc
-- var in list_var = ddd
-- ==========
-- This func5 test.
-- This macro5 test.
-- macro5 ARGC=3
-- ARGC GREATER 2
-- arg = aa
-- arg = bb
-- arg = cc
-- arg = dd

17. CMake的foreach循环

   命令foreach用于循环列表中的每一项。

17.1 格式

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

参数说明

  • loop_var:用于存放每轮循环时列表中该项的值
  • items :列表的项
  • commands :每轮循环执行的指令
  • endforeach :结束foreach循环指令,为了兼容,可把loop_var作为参数传入

foreach 常见用法

  • foreach(<loop_var> RANGE <stop>) 循环值从 0 到指定 stop (含stop) ,stop 不能为负
  • foreach(<loop_var> RANGE <start> <stop> [<step>]) 循环值从 start 到stop (含stop) , 步长为step, stop 不能比 start 小
  • foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items]]) 循环列表中的项,或直接指定项
  • cmake > 3.17版本 : foreach(<loop_var>...IN ZIP_LISTS <lists>) 组合多个列表一起循环,若多个列表项数不等,项数少的loop_var为空

17.2 案例

  • CMakeLists.txt
# cmake_minimum_required(VERSION 3.17)
cmake_minimum_required(VERSION 3.10)	# 我的版本,用法5 所需版本高没测试
project(Foreach)

message(STATUS "用法1:指定stop")
foreach(num RANGE 3)				# 用法1:指定stop

	message(STATUS "num = ${num}")
endforeach()

message(STATUS "=====")
message(STATUS "用法2:指定start stop step")
foreach(num RANGE 3 12 3)			# 用法2:指定start stop step
	message(STATUS "num = ${num}")
endforeach()

message(STATUS "=====")
set(A 2;5)							
set(B 1 2 3)
set(C "1 2 3")
set(D 5;8 9)
set(E "")
message(STATUS "用法3_1:指定列表的变量,多个变量空格分隔")
foreach(x IN LISTS A B C D E)		# 用法3_1:指定列表的变量,多个变量空格分隔
	message(STATUS "x = ${x}")
endforeach()

message(STATUS "=====")
message(STATUS "用法3_2:只指定一个列表变量")
foreach(b IN LISTS B)				# 用法3_2:只指定一个列表变量
	message(STATUS "b = ${b}")
endforeach()

message(STATUS "=====")
message(STATUS "用法4:通过 ITEMS 指定列表的项")
foreach(b IN ITEMS ${B})			# 用法4:通过 ITEMS 指定列表的项,此处用${B}, 即,将B变量的项在此处展开
	message(STATUS "b = ${b}")
endforeach()

message(STATUS "=====")
set(A 5;10;15)
set(B a b c)
set(C 100;200;300)
message(STATUS "用法5_1:多个列表组合")
foreach(pair IN ZIP_LISTS A B)		# 用法5_1:多个列表组合,只用一个变量 变量名_# 取多个列表的项值
	message(STATUS "pair_0 = ${pair_0}, pair_1 = ${pair_1}")
endforeach()

message(STATUS "=====")
message(STATUS "用法5_2:多个列表组合")
foreach(aa bb cc IN ZIP_LISTS A B C)# 用法5_2:多个列表组合,每个列表用一个变量取值
	message(STATUS "aa = ${aa}, bb = ${bb}, cc = ${cc}")
endforeach()

   cmake 后结果:

-- 用法1:指定stop
-- num = 0
-- num = 1
-- num = 2
-- num = 3
-- =====
-- 用法2:指定start stop step
-- num = 3
-- num = 6
-- num = 9
-- num = 12
-- =====
-- 用法3_1:指定列表的变量,多个变量空格分隔
-- x = 2
-- x = 5
-- x = 1
-- x = 2
-- x = 3
-- x = 1 2 3
-- x = 5
-- x = 8
-- x = 9
-- =====
-- 用法3_2:只指定一个列表变量
-- b = 1
-- b = 2
-- b = 3
-- =====
-- 用法4:通过 ITEMS 指定列表的项
-- b = 1
-- b = 2
-- b = 3

18. CMake的条件判断指令

   命令if 用于条件判断。

18.1 格式

if(<条件>)
	<命令>
elseif(<条件>)
	<命令>
else()
	<命令>
endif())

多条件组合,顺序优先级

    1. 有括号的,先检测括号内
    1. 一元检测, 如:EXISTS, COMMAND, DEFINED
    1. 二元检测, 如:EQUAL,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,STREQUAL,STRLESS,STRLESS_EQUAL,STRGREATER,STRGREATER_EQUAL,VERSION_EQUAL,VERSION_LESS,VERSION_LESS_EQUAL,VERSION_GREATER,VERSION_GREATER_EQUAL,MATCHES
    1. bool运算,首先 NOT,接着 AND,最后 OR

18.2 案例

  • CMakeLists.txt
# cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.10)
project(IfElse)
add_executable(main main.cpp)

if(ON)
	message("ON")
endif()

if(NOT IGNORE)
	message("NOT IGNORE")
endif()

if(ON AND NO)
	message("ON AND NO")
elseif(OFF OR 0)
	message("OFF OR 0")
else()
	message(" next else() ")
endif()

if(NOT "var")
	message("NOT var")
endif()

set(var1 "var1")	
if(var1)					# 判断 变量 是否存在
	message("var1")
endif()

function(func1)	
	message("func1")
endfunction()

if(COMMAND func1)			# 判断 函数 是否存在
	message("COMMAND func1")
endif()

if(NOT COMMAND func2)
	message("NOT COMMAND func2")
endif()

if(POLICY CMP0054)			# 判断 策略 是否存在
	message("POLICY CMP0054")
endif()

if(TARGET main)				# 判断 目标 是否存在
	message("TARGET main")
endif()

if(NOT TEST test1)			# 判断 测试 是否存在
	message("NOT TEST test1")
endif()

if(EXISTS /home/xlll/)		# 判断 指定路径(目录或文件) 是否存在
	message("EXISTS")
endif()

if(/home/xlll/CMakeProjs/IfElse/CMakeLists.txt IS_NEWER_THAN /home/xlll/CMakeProjs/IfElse/main.cpp)	# 判断 文件1 是否比 文件2message("IS_NEWER_THAN")
endif()

if(IS_DIRECTORY /home/xlll/CMakeProjs/IfElse/)	# 判断是否是目录
	message("IS_DIRECTORY")
endif()

if(NOT IS_SYMLINK /home/xlll/CMakeProjs/IfElse/CMakeLists.txt)	# 判断是否是符号链接文件
	message("NOT IS_SYMLINK")
endif()

if(IS_ABSOLUTE /home/xlll/)	# 判断是否是绝对路径
	message("IS_ABSOLUTE")
endif()

if("a" MATCHES "[abc]")		# 判断是否匹配正则表达式
	message("MATCHES")
endif()

set(var1 5)
set(var2 10)
if(var1 LESS var2)			# 数字比较大小
	message("LESS")
endif()

set(var1 "hello")
set(var2 "world")
if(var1 STRLESS var2)		# 字符串比较大小
	message("STRLESS")
endif()

set(var1 "3.16.4")
set(var2 "3.17")
if(var2 VERSION_GREATER var1)	# 版本号比较大小
	message("VERSION_GREATER")
endif()

set(var1 "a")
set(var2 a b c d)
if(var1 IN_LIST var2)		# 判断变量是否在列表中
	message("IN_LIST")
endif()

if(DEFINED var1)			# 判断变量是否已定义
	message("DEFINED")		
endif()

set(varFalse FALSE)
set(varName "varFalse")
if(${varName})				# 变量替换 会展开为 if(varFalse), 再把 varFalse 作为变量判断
	message("${varName} is true")
else()
	message("${varName} is false")
endif()

if(varName)					# 如未用 ${} ,则直接作为变量来判断变量值	
	message("varName is true")
endif()

   cmake 后结果:

ON
NOT IGNORE
next else()
NOT var
var1
COMMAND func1
NOT COMMAND func2
POLICY CMP0054
TARGET main
NOT TEST test1
IS_NEWER_THAN
NOT IS_SYMLINK
IS_ABSOLUTE
MATCHES
LESS
STRLESS
VERSION_GREATER
IN_LIST
DEFINED
varFalse is false
varName is true

19. CMake的条件判断指令

   命令while 用于循环判断。

19.1 格式

while(<条件>)
	<命令>
endwhile())

19.2 案例

  • CMakeLists.txt
# cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.10)
project(While)

set(var 10)
while(var GREATER 0)
	message("var = ${var}")
	math(EXPR var "${var}-1")		# var 值减1
	if(var LESS 3)
		message("This is a break()")
		break()
	endif()
	if(var EQUAL 5)
		message("This is a continue()")
		math(EXPR var "${var}-1")
		continue()
	endif()
endwhile()

   cmake 后结果:

var = 10
var = 9
var = 8
var = 7
var = 6
This is a continue()
var = 4
var = 3
This is a break()

20. CMake的math指令

   命令math 用于数学运算。计算 expression 表达式的值,表达式中如要使用16进制的数,此数要以0x前缀,结果必须为64位的有符号整数。

20.1 格式

math(EXPR <variable> "<expression>" [OUTPUT_FORMAT <format>])

参数说明

  • format : 用于设置输出格式,支持 十进制 DECIMAL与 十六进制HEXADECIMAL 两种格式

支持的运算符
+, -, *, /, %, |, &, ^, ~, <<, >>, ()

20.2 案例

  • CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(Math)

math(EXPR val1 "100 * 0xA")     
math(EXPR val2 "100 * 0xA" OUTPUT_FORMAT DECIMAL)       # 十进制格式输出到 val2
math(EXPR val3 "100 * 0xA" OUTPUT_FORMAT HEXADECIMAL)   # 十六进制格式输出到 val3

message("val1 = ${val1}")
message("val2 = ${val2}")
 message("val3 = ${val3}")

21. CMake列表的操作——读取列表

   命令list 用于列表操作。列表以分号分隔开一组字符串,可通过set命令定义。
PS :
set(var a b c d) 定义了一个列表a;b;c;d;而set(var "a b c d") 定义了一个字符串"a b c d",并不是列表

20.1 格式

    1. 列表长度
list(LENGTH <列表> <输出变量>)

   列表长度读取到输出变量。

    1. 读取列表元素
list(GET <列表> <输出变量>)

  读取列表元素至输出变量。元素索引为正,从列表头部开始索引,索引0作为第一个元素;索引为负,从列表尾部开始索引,索引-1作为最后一个元素。

    1. 列表连接成字符串
list(JOIN <列表>  <连接符> <输出变量>)

  把列表的元素连接成一字符串,元素之间指定连接符分隔。

    1. 读取子列表
list(SUBLIST <列表>  <开始索引> <子列表个数> <输出变量>)

  从列表的开始索引读取指定个数作为子列表返回给输出变量。如,子列表个数为-1,或开始索引+子列表个数大于列表元素数,则整个列表直接作为子列表返回给输出变量。

20.2 案例

  • CMakeLists.txt
# cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.10)
project(List)

set(var a b c d e)                  # 定义了一个列表 a;b;c;d;e
message("var = ${var}")

list(LENGTH var varLen)             # 获取列表长度
message("varLen = ${varLen}")

list(GET var 1 3 -1 varElems)       # 获取列表第 2 4 和最后一个元素
message("varElems = ${varElems}")

list(JOIN var "-->" varJoin)        # 将列表元素连接成字符串
message("varJoin = ${varJoin}")

list(SUBLIST var 1 2 varSub1)       # 获取子列表从第 2 个元素开始,共2个元素
list(SUBLIST var 1 -1 varSub2)      # 获取子列表从第 2 个元素开始,到列表结尾
list(SUBLIST var 1 10 varSub3)      # 获取子列表从第 2 个元素开始,到列表结尾
message("varSub1 = ${varSub1}")
message("varSub2 = ${varSub2}")
message("varSub3 = ${varSub3}")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值