CMake所学

news2024/10/2 19:16:00

向大佬lyf学习,先把其8服务器中所授fine

文章目录

  • 前言
  • 一、CMakeList.txt 命令
    • 1.1 最外层CMakeLists
      • 1.1.1 cmake_minimum_required()
      • 1.1.2 project()
      • 1.1.3 set()
      • 1.1.4 add_subdirectory()
    • 1.2. 内层CMakeLists
      • 1.2.1 开头几行的重复
      • 1.2.2 find_package()
      • 1.2.3 find_path()
      • 1.2.4 file()
      • 1.2.5 add_library()
      • 1.2.6 target_include_directories()
      • 1.2.7 set_target_properties()
      • 1.2.8 install()命令
      • 1.2.9 target_link_libraries
  • 二、clangd 如何使用 compile_commands.json
    • 2.1 compile_commands.json
    • 2.2 clangd利用compile_commands.json
  • 三、静态库和动态库
    • 3.1 静态库(Static Library)
    • 3.2 动态库(Shared Library 或 Dynamic Library)
  • 四、targets(目标)的类型
    • 4.1 可执行文件(Executable Target)
    • 4.2 静态库(Static Library Target)
    • 4.3 动态库(Shared Library Target)
    • 4.4 模块库(Module Library Target)
    • 4.5 接口库(Interface Library Target)
    • 4.6 自定义目标(Custom Target)
    • 4.7 导入目标(Imported Target)
    • 4.8 外部目标(External Project Target)
    • 4.9 ALIAS 目标
    • 4.10 OBJECT 库目标(Object Library Target)
    • 4.11 UTILITY 目标
  • 总结


前言

不能光写代码,也需要提升宏观的工程能力,
还是那句话,深度。


一、CMakeList.txt 命令

1.1 最外层CMakeLists

1.1.1 cmake_minimum_required()

指定项目所需的 CMake 最低版本。如果当前 CMake 版本低于指定版本,CMake 会发出错误并停止配置过程。
通过指定最低版本,可以确保项目使用的 CMake 功能和特性在该版本中可用,从而避免因版本不兼容而导致的问题。

1.1.2 project()

定义一个项目的名称和相关信息
project() 命令会生成一些有用的变量,如:
PROJECT_NAME: 项目名称。
PROJECT_SOURCE_DIR: 项目源代码的根目录。
PROJECT_BINARY_DIR: 项目构建目录。

1.1.3 set()

用于为 CMake 脚本中的变量赋值,可以为 CMake 自带的变量(如 CMAKE_CXX_FLAGS_DEBUG、CMAKE_BUILD_TYPE)或用户自定义的变量赋值

典型的用法是 set(变量名 值),通过这种方式将某个值赋给 CMake 中的某个变量。

set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -DDEBUG")

如此处,是将"$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -DDEBUG"赋给CMAKE_CXX_FLAGS_DEBUG ,CMAKE_CXX_FLAGS_DEBUG 是CMake内部变量,是 CMake 提供的一个预定义变量,它专门用于存储在 Debug 构建类型 下(即 CMAKE_BUILD_TYPE 设置为 Debug 时)的编译器选项

ENV是系统环境变量,在linux中可以通过printenv来查看env信息,如果 $ ENV{CXXFLAGS}没找到CXXFLAGS的话,就会返回空字符串从而直接将-O0 -Wall -g -ggdb -DDEBUG赋给CMAKE_CXX_FLAGS_DEBUG
这句话在 CMake 中的作用是为 C++ 编译器设置在 Debug 模式下的编译标志
“$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -DDEBUG”:

  • $ENV{CXXFLAGS}:这是 CMake 语法,用于从操作系统的环境变量 CXXFLAGS 中读取值。如果 CXXFLAGS 存在,它的值会被插入到这个位置;如果不存在,这部分将为空。
  • -O0:关闭优化。Debug 模式下,编译器不会优化代码,这样可以让代码结构尽量保持原样,以便调试。
  • -Wall:启用所有常规警告。编译器会输出所有常见的潜在问题警告,帮助开发者发现代码中的潜在错误。
  • -g:生成调试信息。这会让编译器在生成的可执行文件中包含调试符号,以便在调试器(如 GDB)中使用。
  • -ggdb:为 GDB 调试器生成更多的调试信息,优化调试体验。
    -DDEBUG:定义 DEBUG 宏。在代码中,可能会有一些只在 Debug 模式下执行的代码,通过 #ifdef DEBUG 进行条件编译,这个宏可以帮助启用这些代码块。

1.1.4 add_subdirectory()

add_subdirectory(src) 是 CMake 中的一个命令,用于将指定的子目录(这里是 src 目录)添加到当前 CMake 项目中。CMake 会递归地处理该子目录中的 CMakeLists.txt 文件,并将该目录中的构建目标、编译选项等内容合并到主项目中

1.2. 内层CMakeLists

1.2.1 开头几行的重复

内存CMakeLists.txt中开头几行,一般会有与外层开始几行一样或者类似的重复,如下:
在这里插入图片描述
在这里插入图片描述

  • cmake_minimum_required 的重复
    目的:每个 CMakeLists.txt 文件都应该有一个 cmake_minimum_required() 调用,哪怕在父目录已经调用过。其目的是确保每个独立的 CMakeLists 文件都知道需要的最低版本。
    独立性:虽然项目是从外层的 CMakeLists.txt 开始构建的,但 CMake 是递归处理 add_subdirectory() 中的子目录。每个 CMakeLists.txt 文件都是相对独立的模块,有可能在不同上下文中单独运行。例如,如果你单独运行 src 目录中的 CMakeLists 文件(例如开发中测试子模块时),cmake_minimum_required() 能确保它使用的是正确版本的 CMake。

  • project() 的重复
    项目分层管理:尽管外层的 CMakeLists 文件已经定义了项目名称和相关配置,但每个子目录可能被视为一个独立的逻辑模块,尤其是当项目复杂时。通过在 src 目录的 CMakeLists 文件中定义自己的 project(),可以给该子目录赋予自己的版本号和名称。这在大型项目中有助于管理不同子模块的独立性。
    版本号独立性:project() 定义的项目版本号可以在不同模块中有所区别。例如,外层的项目可能有一个总版本号,而内部的子模块(如 CUDA-GEMM-Algorithms)可以有独立的版本号,方便模块化管理。
    语言设置:LANGUAGES CXX CUDA 的定义也需要在每个 CMakeLists.txt 中明确指定,因为不同的子模块可能使用不同的语言。虽然你的项目同时支持 C++ 和 CUDA,但其他项目或子模块可能会使用不同的语言设置。

  • set(CMAKE_CXX_STANDARD 17) 的重复
    确保一致性:对于每个 CMakeLists.txt 文件中明确指定 C++ 标准(如 C++17),可以确保即使子目录的 CMakeLists 在不同的环境下被单独使用,依然会遵循相同的标准。尽管顶层 CMakeLists 中已经指定了 C++17 标准,但每个子模块如果有自己的设置,就可以防止标准的遗失或错误继承。
    防止未来修改:如果你不在子目录的 CMakeLists 中显式设置 CMAKE_CXX_STANDARD,顶层的设置有可能在某些复杂的构建配置中被覆盖或丢失。为了确保子目录构建时依然使用正确的 C++ 标准,最好在每个模块中都显式设置。

独立构建支持:有些项目希望支持在不同目录下独立构建子模块。比如你可能只想单独编译 src 目录下的内容,而不是整个项目。通过在子目录中定义 cmake_minimum_required、project() 和其他配置,你可以独立构建和测试这个子模块,而不依赖于外层的 CMakeLists.txt。
模块化开发:在模块化开发的场景中,不同模块可以由不同的开发团队或个人维护,甚至单独发布。为了确保每个模块都能独立运行和测试,重复这些命令可以确保一致性和模块化开发的独立性。

1.2.2 find_package()

find_package(CUDAToolkit REQUIRED)
REQUIRED:这个关键字告诉 CMake,如果找不到指定的包,构建过程应当立即停止并报错。
如果不加 REQUIRED,CMake 会继续执行,但 CUDAToolkit_FOUND 变量将被设置为 FALSE,你可以在脚本中自己处理找不到包的情况。
如果加上 REQUIRED,则找不到包时,CMake 将会自动停止并抛出错误信息,提示 CUDA 工具包是必需的,无法继续构建。

find_package查找方法有四层路径:
1.系统路径,CMake 会根据操作系统的标准路径查找。(在 Linux 中,默认查找 /usr/local/cuda、/usr/local/lib 等目录。
在 Windows 中,默认查找 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA。)
2.环境变量,CMake 也会检查以下环境变量:CUDA_PATH:NVIDIA 通常会将 CUDA 安装路径设置为 CUDA_PATH 环境变量。CMake 会读取这个变量以查找 CUDA 工具包的安装路径。PATH、LD_LIBRARY_PATH、CMAKE_PREFIX_PATH:这些变量可能包含与 CUDA 相关的路径。
3.CMake 模块路径:CMake 可能会在 CMAKE_MODULE_PATH 或 CMAKE_PREFIX_PATH 中指定的路径下查找 CUDAToolkit。
4.NVIDIA 提供的配置文件:CMake 会使用 CUDAToolkitConfig.cmake 文件,这是 NVIDIA 提供的官方配置文件,用于帮助 CMake 定位 CUDA 工具包。

find_package()找到包之后会加载包的配置(注意,不是加载包,只是其配置)
通过加载包的配置,而将包的路径、库、头文件等信息存储到一些CMake变量中。
可以通过以target_link_libraries(my_target PRIVATE ${CUDAToolkit_LIBRARIES})等方式直接引用这些变量

同时find_package()也会通过加载包的配置而自动导入一些常用的目标(不是所有,如果你要用的没有被导入,需要手动引入,而不能直接target_link_lib…)

1.2.3 find_path()

find_path() 是 CMake 中的一个命令,专门用于查找指定文件的路径,通常用于查找头文件的包含目录。它会在系统中搜索某个特定的路径,找到指定的文件,然后将该文件所在的目录路径存储到一个 CMake 变量中,以便后续使用
示例:

find_path(CUDA_GEMM_INCLUDE_DIRS cuda_gemm_utils.hpp HINTS ${CMAKE_SOURCE_DIR}/include)

此中含义是
在${CMAKE_SOURCE_DIR}/include里面查找cuda_gemm_utils.hpp文件,若找到,则将文件的目录路径存储到CUDA_GEMM_INCLUDE_DIRS (是一个自定义的CMake变量)中。

find_path()(动态查找判断并赋值)相当于set()(静态赋值)的增强版本,在赋值之前多了一个查找和验证的逻辑,并且存入的不是后面的字符串,而是找到文件的目录路径。

1.2.4 file()

file(GLOB …) 是 CMake 中用于文件查找和模式匹配的命令,它可以根据给定的文件模式来查找匹配的文件,并将匹配的文件列表存储在变量中。

file(GLOB CUDA_GEMM_HEADERS ${CMAKE_SOURCE_DIR}/include/*.hpp ${CMAKE_SOURCE_DIR}/include/*.cuh)
  • file(GLOB CUDA_GEMM_HEADERS …):
    file(GLOB …) 命令用于查找符合条件的文件,并将结果存储在变量 CUDA_GEMM_HEADERS 中。
    CUDA_GEMM_HEADERS 是自定义的变量名,用来存储查找到的文件列表。

  • ${CMAKE_SOURCE_DIR}/include/* .hpp 和 ${CMAKE_SOURCE_DIR}/include/* .cuh:
    GLOB 的第二个参数是文件模式,在这里指定了两个文件模式:
    ${CMAKE_SOURCE_DIR}/include/* .hpp:表示查找项目根目录下 include 文件夹中所有以 .hpp 结尾的头文件。
    ${CMAKE_SOURCE_DIR}/include/* .cuh:表示查找项目根目录下 include 文件夹中所有以 .cuh 结尾的 CUDA 头文件。
    CMAKE_SOURCE_DIR 是 CMake 内置的变量,表示项目的根目录。

在此命令中,CMake 会根据你提供的文件模式查找匹配的 .hpp 和 .cuh 文件,并将这些文件的路径存储在 CUDA_GEMM_HEADERS 变量中。

file()(动态查找判断并赋值)相当于set()(静态赋值)的增强版本,在赋值之前多了一个查找和判断的逻辑并且存入的不是后面的字符串,而是找到匹配文件的文件列表。

1.2.5 add_library()

add_library() 命令用于定义和创建库目标。add_library(cuda_gemm) 命令会创建一个名为 cuda_gemm 的库目标。这个库可以是静态库(.a)、动态库(.so 或 .dll),或者模块库(.mod),具体类型由自己指定。

基本用法:

add_library(<name> [STATIC | SHARED | MODULE] [sources...])
  • STATIC:静态库(.a 或 .lib)。默认如果未指定类型。
  • SHARED:动态库(.so 或 .dll)。
  • MODULE:模块库,主要用于动态加载的插件库。

1.2.6 target_include_directories()

target_include_directories() 是 CMake 用来为指定的目标(可执行文件或库)添加头文件的搜索路径的命令。通过这个命令,编译器会知道在哪里查找头文件(#include 的文件)

基本用法:

target_include_directories(<target> [PUBLIC | PRIVATE | INTERFACE] <directories>...)
  • < target>:指定目标名称(库或可执行文件)
  • [PUBLIC | PRIVATE | INTERFACE]:指定包含路径的可见性:
    PRIVATE:仅对当前目标有效,依赖此目标的其他目标不能继承这些路径。
    INTERFACE:仅对依赖此目标的其他目标有效,当前目标自身不会使用这些路径。
    PUBLIC:当前目标和依赖此目标的其他目标都可以使用这些包含路径。
  • < directories>:一个或多个要添加的包含目录路径。

示例:

add_library( cuda_gemm  SHARED src )
target_include_directories(cuda_gemm PUBLIC ${CUDA_GEMM_INCLUDE_DIRS})

不一定非要是库目标,也可以是可执行目标

1.2.7 set_target_properties()

set_target_properties() 是 CMake 中用于设置目标属性的命令,它可以为指定的目标(例如可执行文件或库)设置各种属性。

set_target_properties(cuda_gemm PROPERTIES CUDA_ARCHITECTURES native)

set_target_properties(cuda_gemm …):指定要设置属性的目标是 cuda_gemm,这是之前用 add_library(cuda_gemm …) 创建的 CUDA 库目标。
PROPERTIES:表示接下来设置的内容是 cuda_gemm 目标的属性。
CUDA_ARCHITECTURES native:设置属性的名称和对应的值。在这个例子中,你设置的是 CUDA_ARCHITECTURES 属性,其值为 native。

cmake会根据project、add library等命令识别到cuda_gemm是一个cuda目标,而在find_package的时候cmake会加载包配置文件从而导入一系列cuda目标,也会给这些cuda目标引入一系列与CUDA相关的属性,就包括CUDA_ARCHITECTURES。
CMake在编译CUDA目标时会把CUDA_ARCHITECTURES属性给NVCC使用,告诉NVCC是为什么架构生成的代码
native是不指定架构号,自动检测当前系统上的GPU,并生成相应代码。

1.2.8 install()命令

install() 命令是 CMake 用来将生成的二进制文件、库文件、头文件等安装到指定位置的命令。它用于定义项目的安装规则,通常用于在构建系统中,将生成的文件拷贝到系统或指定的安装目录中,方便其他用户或程序使用。

基本语法:

install(TARGETS <target>... [EXPORT <export-name>]
        [ARCHIVE | LIBRARY | RUNTIME | OBJECTS | FRAMEWORK | BUNDLE]
        [DESTINATION <dir>] 
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>])
        
install(FILES <file>... DESTINATION <dir> [PERMISSIONS permissions...])
install(DIRECTORY <dir>... DESTINATION <dir> [PERMISSIONS permissions...])
  • TARGETS:指定目标(可执行文件、库等)进行安装。
  • FILES:指定具体的文件安装。
  • DIRECTORY:将整个目录内容进行安装。
  • DESTINATION:定义安装的目标路径,即文件安装到哪个位置。
  • PERMISSIONS:可选参数,定义安装文件的权限。
  • CONFIGURATIONS:指定安装哪些构建配置(如 Debug, Release)。
install(TARGETS cuda_gemm DESTINATION lib)

将cuda_gemm目标安装到lib里面。

install() 命令中的 DESTINATION 选项决定了文件的安装位置,但这个位置通常是相对于 CMake 安装前缀 的默认路径。CMake 的安装前缀可以通过 CMAKE_INSTALL_PREFIX 变量指定,默认情况下,这个前缀通常是 /usr/local(Linux 和 macOS)或 C:/Program Files(Windows)。

install() 命令在 CMake 中的主要作用是定义项目的安装规则,但它并不是项目构建和运行的必需部分。通常情况下,没有 install() 命令,程序依然可以正常编译、运行和调试,但 install() 提供了项目发布、部署或在其他环境中使用你的软件时的重要功能。

要在 /usr/local/lib 和 /usr/local/include 里面找到相应的东西的话,可能得先确保你是否有相关读写权限。

1.2.9 target_link_libraries

target_link_libraries() 是 CMake 中用于将一个目标(通常是可执行文件或库)与其他库链接的命令。它将指定的库添加到目标的链接过程中,使目标能够使用这些库中的符号和功能。

基本语法:

target_link_libraries(<target> [PRIVATE | PUBLIC | INTERFACE] <lib1> <lib2> ...)
  • < target>:需要链接库的目标,通常是通过 add_library() 或 add_executable() 定义的目标。
  • PRIVATE、PUBLIC、INTERFACE:指定链接库的可见性(控制库链接和传递的范围)。
  • PRIVATE:库只会被当前目标使用,依赖于该目标的其他目标不会继承这些链接库。
  • PUBLIC:库不仅会被当前目标使用,依赖该目标的其他目标也会继承这些链接库。
  • INTERFACE:库不会直接链接到当前目标,但依赖该目标的其他目标会继承这些库。

二、clangd 如何使用 compile_commands.json

2.1 compile_commands.json

compile_commands.json 中的每条记录都包含三个重要的字段:

directory:编译时的工作目录。
command:完整的编译命令,包含编译器、编译选项、头文件搜索路径、宏定义等。
file:源文件的路径。
这三个字段的作用如下:

directory:表示运行编译命令时的当前目录。编译器通常会使用这个目录作为基准来解析相对路径的头文件或者依赖文件路径。clangd 通过这个字段确保在正确的目录下解析文件路径,正确查找头文件等依赖项。

command:这个字段是实际用于编译该源文件的完整命令行。它包括:

编译器路径(如 /usr/bin/g++),clangd 使用这个信息来模拟真实的编译环境。
编译选项(如 -Wall, -O2, -g),这些选项会影响 clangd 如何解析代码。
头文件包含路径(如 -I/path/to/includes),clangd 通过这些选项能够找到头文件,并理解项目的依赖关系。
宏定义(如 -DDEBUG),这些定义会影响代码的编译和行为,clangd 使用这些定义来精确解析带有条件编译的代码。
file:表示当前需要编译的源文件。clangd 通过这个字段知道要解析和分析哪个源文件。

2.2 clangd利用compile_commands.json

  1. 解析 compile_commands.json 文件
    当你在某个项目中使用 clangd 时,clangd 会首先查找并解析构建目录中的 compile_commands.json 文件。每一条记录代表一个源文件的编译命令,clangd 会根据需要处理不同的源文件。

  2. 智能跳转
    智能跳转是指当你在编辑器中点击某个符号(如函数、变量、类名等)时,clangd 能够跳转到符号的定义或声明处。为了做到这一点,clangd 需要完整解析代码的上下文,这就依赖于正确的编译配置。具体过程如下:
    通过 compile_commands.json 中的 file 字段找到对应的源文件。
    从 directory 字段得知该文件的工作目录,并进入该目录,确保相对路径能够正确解析。
    通过 command 字段获取完整的编译命令,解析头文件路径、宏定义等编译选项。
    使用这些信息构建编译环境,然后解析源文件,构建符号表。
    当用户点击某个符号时,clangd 利用解析的符号表找到其定义或声明,并跳转到对应的位置。

  3. 代码补全
    代码补全功能依赖于对代码的准确解析。在编辑器中,当你输入一个变量或对象名称时,clangd 可以根据上下文提供可能的补全项。为了提供精确的补全,clangd 必须知道项目的完整编译过程。以下是具体步骤:
    clangd 从 compile_commands.json 中提取与当前文件相关的编译命令(通过 file 字段匹配当前正在编辑的文件)。
    它使用 command 字段中的编译选项来理解该文件是如何编译的,尤其是头文件搜索路径和宏定义。
    通过 directory 字段,clangd 确保在正确的目录中解析相对路径的头文件。
    利用这些信息,clangd 可以解析当前文件和其依赖的头文件,分析代码结构。
    当用户请求代码补全时,clangd 根据已有的符号表和代码上下文生成可能的补全建议。

  4. 错误诊断和静态分析
    通过 compile_commands.json 提供的信息,clangd 也可以对代码进行更精确的错误诊断。例如,某些编译选项(如宏定义、头文件搜索路径)可能会影响到编译器能否正确处理某段代码。clangd 使用这些选项来确保它分析代码时的环境与实际编译环境一致,这样可以帮助开发者更早地发现编译错误或潜在问题。

三、静态库和动态库

3.1 静态库(Static Library)

扩展名:静态库在 Linux 和 macOS 中通常是 .a 文件,在 Windows 中是 .lib 文件。

编译时链接:静态库在编译阶段被直接链接到可执行文件中。在生成可执行文件时,静态库的代码被完整地拷贝到最终的可执行文件中。

  • 优点:
    独立性:静态链接的可执行文件不依赖于外部的库文件,在运行时不需要额外的库文件。
    运行效率:静态库在运行时无需动态加载,运行速度更快,因为所有库代码都已经编译进可执行文件中。

  • 缺点:
    文件体积大:由于库的代码被拷贝到可执行文件中,生成的可执行文件通常比动态链接方式大。
    更新不便:如果静态库有更新,所有依赖该库的可执行文件都需要重新编译。
    CMake 中创建静态库: 使用 add_library() 命令,并将 STATIC 作为参数:

add_library(my_static_lib STATIC lib_source1.cpp lib_source2.cpp)

这会生成一个静态库 my_static_lib.a(在 Linux/macOS)或 my_static_lib.lib(在 Windows)。

3.2 动态库(Shared Library 或 Dynamic Library)

扩展名:动态库在 Linux 中是 .so 文件,在 macOS 中是 .dylib 文件,在 Windows 中是 .dll 文件。

运行时链接:动态库在运行时才被加载到内存中。可执行文件只包含对动态库的引用,而不直接包含库的代码。在可执行文件运行时,操作系统会加载动态库,并链接到可执行文件中。

  • 优点:
    节省空间:由于多个可执行文件可以共享一个动态库,生成的可执行文件较小,而且系统内存中也只需加载一次动态库。
    更新方便:动态库更新时,不需要重新编译可执行文件。只需替换动态库即可使所有依赖的可执行文件使用新版库。

  • 缺点:
    运行时依赖:可执行文件在运行时依赖于动态库,因此动态库必须存在于系统的库路径中。如果动态库缺失或版本不兼容,可执行文件将无法运行。
    加载开销:在运行时加载和链接动态库可能会引入一定的性能开销。
    CMake 中创建动态库: 使用 add_library() 命令,并将 SHARED 作为参数:

add_library(my_shared_lib SHARED lib_source1.cpp lib_source2.cpp)

这会生成一个动态库 my_shared_lib.so(在 Linux)或 my_shared_lib.dll(在 Windows)。

四、targets(目标)的类型

4.1 可执行文件(Executable Target)

命令:add_executable( [sources…])
描述:可执行文件 target 用于生成最终的二进制可执行文件。这个 target 通常包含源文件,并通过编译、链接生成一个可以运行的可执行程序。

add_executable(my_executable main.cpp)

4.2 静态库(Static Library Target)

命令:add_library( STATIC [sources…])
描述:静态库 target 生成一个静态库(.a 或 .lib)。静态库在编译阶段被打包到最终的可执行文件中,不需要在运行时加载。

add_library(my_static_lib STATIC lib1.cpp lib2.cpp)

4.3 动态库(Shared Library Target)

命令:add_library( SHARED [sources…])
描述:动态库 target 生成一个动态链接库(.so、.dll 或 .dylib)。动态库在运行时加载,多个可执行文件可以共享同一份库。

add_library(my_shared_lib SHARED lib1.cpp lib2.cpp)

4.4 模块库(Module Library Target)

命令:add_library( MODULE [sources…])
描述:模块库 target 生成一个模块库。模块库在运行时动态加载,但不会自动链接到其他目标。它通常用于插件系统或自定义动态加载场景。

add_library(my_module MODULE plugin.cpp)

4.5 接口库(Interface Library Target)

命令:add_library( INTERFACE)
描述:接口库 target 不生成任何二进制文件。它只定义了一组编译选项、包含路径、依赖库等,供其他 targets 使用。接口库主要用于组织和复用编译选项和依赖。

add_library(my_interface_lib INTERFACE)
target_include_directories(my_interface_lib INTERFACE include/)

4.6 自定义目标(Custom Target)

命令:add_custom_target( [ALL] [COMMAND command1 [ARGS …]] …)
描述:自定义目标 target 不生成可执行文件或库,它定义了一些自定义命令或操作(例如脚本执行、文件生成等)。add_custom_target 可以用来创建不依赖于源代码的构建任务。

add_custom_target(run_tests ALL
  COMMAND my_executable --run-tests
)

4.7 导入目标(Imported Target)

命令:add_library( IMPORTED) 或 add_executable( IMPORTED)
描述:导入目标 target 表示一个已经存在的库或可执行文件,而不是由 CMake 构建的目标。IMPORTED 目标通常用于链接外部的预编译库或工具,它不会被 CMake 构建,但可以链接到其他 CMake targets。

add_library(my_imported_lib STATIC IMPORTED)
set_target_properties(my_imported_lib PROPERTIES
  IMPORTED_LOCATION /path/to/libmy_imported_lib.a
)

注意:find_package() 加载包配置之后会导入的目标的类型就是导入目标类型

4.8 外部目标(External Project Target)

命令:通过 ExternalProject_Add() 命令创建。
描述:外部项目 target 是 CMake ExternalProject 模块的一部分,用于从外部构建其他项目。可以用它来自动下载、配置、编译和安装外部项目。

include(ExternalProject)
ExternalProject_Add(my_external_project
  GIT_REPOSITORY https://github.com/user/repo.git
  GIT_TAG main
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
)

4.9 ALIAS 目标

命令:add_library( ALIAS ) 或 add_executable( ALIAS )
描述:ALIAS 目标是已有目标的别名,不能直接创建新的构建产物。它为现有目标提供了一个新的名称,可以更方便地引用该目标。

add_library(my_lib STATIC lib.cpp)
add_library(my_alias ALIAS my_lib)
target_link_libraries(my_target my_alias)

4.10 OBJECT 库目标(Object Library Target)

命令:add_library( OBJECT [sources…])
描述:对象库 target 生成的是编译后的目标文件(.o 或 .obj),而不是库文件。它可以在多个 target 之间共享编译后的对象文件,而不生成最终的库。

add_library(my_object_lib OBJECT file1.cpp file2.cpp)
target_link_libraries(my_target PRIVATE $<TARGET_OBJECTS:my_object_lib>)

4.11 UTILITY 目标

描述:UTILITY 目标是 makefile 或 Ninja 文件中的概念,通常用于表示一些辅助的目标,比如 all、clean。它们是构建工具的内部目标,CMake 并没有专门的命令来定义 UTILITY 目标。


总结

又臭又长,希望可以一劳提高效率。

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

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

相关文章

小红书制作视频如何去原视频音乐,视频如何去原声保留背景音乐?

在视频编辑、音乐制作或个人娱乐中&#xff0c;有时我们希望去掉视频中的原声&#xff08;如对话、解说等&#xff09;&#xff0c;仅保留背景音乐。这种处理能让观众更加聚焦于视频的氛围或节奏&#xff0c;同时也为创作者提供了更多创意空间。选择恰当的背景音乐&#xff0c;…

【tower-boot 系列】开源RocketMQ和阿里云rockerMq 4.x和5.x集成 (一)

RocketMQ 简单介绍 阿里云rockerMq 4.x和5.x集成 一、云平台创建实例 参考文档&#xff1a; 阿里云api 阿里云 创建实例 二、skd集成思路 公司用的RocketMQ一般是自建开源apache的RocketMQ和上阿里云的RocketMQ&#xff0c;目前阿里云支持4.x和5.x版本 项目集成思路&…

【MAUI】CollectionView之 垂直网格

App主页或者导航页面中动态按钮的垂直网格布局 在 XAML 中,CollectionView 可以通过将其 ItemsLayout 属性设置为 VerticalGrid,在垂直网格中显示其项: <CollectionView ItemsSource="{Binding Monkeys}"ItemsLayout

链表面试编程题

1. 删除链表中等于给定值 val 的所有节点。 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 2. 反转一个单链表。206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 3. 给定一个带有头结点 head 的非空单链表&#xff0c;返回链表的中间结点。如果有两个中间…

FOCShield v2.0.4原理图

1.FOCShield v2.0.4原理图,开源原文件用AD制作。用 AD09可以打开。 主要部分为 1.电机驱动芯片部分 2.电流采样部分

2024 全新体验:国学心理 API 接口来袭

在当今快节奏的生活中&#xff0c;人们对于心理健康越来越重视。而研究发现&#xff0c;国学心理学乃至传统文化中的思想智慧&#xff0c;对于人们的心理健康有着独特且深远的影响。为了让更多人能够体验到国学心理的魅力&#xff0c;2024年全新推出的国学心理 API 接口&#x…

Efficient Knowledge Infusion via KG-LLM Alignment

文章目录 题目摘要引言相关作品方法论实验设置和结果分析结论局限性附录 题目 通过KG-LLM比对实现高效的知识注入 论文地址&#xff1a;https://aclanthology.org/2024.findings-acl.176.pdf 摘要 为了解决大型语言模型中特定领域知识匮乏的问题&#xff0c;知识图检索扩充方…

27 Vue3之unocss原子化

前置知识 什么是原子化 CSS 原子化 CSS 是一种 CSS 的架构方式&#xff0c;它倾向于小巧且用途单一的 class&#xff0c;并且会以视觉效果进行命名。 为什么使用 原子化 CSS 传统方案 制作原子化 CSS 的传统方案其实就是提供所有你可能需要用到的 CSS 工具。例如&#xff0c…

ES索引生命周期管理

基于如何 定时删除ES索引过期数据 而引发的一系列关于ES索引生命周期管理ILM(Index Lifecycle Management)的学习 快速上手 &#xff1a;定时删除ES索引中的过期数据 1. ILM解决什么问题&#xff1f; ES从6.7版本引入ILM&#xff0c;通过ILM可以解决哪些问题呢? 自动新建…

Python 课程22-Pillow

前言 Pillow 是一个 Python 图像处理库&#xff0c;是 Python Imaging Library (PIL) 的升级版。Pillow 提供了对常见图像文件格式&#xff08;如 PNG、JPEG、GIF 等&#xff09;的支持&#xff0c;并允许你进行图像裁剪、调整大小、旋转、滤镜应用、文本添加等操作。Pillow 广…

Applio:颠覆语音克隆的AI黑科技!

Applio&#xff1a;颠覆语音克隆的AI黑科技&#xff01; Applio是一个神奇的AI语音克隆工具✨&#xff0c;提供超过20,000种声音模型&#x1f3a4;&#xff0c;让你轻松创造独特音色&#x1f3b6;&#xff01;开源社区欢迎所有人参与&#xff0c;共同探索AI音频的无限可能&…

蓝桥杯备赛---2.新建工程

推荐根据视频进行工程建立 开发板资源简介&工程模板建立_哔哩哔哩_bilibili 目录 推荐根据视频进行工程建立 1.点击"File"下的"New Project"新建一个工程 ​编辑 2. 查看官方给的数据手册&#xff0c;选择对于的单片机型号 3. 查看原理图&#…

银河麒麟操作系统中设置进程堆栈大小的方法

银河麒麟操作系统中设置进程堆栈大小的方法 1、临时修改堆栈大小步骤一&#xff1a;查看当前堆栈大小步骤二&#xff1a;修改堆栈大小 2、永久修改堆栈大小步骤一&#xff1a;查看当前堆栈大小&#xff08;可选&#xff09;步骤二&#xff1a;编辑配置文件步骤三&#xff1a;注…

论文精读--Two-Stream Convolutional Networks for Action Recognition in Videos

对于单张图片&#xff0c;丢进卷积和全连接层直接得出分类结果就行 但对于视频&#xff0c;早期的一些工作把视频中的一些关键帧抽取出来&#xff0c;把一个个帧通过网络&#xff0c;最后把结果合并&#xff0c;或者把帧叠起来&#xff0c;一起丢进网络。在网络中进行early fu…

【C++】模拟实现红黑树

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:实战项目集 ⚙️操作环境:Visual Studio 2022 目录 一.了解项目功能 二.逐步实现项目功能模块及其逻辑详解 &#x1f4cc;实现RBTreeNode类模板 &#x1f38f;构造RBTreeNode类成员变量 &#x1f38f;实现RBTreeNode类构…

【数据结构】堆(Heap)详解----定义堆、初始化,删除、插入、销毁、判空、取堆顶

文章目录 一、堆的概念及其性质&#xff1a;堆的概念&#xff1a;堆的性质&#xff1a; 二、堆的定义及其基础操作的代码实现&#xff08;C语言版&#xff09;1.定义堆2.堆的初始化3.堆的销毁4.堆的插入5.堆的删除6.取堆顶的数据7.堆的数据个数8.堆的判空 总结&#xff1a; 提示…

Python开发环境配置(mac M2)

1. 前言 作为一名程序员&#xff0c;工作中需要使用Python进行编程&#xff0c;甚至因为项目需要还得是不同版本的Python如何手动管理多个版本的Python&#xff0c;如何给Pycharm&#xff08;IDE&#xff09;配置对应的interpreter等&#xff0c;都成为一个 “不熟练工” 的难…

【面向对象】设计模式概念和分类

零.前提提要 本文章是我考中级软件设计师时的笔记&#xff0c;基本都是一些自己的思路和见解&#xff0c;现记录一下&#xff0c;希望可以帮助到即将考证的同学。 一.面向对象设计模式的概念 二.面向对象的设计模式分类 设计模式确定了所包含的类和实例、他们的角色和写作方式以…

AMBER学习记录--使用Multiwfn计算有机小分子的RESP电荷--问题及解决

1 ORCAMultiwfn在wsl中的安装 ORCA的安装参考量子化学程序ORCA的安装方法 - 思想家公社的门口&#xff1a;量子化学分子模拟二次元 (sobereva.com) Multiwfn的安装 参考保姆级安装Linux版Multiwfn教程_multiwfn安装过程-CSDN博客 2 计算C3G的RESP电荷 2.1从pubchem上下载C3G的…

77. 组合【含回溯详解、N叉树类比、剪枝优化】

文章目录 77. 组合思路暴力法回溯与N叉树类比回溯法三部曲 总结剪枝优化剪枝总结 77. 组合 77. 组合 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&am…