跳转至

CMakeLists

CMakeLists中命令不区分大小写的,但通常建议命令使用大写

1 入门示例

  • cmake_minimum_required:指定 cmake 最低版本
  • project:指定项目名称
  • add_executable:添加可执行文件
cmake_minimum_required(VERSION 3.10)

## set the project name
project(Tutorial)

## add the executable
add_executable(Tutorial tutorial.cxx)

2 项目设置

2.1 cmake_minimum_required

  • 功能:设置需要的 cmake 最小版本号
  • 语法:cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
    • <min>:(必选)最小版本号,格式是 major.minor[.patch[.tweak]],比如 1.2.0
    • ...<policy_max>:(可选)最大版本号
    • FATAL_ERROR:(可选)该参数在 cmake 的 2.6 及以后的版本被忽略,在 cmake 的 2.4 及以前的版本,需要指明该参数,以便 cmake 能提示失败而不仅仅是一个警告。
  • 示例
cmake_minimum_required(VERSION 3.12.0)
cmake_minimum_required(VERSION 3.12.0...3.24.0)

2.2 project

project会影响以下几个变量:
- `PROJECT_NAME`:这是在当前目录范围或上层范围内最近一次调用的 project() 命令的名称。
- `CMAKE_PROJECT_NAME`:这是在顶级 CMakeLists.txt 文件中最近一次调用project() 命令的名称。
- `PROJECT_SOURCE_DIR`, `<PROJECT-NAME>_SOURCE_DIR`:项目源文件的绝对路径
- `PROJECT_BINARY_DIR`, `<PROJECT-NAME>_BINARY_DIR`:项目二进制文件的绝对路径
- `PROJECT_IS_TOP_LEVEL`, `<PROJECT-NAME>_IS_TOP_LEVEL`:New in version 3.21.
  • 功能:设置项目的名称,并将其存储在变量 PROJECT_NAME 中。当从顶层调用时,CMakeLists.txt 还将项目名称存储在变量 CMAKE_PROJECT_NAME 中。
  • 语法:2 种语法形式,第一种简单形式,可选支持的语言类型,默认 C、CXX
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
        [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
        [DESCRIPTION <project-description-string>]
        [HOMEPAGE_URL <url-string>]
        [LANGUAGES <language-name>...])
  • 示例 1:简单形式
project(nfs-ganesha C CXX)
  • 示例 2:复杂形式
cmake_minimum_required(VERSION 3.10)

project(MyProject
        VERSION 1.0.0
        LANGUAGES CXX
        DESCRIPTION "A simple CMake project"
        HOMEPAGE_URL "https://example.com/myproject"
        LICENSES MIT)

add_executable(MyExecutable main.cpp)

3 库生成

1. `add_dependencies`相当于gcc中`-l`链接库
2. `target_include_directories、include_directories`相当于gcc中`-I`头文件搜索路径
3. 

3.1 add_executable

  • 功能:使用指定的源文件生成可执行文件。
  • 语法:add_executable(<name> [source1] [source2 ...])
    • <name>:可执行文件名
    • [source1] [source2 ...]:源文件名
  • 示例
add_executable(main main.cc)

3.2 add_library

  • 功能:使用指定的源文件生成库文件。
  • 语法:add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
    • <name>
    • [STATIC | SHARED | MODULE] :STATIC 表示静态库、SHARED 表示动态库、MODULE 是可以被 dlopen 相关函数动态加载的库
    • [EXCLUDE_FROM_ALL]
    • [<source>...]
title: 当不指定库类型时,生成静态库还是动态库,遵循什么规则?
1. 当`BUILD_SHARED_LIBS`变量值为ON时,生成动态库,否则生成静态库
  • 示例:设置 BUILD_SHARED_LIBS 变量值 ON,生成动态库
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
add_library(MathFunctions mysqrt.cxx)

## cmake输出结果(部分)
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
## make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX shared library libMathFunctions.so
  • 示例:生成动态库
add_library(MathFunctions SHARED mysqrt.cxx)

### make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX shared library libMathFunctions.so
  • 示例:生成静态库
add_library(MathFunctions STATIC mysqrt.cxx)

### make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX static library libMathFunctions.a

3.3 add_dependencies

  • 功能:在目标添加一个依赖关系,确保依赖库在目标链接前已经存在,比如生成 main 可执行文件需要链接 liba.so,libb.so,则可以使用 add_dependencies(main a b)
  • 语法:add_dependencies(<target> [<target-dependency>]...)
    • <target>:只能是 add_library、add_executable 指定的目标文件

3.4 add_definitions

  • 功能:添加宏定义
  • 语法 add_definitions(-DFOO -DBAR ...)

3.5 add_compile_definitions

  • 功能:将预处理器定义添加到源文件的编译中
  • 语法:add_compile_definitions(<definition> ...),使用语法 VAR 或 VAR=value 指定定义。

3.6 include_directories

3.7 target_include_directories

title: target_include_directories、include_directories区别?
其中target_include_directories只添加到指定的目标上,而include_directories将给定目录添加到编译器用于搜索包含文件的目录
  • 功能:给指定目标添加 include 文件搜索路径
  • 语法:
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
  • 示例
cmake_minimum_required(VERSION 3.0.0)
project(TESt)

add_executable(main "")
add_subdirectory(common)
target_sources(main PRIVATE main.cc)
target_link_libraries(main mymath)
target_include_directories(main PRIVATE common)

以上项目结构如下 :

[shw@rocky src]$ tree
.
├── CMakeLists.txt
├── common
│   ├── CMakeLists.txt
│   └── math
│       ├── CMakeLists.txt
│       ├── mymath.cc
│       └── mymath.h
├── include
└── main.cc
  • 功能:指定目标文件的依赖库或编译选项(如 -g,-O0
  • 语法:target_link_libraries(<target> ... <item>... ...)
    • <target>:只能是 add_library、add_executable 指定的目标文件
    • <item> :可以有几种格式
      • 库目标名:是 add_library() 中指定的目标
      • 库全路径名:比如 /usr/lib/libfoo.so ,最后解析成 -lfoo
      • plain 库名:比如 foo ,最后解析成 -lfoo or foo.lib
      • 链接选项:比如 -g
      • 生成器表达式
  • 示例
target_link_libraries(ganesha.nfsd
  ganesha_nfsd
  ${LIBTIRPC_LIBRARIES}
  ${SYSTEM_LIBRARIES}
  ${LTTNG_LIBRARIES}
  "-Wl,--no-undefined"
)

3.9 target_sources

  • 功能:给 add_executable() or add_library() or add_custom_target() 指定需要的源文件。
  • 语法:
    • <target> :是 add_executable() or add_library() or add_custom_target() 中的目标名
    • [items1...] :文件列表
target_sources(<target>
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
  • 示例
target_sources(myLib
    PRIVATE
        bar.cpp
        bar.h
        gumby.cpp
        gumby.h
)

3.10 PRIVATE, PUBLIC 和 INTERFACE

这几个关键字用来 控制头文件搜索目录或链接库的可见性 的。 target_include_directories 里面的关键字控制 头文件目录 传递。 target_link_libraries 里的关键字控制 头文件目录 以及 链接库 传递。 - PUBLIC :可将头文件目录以及链接库传递给上层链接库。 - PRIVATE :不可传递头文件目录、链接库给上层链接库。 - INTERFACE :仅传递头文件目录、链接库给上层链接库,但当前目标使不使用。

4 加载其它 CMake 文件

4.1 add_subdirectory

  • 功能:将子目录添加到 cmake 构建树中。
  • 语法:
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
  • 示例
if(USE_GTEST)
  add_subdirectory(gtest)
endif(USE_GTEST)

其中 source_dir 指定了源 CMakeLists.txt 和代码文件所在的目录,可选的 binary_dir 表示的是构建生成二进制文件的位置,如果不指定 binary_dir,则使用 source_dir 作为输出目录

4.2 include

  • 功能:从给定文件 加载并运行 CMake 代码。如果指定了模块而不是文件,则首先在 CMAKE_MODULE_PATH 中搜索名为 <modulename>.cmake 的文件,然后在 cmake 模块目录中搜索。有一个例外:如果调用 include() 的文件本身位于 CMake 内置模块目录中,则首先搜索 CMake 内建模块目录,然后搜索 CMAKE_MODULE_PATH
  • 语法:支持 file|module 这 2 种文件类型
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
                      [NO_POLICY_SCOPE])
  • 示例
# Add maintainer mode for (mainly) strict builds
include(${GANESHA_TOP_CMAKE_DIR}/cmake/maintainer_mode.cmake)

# For libraries that provi

5 执行

5.1 file

  • 功能:该命令专用于需要访问文件系统的文件和路径操作。
  • 语法:
Reading
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])
  file(GET_RUNTIME_DEPENDENCIES [...])

Writing
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])
  file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])

Filesystem
  file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
  file(MAKE_DIRECTORY [<dir>...])
  file({REMOVE | REMOVE_RECURSE } [<files>...])
  file(RENAME <oldname> <newname> [...])
  file(COPY_FILE <oldname> <newname> [...])
  file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
  file(SIZE <filename> <out-var>)
  file(READ_SYMLINK <linkname> <out-var>)
  file(CREATE_LINK <original> <linkname> [...])
  file(CHMOD <files>... <directories>... PERMISSIONS <permissions>... [...])
  file(CHMOD_RECURSE <files>... <directories>... PERMISSIONS <permissions>... [...])

Path Conversion
  file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])
  file(RELATIVE_PATH <out-var> <directory> <file>)
  file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)

Transfer
  file(DOWNLOAD <url> [<file>] [...])
  file(UPLOAD <file> <url> [...])

Locking
  file(LOCK <path> [...])

Archiving
  file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [...])
  file(ARCHIVE_EXTRACT INPUT <archive> [...])
  • 示例
set(NTIRPC_VERSION_HEADER "${NTIRPC_INCLUDE_DIR}/version.h")
if (EXISTS ${NTIRPC_VERSION_HEADER})
    file(READ "${NTIRPC_VERSION_HEADER}" header)
    string(REGEX REPLACE ".*#[ \t]*define[ \t]*NTIRPC_VERSION[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
    set(NTIRPC_VERSION "${match}")
else()
    set(NTIRPC_VERSION "0.0.0")
endif()

5.2 execute_process

  • 功能:执行一个或多个子进程。
  • 语法:
execute_process(COMMAND <cmd1> [<arguments>]
                [COMMAND <cmd2> [<arguments>]]...
                [WORKING_DIRECTORY <directory>]
                [TIMEOUT <seconds>]
                [RESULT_VARIABLE <variable>]
                [RESULTS_VARIABLE <variable>]
                [OUTPUT_VARIABLE <variable>]
                [ERROR_VARIABLE <variable>]
                [INPUT_FILE <file>]
                [OUTPUT_FILE <file>]
                [ERROR_FILE <file>]
                [OUTPUT_QUIET]
                [ERROR_QUIET]
                [COMMAND_ECHO <where>]
                [OUTPUT_STRIP_TRAILING_WHITESPACE]
                [ERROR_STRIP_TRAILING_WHITESPACE]
                [ENCODING <name>]
                [ECHO_OUTPUT_VARIABLE]
                [ECHO_ERROR_VARIABLE]
                [COMMAND_ERROR_IS_FATAL <ANY|LAST>])
  • 示例 1:
cmake_minimum_required(VERSION 3.10)

# 定义一个变量来保存命令的输出
set(OutputVariable "")

# 执行外部命令
execute_process(
    COMMAND echo "Hello, World!"
    OUTPUT_VARIABLE OutputVariable
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

message("Command output: ${OutputVariable}")
  • 示例 2:
execute_process(
    COMMAND g++ --version
    OUTPUT_VARIABLE CompilerVersion
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

message("Compiler version: ${CompilerVersion}")

6 查找文件

1. 以下这些(除find_package)都有默认查找路径,这意味着如果待查找文件存在默认查找路径里面,我们可以不指定查找路径。
2. 以下查找函数(除find_package)语法大部分相同,列举几个:
  1. `<VAR>`  :变量,用来存储查询结果。
  2. `name | NAMES name1 [name2 ...]` :要查找的文件名。
  3. `[HINTS [path | ENV var]... ]` :指定要搜索的目录。
  4. `[PATHS [path | ENV var]... ]` :指定要搜索的目录,同HINTS。
  5. `[PATH_SUFFIXES suffix1 [suffix2 ...]]` :在每个目录位置下指定要检查的其他子目录。

6.1 find_library

  • 功能:查找到库所在路径
  • 语法:
    • <VAR>:是一个变量,用来存储查询结果,如果查询成功则是库的全路径,否则是 <VAR>-NOTFOUNDname1 是查询的库名称,可以是 libnsl.so 或者去除前缀后缀的 nslpath 则表示要搜索库的位置。
    • nameNAMES name1 [name2 ...] :当查找的是一个库时,可以 2 种方式都可以使用,当是一个列表时(表示查找列表种任意一个),需要用 NAMES 修饰。
    • HINTSPATHS :指定要搜索的目录(指定目录没找到还会去默认位置查,除非指定了 NO_DEFAULT_PATH)。ENV var 子选项表示从系统环境变量读取路径。
    • NO_CACHE :结果不存在 cmake 缓存中,而存在普通变量中
    • REQUIRED:如果未找到任何内容,则停止处理并显示一条错误消息
    • NO_DEFAULT_PATH :不从默认路径中搜索
find_library (
          <VAR>
          name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
          [HINTS [path | ENV var]... ]
          [PATHS [path | ENV var]... ]
          [REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
          [PATH_SUFFIXES suffix1 [suffix2 ...]]
          [DOC "cache documentation string"]
          [NO_CACHE]
          [REQUIRED]
          [NO_DEFAULT_PATH]
          [NO_PACKAGE_ROOT_PATH]
          [NO_CMAKE_PATH]
          [NO_CMAKE_ENVIRONMENT_PATH]
          [NO_SYSTEM_ENVIRONMENT_PATH]
          [NO_CMAKE_SYSTEM_PATH]
          [NO_CMAKE_INSTALL_PREFIX]
          [CMAKE_FIND_ROOT_PATH_BOTH |
           ONLY_CMAKE_FIND_ROOT_PATH |
           NO_CMAKE_FIND_ROOT_PATH]
         )
  • 示例 1
set(fuse_names fuse)
find_library(FUSE_LIBRARIES
    NAMES ${fuse_names}
    HINTS ${PKG_FUSE_LIBDIR}
    NO_DEFAULT_PATH)
  • 示例 2
find_library(MY_LIBRARY NAMES my_lib PATHS /usr/lib /usr/local/lib)
if(MY_LIBRARY)
    message("Found library: ${MY_LIBRARY}")
else()
    message(FATAL_ERROR "Library not found")
endif()

6.2 find_program

  • 功能:查找指定的程序
  • 语法:类似 find_library
  • 示例
if(COVERAGE)
    find_program(LCOV_EXEC lcov)
    find_program(GENHTML_EXEC genhtml)
    if(LCOV_EXEC AND GENHTML_EXEC)
        add_custom_target(lcov)
        add_custom_command(TARGET lcov
            COMMAND ${LCOV_EXEC} --capture --directory .
            --output-file coverage.info
            COMMAND ${GENHTML_EXEC} coverage.info
            --output-directory ./coverage_html/
            VERBATIM
            WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
            )
    endif(LCOV_EXEC AND GENHTML_EXEC)
endif(COVERAGE)
  • 示例 2
find_program(MY_COMPILER NAMES gcc g++ clang)
if(MY_COMPILER)
    message("Found compiler: ${MY_COMPILER}")
else()
    message(FATAL_ERROR "Compiler not found")
endif()

6.3 find_file

  • 功能:查找一个文件全路径
  • 语法:类似 find_library
  • 示例
option(WITH_SELINUX "build SELinux policy" OFF)
if(WITH_SELINUX)
  find_file(SELINUX_MAKEFILE selinux/devel/Makefile
    PATH /usr/share)
  if(NOT SELINUX_MAKEFILE)
    message(FATAL_ERROR "Can't find selinux's Makefile")
  endif()
  add_subdirectory(selinux)
endif(WITH_SELINUX)
  • 示例 2
find_file(MY_CONFIG_FILE my_config.conf PATHS /etc /usr/local/etc)
if(MY_CONFIG_FILE)
    message("Found config file: ${MY_CONFIG_FILE}")
else()
    message(FATAL_ERROR "Config file not found")
endif()

6.4 find_path

find_path查找的得到的是**父目录**,而find_file查找得到的是**文件全路径**。
  • 功能:查找指定文件所在目录
  • 语法:find_path(<VAR> name1 [path1 path2 ...])
find_path(  
<VAR>  
name | NAMES name1 [name2 ...]  
[HINTS path1 [path2 ... ENV var]]  
[PATHS path1 [path2 ... ENV var]]  
[PATH_SUFFIXES suffix1 [suffix2 ...]]  
[DOC "cache documentation string"]  
[NO_DEFAULT_PATH]  
[NO_CMAKE_ENVIRONMENT_PATH]  
[NO_CMAKE_PATH])
  • 示例 1
find_path(LIBURCU_INC urcu-bp.h)
if (NOT LIBURCU_INC)
  message(FATAL_ERROR "userspace-rcu includes not found!")
endif(NOT LIBURCU_INC)
  • 示例 2
find_path(MY_HEADER_PATH my_header.h PATHS /usr/include /usr/local/include)
if(MY_HEADER_PATH)
    message("Header file found at: ${MY_HEADER_PATH}")
else()
    message(FATAL_ERROR "Header file not found")
endif()

6.5 find_package

[[ChartGPT-提问#1.3 cmake find_package 的 CONFIG、MODULE 模式]]

`Find<PackageName>.cmake` 设置的普通变量可以被上层调用者使用
  • 功能:找到一个包 (通常由项目外部提供)。
  • 语法:
  • <PackageName> :要查找的包名
  • REQUIRED:用于指定被查找的外部软件包是否是项目的必需部分。当设置为 REQUIRED 时,如果 CMake 找不到指定的软件包,将会产生一个致命错误,导致构建过程中止。如果未设置为 REQUIRED,则找不到软件包时会产生警告,但构建过程会继续。
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
             [GLOBAL]
             [NO_POLICY_SCOPE]
             [BYPASS_PROVIDER])
  • 示例:
# 查找 MyLibrary 软件包,如果找不到将导致构建过程中止
find_package(MyLibrary REQUIRED)

# 使用 MyLibrary 提供的功能继续构建
  • 示例:设置 module 查找路径,然后在此路径下查找 FindToolchain.cmake 文件
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${GANESHA_TOP_CMAKE_DIR}/cmake/modules/")

find_package(Toolchain REQUIRED)

7 功能性命令

7.1 message

在3.17后增加了check功能
  • 功能:输出提示信息
  • 语法:
message([<mode>] "message text" ...)
message(<checkState> "message text" ...)
  • 主要的 mode 有
    • FATAL_ERROR: 错误,会停止执行 cmake 命令
    • WARNING: 警告,继续执行
    • STATUS: 状态信息
  • 新增的 checkState 有以下:
    • CHECK_START:检查记录的开始
    • CHECK_PASS:检查成功信息
    • CHECK_FAIL:检查失败信息
  • 示例
message(CHECK_START "Finding my things")
list(APPEND CMAKE_MESSAGE_INDENT "  ")
unset(missingComponents)

message(CHECK_START "Finding partA")
## ... do check, assume we find A
message(CHECK_PASS "found")

message(CHECK_START "Finding partB")
## ... do check, assume we don't find B
list(APPEND missingComponents B)
message(CHECK_FAIL "not found")

list(POP_BACK CMAKE_MESSAGE_INDENT)
if(missingComponents)
  message(CHECK_FAIL "missing components: ${missingComponents}")
else()
  message(CHECK_PASS "all components found")
endif()
  • 输出
-- Finding my things
--   Finding partA
--   Finding partA - found
--   Finding partB
--   Finding partB - not found
-- Finding my things - missing components: B

7.2 set

  • 功能:给变量设置值
  • 语法:
    • 设置普通变量:set(<variable> <value>... [PARENT_SCOPE])
    • 设置 Cache Entry:set(<variable> <value>... CACHE <type> <docstring> [FORCE])
    • 设置 ENV 变量:set(ENV{<variable>} [<value>])
  • 示例
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
message(STATUS "CC=$ENV{CC}")
set(ENV{CC} g++)
message(STATUS "CC=$ENV{CC}")
  • 输出
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
-- CC=
-- CC=g++
-- Configuring done
-- Generating done

7.3 string

- 内容较多,参考[官方文档](https://cmake.org/cmake/help/latest/command/string.html#string)
  • 功能:字符串操作,包括查找、替换、比较等
  • 语法:
Search and Replace
  string(FIND <string> <substring> <out-var> [...])
  string(REPLACE <match-string> <replace-string> <out-var> <input>...)
  string(REGEX MATCH <match-regex> <out-var> <input>...)
  string(REGEX MATCHALL <match-regex> <out-var> <input>...)
  string(REGEX REPLACE <match-regex> <replace-expr> <out-var> <input>...)

Manipulation
  string(APPEND <string-var> [<input>...])
  string(PREPEND <string-var> [<input>...])
  string(CONCAT <out-var> [<input>...])
  string(JOIN <glue> <out-var> [<input>...])
  string(TOLOWER <string> <out-var>)
  string(TOUPPER <string> <out-var>)
  string(LENGTH <string> <out-var>)
  string(SUBSTRING <string> <begin> <length> <out-var>)
  string(STRIP <string> <out-var>)
  string(GENEX_STRIP <string> <out-var>)
  string(REPEAT <string> <count> <out-var>)

Comparison
  string(COMPARE <op> <string1> <string2> <out-var>)

Hashing
  string(<HASH> <out-var> <input>)

Generation
  string(ASCII <number>... <out-var>)
  string(HEX <string> <out-var>)
  string(CONFIGURE <string> <out-var> [...])
  string(MAKE_C_IDENTIFIER <string> <out-var>)
  string(RANDOM [<option>...] <out-var>)
  string(TIMESTAMP <out-var> [<format string>] [UTC])
  string(UUID <out-var> ...)

JSON
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         {GET | TYPE | LENGTH | REMOVE}
         <json-string> <member|index> [<member|index> ...])
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         MEMBER <json-string>
         [<member|index> ...] <index>)
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         SET <json-string>
         <member|index> [<member|index> ...] <value>)
  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
         EQUAL <json-string1> <json-string2>)
  • 示例
  string(REPLACE
    "\"" ""
    LSB_RELEASE_DESCRIPTION_SHORT
    "${LSB_RELEASE_DESCRIPTION_SHORT}")

7.4 list

- 内容较多,参考[官方文档](https://cmake.org/cmake/help/latest/command/list.html#list)
  • 功能:列表操作
  • 语法:其中最常用的是 APPEND,向列表追加内容
Reading
  list(LENGTH <list> <out-var>)
  list(GET <list> <element index> [<index> ...] <out-var>)
  list(JOIN <list> <glue> <out-var>)
  list(SUBLIST <list> <begin> <length> <out-var>)

Search
  list(FIND <list> <value> <out-var>)

Modification
  list(APPEND <list> [<element>...])
  list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)
  list(INSERT <list> <index> [<element>...])
  list(POP_BACK <list> [<out-var>...])
  list(POP_FRONT <list> [<out-var>...])
  list(PREPEND <list> [<element>...])
  list(REMOVE_ITEM <list> <value>...)
  list(REMOVE_AT <list> <index>...)
  list(REMOVE_DUPLICATES <list>)
  list(TRANSFORM <list> <ACTION> [...])

Ordering
  list(REVERSE <list>)
  list(SORT <list> [...])
  • 示例
list(FIND _optionNames "${currentArg}" optionIndex) 

8 条件、循环

8.1 option

  • 功能:提供用户可以选择的布尔选项。通常和 if 条件语句配合使用,可选择的执行命令
  • 语法:option(<variable> "<help_text>" [value])
    • <variable> :选项的变量名
    • "<help_text>":针对选项的帮助信息
    • [value]:默认是 OFF,表示选项关闭,ON 表示选项打开
  • 示例
option(OPENMESSAGE "是否执行信息输出" OFF)
if(OPENMESSAGE)
message(STATUS "condition 1")
else()
message(STATUS "condition 2")
endif()
  • 输出:cmake .
$ cmake .
-- condition 2
  • 输出: cmake -DOPENMESSAGE=ON .
$ cmake -DOPENMESSAGE=ON .
-- condition 1

8.2 if

- 详细教程参考[官方文档](https://cmake.org/cmake/help/latest/command/if.html)
  • 功能:有条件地执行一组命令。
  • 语法:
if(<condition>)
  <commands>
elseif(<condition>) ## optional block, can be repeated
  <commands>
else()              ## optional block
  <commands>
endif([<condition>]) ## 如果指定<condition>,就必须和if块的保持一致
  • 示例
option(OPENMESSAGE "是否执行信息输出" OFF)
if(OPENMESSAGE)
message(STATUS "condition 1")
else()
message(STATUS "condition 2")
endif(OPENMESSAGE)

8.3 foreach

8.4 while

  • 功能:
  • 语法:
while(<condition>)
  <commands>
endwhile()
  • 示例
while(NOT EXISTS "${GIT_DIR}")  # .git dir not found, search parent directories
    set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
    get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
    if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
        # We have reached the root directory, we are not in git
        set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
        set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
        return()
    endif()
    set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()

9 属性

[[ChartGPT-提问#1.4 cmake 属性]]

9.1 set_property

set_property 是 CMake 中用于设置属性的函数,它可以用来修改项目中的各种属性,包括目标属性、文件属性、目录属性等。以下是一些常见的示例,演示了如何使用 set_property 函数来设置不同类型的属性:

设置目标属性示例:

# 定义一个可执行目标
add_executable(MyExecutable main.cpp)

# 设置可执行目标的属性
set_property(TARGET MyExecutable PROPERTY CXX_STANDARD 17)
set_property(TARGET MyExecutable PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET MyExecutable PROPERTY CXX_EXTENSIONS OFF)

在这个示例中,我们定义了一个名为 MyExecutable 的可执行目标,并使用 set_property 函数来设置该目标的属性,包括 C++ 标准、是否需要指定标准以及是否启用标准的扩展。

设置文件属性示例:

# 设置文件属性
set_property(SOURCE myfile.cpp PROPERTY COMPILE_DEFINITIONS MY_DEFINITION)
set_property(SOURCE myfile.cpp PROPERTY COMPILE_OPTIONS -Wall)

在这个示例中,我们使用 set_property 函数来为名为 myfile.cpp 的源文件设置属性,包括编译定义和编译选项。

设置目录属性示例:

# 设置目录属性
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/include)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY LINK_DIRECTORIES ${CMAKE_BINARY_DIR}/lib)

这个示例展示了如何使用 set_property 函数来为特定目录设置属性,包括包含目录和链接目录。

请注意,set_property 函数的具体用法可能会根据你的项目结构和需求而有所不同。你可以根据自己的需要在 CMake 脚本中使用 set_property 来设置各种属性,以控制构建过程和生成的目标。 设置缓存变量示例:

macro (goption OPTNAME DESC DEFVAL)
  set(${OPTNAME} DEFAULT_${DEFVAL} CACHE STRING "${DESC}")
  set_property(CACHE ${OPTNAME} PROPERTY STRINGS ON OFF)
endmacro()

9.2 get_property

在 CMake 中,你可以使用 get_property 函数来获取特定目标、文件或目录的属性值。

获取目标属性示例:

# 定义一个可执行目标
add_executable(MyExecutable main.cpp)

# 获取目标的属性值
get_property(executable_std TARGET MyExecutable PROPERTY CXX_STANDARD)
message("C++ standard for MyExecutable: ${executable_std}")

在这个示例中,我们首先定义了一个名为 MyExecutable 的可执行目标,然后使用 get_property 函数来获取该目标的 C++ 标准属性,并将其存储在变量 executable_std 中。最后,我们使用 message 命令来输出该属性的值。

获取文件属性示例:

# 获取文件的属性值
get_property(file_compile_defs SOURCE myfile.cpp PROPERTY COMPILE_DEFINITIONS)
message("Compile definitions for myfile.cpp: ${file_compile_defs}")

在这个示例中,我们使用 get_property 函数来获取名为 myfile.cpp 的源文件的编译定义属性,并将其存储在变量 file_compile_defs 中,然后使用 message 命令来输出该属性的值。

获取目录属性示例:

# 获取目录的属性值
get_property(dir_includes DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
message("Include directories for ${CMAKE_SOURCE_DIR}: ${dir_includes}")

在这个示例中,我们使用 get_property 函数来获取 ${CMAKE_SOURCE_DIR} 目录的包含目录属性,并将其存储在变量 dir_includes 中,然后使用 message 命令来输出该属性的值。

总之,get_property 函数允许你查询目标、文件或目录的属性值,以便在 CMake 脚本中获取这些属性并进行进一步的处理。

10 函数

在 CMake 中,函数(function)是一种用于定义可重用代码块的机制,类似于编程语言中的函数。你可以在 CMake 脚本中定义函数,然后在需要的地方调用这些函数。函数可以带有参数,执行一系列操作,并且可以返回结果。

以下是一个使用 CMake 函数的示例:

# 定义一个函数
function(MyFunction arg1 arg2)
    message("Function called with arguments: ${arg1}, ${arg2}")

    # 在函数内部进行操作
    add_executable(${arg1} ${arg2})

    # 可以在函数中使用 return() 返回结果,但在函数内部并不常用
endfunction()

# 调用函数
MyFunction(MyExecutable main.cpp)

在这个示例中,我们定义了一个名为 MyFunction 的函数,它接受两个参数 arg1arg2。函数内部我们使用这些参数创建了一个可执行目标。然后我们在代码的其他地方调用了这个函数,并传递了相应的参数。

需要注意的是,CMake 中的函数在某些方面与传统编程语言中的函数不同。例如,CMake 中的函数是在它们被调用的地方展开的,而不是在定义的地方。这意味着你可以在任何地方定义函数,然后在其他地方调用它们。另外,CMake 中的函数没有严格的返回值,尽管你可以使用 return() 语句返回结果,但在函数内部并不常用。

总之,CMake 中的函数允许你创建可重用的代码块,带有参数和操作。通过定义和调用函数,你可以使 CMake 脚本更加模块化和易于维护。

10.1 function

  • 功能:定义一个函数,可以被调用。
  • 语法:
function(<name> [<arg1> ...])
  <commands>
endfunction()

其中 <name> 表示函数名称,<arg1> 表示函数参数,<commands> 是函数体,最后的 endfunction() 是函数结束标志。

定义为:

function(foo)
  <commands>
endfunction()

函数调用不区分大小写。可以以下任一种方式调用:

foo()
Foo()
FOO()
cmake_language(CALL foo)

10.2 endfunction

  • 功能:配合 function 使用,表示函数结束。
  • 语法:
endfunction([<name>])

其中 <name> 是可选的,如果要写,必须和 function 中的 <name> 一致。

10.3 示例

当使用 CMake 进行项目构建时,有许多常见的用例可以通过函数来实现。以下是一些常用的 CMake 函数示例:

  1. 创建库:
function(CreateLibrary name sources)
    add_library(${name} ${sources})
endfunction()

CreateLibrary(MyLibrary source1.cpp source2.cpp)

这个函数用于创建一个库,可以传递库的名称和源文件列表作为参数。

  1. 创建可执行目标:
function(CreateExecutable name sources)
    add_executable(${name} ${sources})
endfunction()

CreateExecutable(MyExecutable main.cpp utility.cpp)

这个函数用于创建一个可执行目标,可以传递可执行目标的名称和源文件列表作为参数。

  1. 设置编译选项:
function(SetCompilerOptions target)
    target_compile_options(${target} PRIVATE -Wall -Wextra)
endfunction()

CreateExecutable(MyExecutable main.cpp utility.cpp)
SetCompilerOptions(MyExecutable)

这个函数用于设置目标的编译选项,将选项应用于特定的目标。

  1. 安装文件:
function(InstallFiles target)
    install(TARGETS ${target} DESTINATION bin)
endfunction()

CreateExecutable(MyExecutable main.cpp utility.cpp)
InstallFiles(MyExecutable)

这个函数用于在构建完成后安装目标文件到指定的目录。

  1. 条件判断和生成:
function(ConditionalBuild condition target)
    if(${condition})
        add_executable(${target} main.cpp)
    endif()
endfunction()

set(BuildEnabled TRUE)
ConditionalBuild(BuildEnabled MyExecutable)

这个函数根据条件来决定是否构建目标。

这些只是一些基本示例,你可以根据项目的需求定义更复杂的函数,用来处理更多的构建和配置任务。函数可以帮助你在 CMake 脚本中模块化代码,并提高代码的可维护性和重用性。

11 宏

宏是一种展开形式,不能返回结果,这是和函数的区别。

11.1 宏定义

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

解释: - ·marco() :宏开始标记 - endmacro() :宏结束标记 - name :宏名称 - arg :宏的参数名,可选,任意数量 - commands :此宏执行的操作,可以使用参数名或者 ${ARGN} 获取参数或列表,见下面示例。

11.2 宏调用

## 定义foo宏
macro(foo)
  <commands>
endmacro()

## 如下4种方式调用
foo()
Foo()
FOO()
cmake_language(CALL foo)

11.2.1 示例 1

## 定义goption,相比cmake原生option,设置了默认值
macro (goption OPTNAME DESC DEFVAL)
  set(${OPTNAME} DEFAULT_${DEFVAL} CACHE STRING "${DESC}")
  set_property(CACHE ${OPTNAME} PROPERTY STRINGS ON OFF)
endmacro()

## 使用
goption(USE_CAPS "Enable capability management" ON)

11.2.2 示例 2

# 定义一个带有特定参数名和可变参数的宏
macro(MyMacroWithNamedArgs first_arg)
    message("Macro has been called.")
    message("Named argument: ${first_arg}")
    message("Variadic arguments passed to the macro: ${ARGN}")

    # 在这里可以对参数进行处理和操作
endmacro()

# 调用宏并传递参数
MyMacroWithNamedArgs("hello" arg1 arg2 arg3)

在上面的示例中,宏 MyMacroWithNamedArgs 接受一个特定的参数 first_arg,以及可变参数 ${ARGN}。在调用宏时,你需要先传递特定的参数,然后在后面传递可变参数。

12 变量

[[ChartGPT-提问#1.1 cmake 有哪几种变量]] [[ChartGPT-提问#1.2 cmake 变量继承规则]]

title: cmake中变量有4种类型
1. Normal Variable(普通变量):局部作用域。
2. Environment Variable(环境变量):如`CC、CFLAGS、CMAKE_PREFIX_PATH`等,全局作用域。
3. Cache Entry(缓存条目):保存在CMakeCache.txt文件中,可以被子cmakelist文件中继承。
4. Built-in Variables(内置变量):如`CMAKE_SOURCE_DIR`、`CMAKE_BINARY_DIR`等,全局作用域。

12.1 变量值获取

  • 普通变量:${variable}
  • 环境变量:$ENV{variable}

12.2 变量值设置

设置变量的方式有3种,可以通过以下命令设置
1. set
2. string
3. list
---
示例如下:
Strings using `set()`:
- `set(MyString "Some Text")`
- `set(MyStringWithVar "Some other Text: ${MyString}")`
- `set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")`

Or with `string()`:
- `string(APPEND MyStringWithContent " ${MyString}")`

Lists using `set()`:
- `set(MyList "a" "b" "c")`
- `set(MyList ${MyList} "d")`

Or better with `list()`:
- `list(APPEND MyList "a" "b" "c")`
- `list(APPEND MyList "d")`
  • 普通变量:set(<variable> [<value>])
  • 环境变量:set(ENV{<variable>} [<value>])
  • 示例
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
message(STATUS "CC=$ENV{CC}")
set(ENV{CC} g++)
message(STATUS "CC=$ENV{CC}")
add_library(MathFunctions mysqrt.cxx)

### cmake输出结果(部分)
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
-- CC=/usr/bin/cc
-- CC=g++

12.3 内置变量

  • CMAKE_CURRENT_SOURCE_DIR :当前正在处理的源目录的路径。(即当前执行 CMakeLists.txt 文件所在目录)
  • CMAKE_SOURCE_DIR :源树顶层的路径。(即 cmake 最先解析的 CMakeLists.txt 所在目录)

12.3.1 路径相关变量

在 CMakeLists.txt 文件中,你可以使用一些内置变量来引用文件和目录的信息。这些变量可用于设置构建过程、安装路径、包含路径等。以下是一些常用的关于文件和目录的内置变量:

  1. CMAKE_SOURCE_DIR:项目的顶级源代码目录的绝对路径。
  2. CMAKE_BINARY_DIR:构建目录的绝对路径。
  3. CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 文件所在的源代码目录的绝对路径。
  4. CMAKE_CURRENT_BINARY_DIR:当前处理的 CMakeLists.txt 文件所在的构建目录的绝对路径。
  5. CMAKE_CURRENT_LIST_DIR:当前处理的 CMakeLists.txt 文件所在的目录的绝对路径。
  6. CMAKE_CURRENT_LIST_FILE:当前处理的 CMakeLists.txt 文件的完整路径。
  7. CMAKE_CURRENT_LIST_LINE:当前处理的 CMakeLists.txt 文件中的行号。
  8. PROJECT_SOURCE_DIR:整个项目的顶级源代码目录的绝对路径。通常与 CMAKE_SOURCE_DIR 相同,但在使用 project() 命令定义项目时,可能会有所不同。
  9. PROJECT_BINARY_DIR:整个项目的构建目录的绝对路径。通常与 CMAKE_BINARY_DIR 相同,但在使用 project() 命令定义项目时,可能会有所不同。
  10. CMAKE_CURRENT_FUNCTION_LIST_DIR:正在执行的函数(包括宏和命令)的列表文件的目录。
  11. CMAKE_MODULE_PATH:指定查找 CMake 模块(FindXXX.cmake)的路径。

这些内置变量使得在 CMake 脚本中引用文件和目录变得更加方便。你可以使用它们来设置路径、定义目标、包含文件等等。

13 generator expression

生成器表达式在生成系统期间求值,以生成特定于每个生成配置的信息。如下

target_include_directories(tgt PRIVATE /opt/include/$<CXX_COMPILER_ID>)

这将扩展到 /opt/include/GNU/opt/include/Clang 等,具体取决于使用的 C++ 编译器。

14 configure_file

  • 功能:将文件复制到其他位置并修改其引用的变量内容。
  • 语法:
    configure_file(input_file 
      output_file 
      [COPYONLY] 
      [ESCAPE_QUOTES] 
      [@ONLY] 
      [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF]] 
      [FATAL_ERROR]
    )
    
  • input_file:要复制和配置的源文件路径。
  • output_file:生成的目标文件的路径。
  • COPYONLY:可选参数,如果指定了此参数,则只复制文件,不进行变量替换。
  • ESCAPE_QUOTES:可选参数,如果指定了此参数,则会对变量值中的引号进行转义。
  • @ONLY:可选参数,如果指定了此参数,则只会替换 @ 符号引导的变量,而不会替换 ${} 形式的变量。
  • NEWLINE_STYLE:可选参数,用于指定生成文件的换行符风格。可以选择 UNIXDOSWIN32LFCRLF
  • FATAL_ERROR:可选参数,如果找不到输入文件并且未提供 COPYONLY,则会生成致命错误。

下面是一个使用示例:

假设我们有一个配置文件 config.h.in,其中包含一个变量 ${VERSION} 需要在构建时进行替换:

// config.h.in
#ifndef CONFIG_H
#define CONFIG_H

#define VERSION "${VERSION}"

#endif

然后,在 CMakeLists.txt 中使用 configure_file 指令来生成最终的配置文件 config.h

# CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(ConfigExample)

set(VERSION "1.0.0")

configure_file(config.h.in config.h)

add_executable(my_app main.cpp)

在这个示例中,当运行 CMake 时,会生成一个名为 config.h 的文件,其中 ${VERSION} 会被替换为 "1.0.0"。然后,这个生成的文件可以在代码中包含并使用。

请注意,这只是一个简单的示例,实际中可能还需要处理更复杂的配置。configure_file 的主要用途是在构建过程中生成可执行文件所需的配置文件,从而使代码能够与所需的环境进行交互。

14.1 cmakedefine 规则

`#cmakedefine`具有if条件判断能力;
1. 当 VAR 真时,转为为`/* #undef VAR */`;
2. 当 VAR 假时,转为`#define VAR ...`;
  • 语法:#cmakedefine VAR ...,其中...可选

如下示例: foo. h.in 文件内容如下

#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "@FOO_STRING@"
CMakeLists.txt文件如下
option(FOO_ENABLE "Enable Foo" ON)
if(FOO_ENABLE)
  set(FOO_STRING "foo")
endif()
configure_file(foo.h.in foo.h @ONLY)
那么会生成 foo. h 如下
#define FOO_ENABLE
#define FOO_STRING "foo"
如果 FOO_ENABLE 是 OFF,那么生成 foo. h 如下
/* #undef FOO_ENABLE */
/* #undef FOO_STRING */

14.2 变量替换

在 config 文件中可以通过这几种方式访问 cmake 变量,@VAR@${VAR}$CACHE{VAR} or $ENV{VAR}

15 其它

15.1 mark_as_advanced

mark_as_advanced 是 CMake 中的一个函数,用于将一个或多个变量标记为高级选项(advanced option)。在 CMake 中,高级选项是指那些通常由高级用户或开发人员使用,而不是由一般用户直接操作的选项。标记一个变量为高级选项后,它会在 CMake 的图形界面工具中被隐藏,从而避免一般用户进行意外的更改。这可以防止不了解内部工作的用户修改某些可能会影响构建的重要选项。

语法如下:

mark_as_advanced(FORCE|CLEAR) variable1 [variable2 ...]
  • FORCE: 将指定的变量标记为高级选项。
  • CLEAR: 取消指定的变量的高级选项标记。

以下是一个示例,演示了如何使用 mark_as_advanced 函数来标记变量为高级选项:

# 定义一个变量
set(MY_OPTION "default_value")

# 将变量标记为高级选项
mark_as_advanced(MY_OPTION)

在上面的示例中,我们定义了一个名为 MY_OPTION 的变量,并使用 mark_as_advanced 函数将它标记为高级选项。这将使得该变量在 CMake 的图形界面工具中被隐藏,只有那些知道如何在 CMake 脚本中设置变量的高级用户才能访问和修改它。

需要注意的是,虽然 mark_as_advanced 可以用于隐藏变量,但并不是绝对安全的措施。有些用户仍然可以通过编辑 CMake 缓存文件来查看和修改被标记为高级选项的变量。因此,在使用 mark_as_advanced 时,需要确保仍然进行适当的文档和沟通,以确保只有了解内部工作原理的人才会更改这些变量。

15.2 cmake 中怎么设置库的版本号

在 CMake 中,你可以使用 VERSION 参数来设置库的版本号。通过在 add_library 命令中使用 VERSION 参数,你可以为库指定一个版本号。在使用 set_target_properties 命令设置库的版本属性时,通常使用的版本相关属性包括:

  1. VERSION:指定库的主版本号。这是一个整数,表示 API 发生重大变化时增加的版本号。
  2. SOVERSION:指定库的共享对象(动态库)的次版本号。这是一个整数,通常在保持向后兼容性的情况下增加。
  3. INTERFACE_VERSION:用于头文件版本控制。在 CMake 3.21 及更高版本中引入。这是一个整数,表示库的头文件 API 的版本。

以下是一个示例,展示如何在 CMake 中使用 set_target_properties 来设置库的版本属性:

# 定义一个共享库并设置版本属性
add_library(MySharedLibrary SHARED my_source.cpp)

# 设置主版本号和次版本号
set_target_properties(MySharedLibrary PROPERTIES
    VERSION 1.2
    SOVERSION 1
)

# 设置头文件 API 的版本
target_include_directories(MySharedLibrary
    INTERFACE
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
set_target_properties(MySharedLibrary PROPERTIES INTERFACE_VERSION 1)

在这个示例中,我们定义了一个共享库 MySharedLibrary 并使用 set_target_properties 设置了主版本号为 1.2,次版本号为 1,以及接口版本号为 1。接口版本号在 target_include_directories 中设置,用于版本化头文件的路径。

注意事项:

  • 如果你的项目中有多个目标,你可以针对每个目标使用 set_target_properties 命令来设置版本号。
  • 版本号的格式通常遵循 <major>.<minor>.<patch> 格式,其中 <major> 表示主版本号,<minor> 表示次版本号,<patch> 表示修订版本号。

在使用库的项目中,你可以使用 target_link_libraries 命令来链接到特定版本的库。例如:

# 链接到指定版本的库
target_link_libraries(MyExecutable PRIVATE MySharedLibrary)

这样,在链接库时,CMake 会根据设置的库版本号来决定链接到哪个版本的库文件。 通过设置库的版本号,你可以为项目的库提供明确的版本信息,使其在构建和部署过程中更加清晰和可管理。