CMakeLists.txt 基本用法实战

bash 复制代码
# 1. 最低 CMake 版本要求(建议写 3.16+,兼容大部分系统)
cmake_minimum_required(VERSION 3.10 )

# 2. 项目定义(项目名、版本、语言)
project(
    OpenCV_Demo
    VERSION 1.0.0
    LANGUAGES CXX
)

# 3. 设置 C++ 标准(比如 C++17)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# -----------------------------------------------------------
# 3. 选项开关:是否启用 CUDA
# -----------------------------------------------------------
# 在 cmake 配置时可以通过 -DENABLE_CUDA=ON 来开启
option(ENABLE_CUDA "Enable NVIDIA CUDA support" OFF)
# 把 ENABLE_CUDA 定义传给 C++ 编译器
if(ENABLE_CUDA)
    add_definitions(-DENABLE_CUDA)  # 这一行必须加!
endif()

# 输出目录设置
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# -----------------------------------------------------------
# 4. 查找 OpenCV
# -----------------------------------------------------------
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
    message(STATUS "OpenCV found: ${OpenCV_VERSION}")
    message(STATUS "OpenCV libs: ${OpenCV_LIBS}")
endif()

# -----------------------------------------------------------
# 5. 配置 ONNX Runtime
# -----------------------------------------------------------
if(WIN32)
    # --- 根据你的实际路径修改这里 ---
    # 如果想切换 CPU/GPU,直接改这个路径或者用 CMake 变量传入
    if(ENABLE_CUDA)
        # GPU 版本路径
        set(ONNXRUNTIME_ROOTDIR "E:/FindJob/onnxruntime-win-x64-gpu-1.14.1")
        message(STATUS ">>> 使用 ONNX Runtime GPU 版本")
    else()
        # CPU 版本路径
        set(ONNXRUNTIME_ROOTDIR "E:/FindJob/onnxruntime-win-x64-1.14.1")
        message(STATUS ">>> 使用 ONNX Runtime CPU 版本")
    endif()
else()
    # Linux 路径示例
    set(ONNXRUNTIME_ROOTDIR "/usr/local/onnxruntime")
endif()

# 包含头文件目录
target_include_directories(${PROJECT_NAME} PRIVATE ${ONNXRUNTIME_ROOTDIR}/include)
# 链接库目录
target_link_directories(${PROJECT_NAME} PRIVATE ${ONNXRUNTIME_ROOTDIR}/lib)

# 核心库
set(ONNXRUNTIME_LIBS onnxruntime)

# 如果开启 CUDA,需要额外链接 Provider 库
if(ENABLE_CUDA)
    # 注意:GPU 版本需要链接这两个额外的库
    list(APPEND ONNXRUNTIME_LIBS onnxruntime_providers_cuda)
    list(APPEND ONNXRUNTIME_LIBS onnxruntime_providers_shared)
endif()

# -----------------------------------------------------------
# 6. 生成可执行文件 (关键修复:必须在 target_link_libraries 之前)
# -----------------------------------------------------------
add_executable(${PROJECT_NAME} main.cpp)

# -----------------------------------------------------------
# 7. 链接库
# -----------------------------------------------------------
target_link_libraries(${PROJECT_NAME}
    PRIVATE
    ${OpenCV_LIBS}
    ${ONNXRUNTIME_LIBS}
)

# -----------------------------------------------------------
# 8. Windows DLL 自动拷贝 (非常重要,否则运行找不到 dll)
# -----------------------------------------------------------
if(WIN32)
    # 拷贝核心 DLL
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime.dll"
        $<TARGET_FILE_DIR:${PROJECT_NAME}>
    )

    # 如果开启了 CUDA,还需要拷贝 Provider 的 DLL
    if(ENABLE_CUDA)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime_providers_cuda.dll"
            "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime_providers_shared.dll"
            $<TARGET_FILE_DIR:${PROJECT_NAME}>
        )
        # 注意:运行 GPU 版本还需要系统环境变量中有 CUDA 的 cudnn.dll 和 cublas.dll 等
    endif()
endif()

cmake_minimum_required(VERSION 3.10)

  • 含义:声明运行此 CMake 脚本所需的最低版本。如果用户的 CMake 版本低于 3.10,CMake 会报错并停止运行。
  • 作用:确保脚本中使用的语法特性在当前环境中受支持。
  • 当前状态:你的电脑上安装的 CMake 版本必须 ≥ 3.10。

project(OpenCV_Demo VERSION 1.0.0 LANGUAGES CXX)

  • 含义:定义项目名称、版本号、语言。这是 CMake 脚本中最重要的指令之一,它会初始化一系列变量。
  • 关键字
    • OpenCV_Demo:这是你给项目起的名字。
    • VERSION 1.0:项目的版本号。
  • 生成的变量
    • PROJECT_NAME:值为 "OpenCV_Demo"
    • PROJECT_VERSION:值为 "1.0"
    • PROJECT_SOURCE_DIR:包含此文件的根目录。

总结:给项目起名字

告诉 CMake:我用的语言是 C++

让 CMake 检查 C++ 编译器是否存在

set(CMAKE_CXX_STANDARD 17)

  • 含义:告诉 CMake 使用 C++17 标准来编译代码。
  • 作用 :相当于在 g++ 编译器后面加了 -std=c++17 参数。这让你可以使用现代 C++ 的特性(如 autofilesystem 等)。

set(CMAKE_CXX_STANDARD_REQUIRED ON)

  • 含义:强制要求编译器支持 C++17。
  • 作用 :如果编译器太老(不支持 C++17),CMake 会直接报错,而不是悄悄降级使用旧标准(如 C++98),避免莫名其妙的编译错误。
    大白话翻译:"我指定的 C++ 版本是必须的!编译器不支持就别编译了!"

set(CMAKE_CXX_EXTENSIONS OFF)

工程化细节。这行代码告诉编译器不要使用编译器特有的扩展(比如 GCC 的 -std=gnu++17),而是严格遵循标准(-std=c++17)。这能保证你的代码在不同编译器(GCC, Clang, MSVC)上表现一致,避免"在我的电脑上能跑,换个环境就挂了"的问题。

CUDA 开关与宏定义

cmake 复制代码
option(ENABLE_CUDA "Enable NVIDIA CUDA support" OFF)
if(ENABLE_CUDA)
    add_definitions(-DENABLE_CUDA)  # 这一行必须加!
endif()
  • option(ENABLE_CUDA ...) : 这是一个交互式开关

    • 当你运行 cmake .. 时,默认是 OFF。
    • 如果你想用 GPU,只需运行 cmake .. -DENABLE_CUDA=ON。这比修改代码去切换版本要专业得多。
  • add_definitions(-DENABLE_CUDA) : 这是连接 CMake 和 C++ 代码的桥梁

    • 作用 :它会在编译时给编译器传入一个 -DENABLE_CUDA 参数。

    • 代码里的体现 :在你的 main.cpp 里,你可以这样写:

      cpp 复制代码
      #ifdef ENABLE_CUDA
          // 初始化 CUDA Provider
          OrtCUDAProviderOptions cuda_options;
          session_options.AppendExecutionProvider_CUDA(cuda_options);
      #endif
    • 如果没有这一行,即使你链接了 CUDA 库,你的 C++ 代码里关于 CUDA 的初始化代码也不会被编译进去,导致程序实际还是在跑 CPU。

查找 OpenCV

cmake 复制代码
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
    message(STATUS "OpenCV found: ${OpenCV_VERSION}")
    message(STATUS "OpenCV libs: ${OpenCV_LIBS}")
endif()
  • find_package(OpenCV REQUIRED) : CMake 会自动去系统路径(如 /usr/local 或环境变量 OpenCV_DIR)找 OpenCV 的配置文件。
  • REQUIRED: 强制要求。如果没装 OpenCV,CMake 直接报错停止,防止后续出现莫名其妙的错误。
  • message(STATUS ...): 在配置阶段打印出找到的 OpenCV 版本和库列表,方便排查"为什么链接不上"的问题。

此处本人是使用vcpkg 部署的opencv

配置 ONNX Runtime(跨平台处理)

cmake 复制代码
# 5. 配置 ONNX Runtime
if(WIN32)
    # --- Windows 特有逻辑 ---
    if(ENABLE_CUDA)
        set(ONNXRUNTIME_ROOTDIR "E:/FindJob/onnxruntime-win-x64-gpu-1.14.1")
        message(STATUS ">>> 使用 ONNX Runtime GPU 版本")
    else()
        set(ONNXRUNTIME_ROOTDIR "E:/FindJob/onnxruntime-win-x64-1.14.1")
        message(STATUS ">>> 使用 ONNX Runtime CPU 版本")
    endif()
else()
    # --- Linux 特有逻辑 ---
    set(ONNXRUNTIME_ROOTDIR "/usr/local/onnxruntime")
endif()

target_include_directories(${PROJECT_NAME} PRIVATE ${ONNXRUNTIME_ROOTDIR}/include)
target_link_directories(${PROJECT_NAME} PRIVATE ${ONNXRUNTIME_ROOTDIR}/lib)
  • if(WIN32): 区分操作系统。Windows 下通常使用预编译的压缩包(zip),路径是固定的;Linux 下通常是安装到系统目录。
  • target_include_directories : 告诉编译器去哪里找 onnxruntime_cxx_api.h 等头文件。
  • target_link_directories : 告诉链接器去哪里找 .lib (Windows) 或 .so (Linux) 文件。
    • 注:虽然现代 CMake 推荐用 find_library,但在部署特定版本的 ONNX Runtime 时,直接指定路径(硬编码或变量)往往更直接有效。

include_directories 和target_include_directories什么关系

一句话终极结论
include_directories = 全局生效(老写法,不推荐)
target_include_directories = 只给某个目标生效(现代 CMake,必须用)
1. 先讲清楚:它们是亲戚关系,但地位完全不同
  • include_directories老一辈的命令
  • target_include_directories现代 CMake 的标准

它们的目的完全一样

告诉编译器:去哪里找 .h 头文件!
2. 核心区别(最关键)
🔴 include_directories(xxx)

作用范围:整个项目所有目标

  • 你写了这一行
  • 后面所有 add_executable / add_library
  • 全部都能找到这个头文件路径

缺点:污染全局!容易冲突!

🟢 target_include_directories(目标 ...)

作用范围:只给这一个目标

  • 只让你指定的程序/库能找到头文件,当你在代码中写 #include <myheader.h> 时,编译器会去这个目录下查找。
  • 别的目标完全不受影响

优点:干净、安全、现代、无冲突!

3. 举个超级大白话例子

假设你有:

复制代码
项目
├─ A.exe
└─ B.exe

你只想让 A 能用 OpenCV 的头文件,B 不能用。

✅ 现代正确写法(推荐)
cmake 复制代码
add_executable(A a.cpp)

# 只给 A 用
target_include_directories(A
    PRIVATE
    ${OpenCV_INCLUDE_DIRS}
)
❌ 老写法(全局污染,不推荐)
cmake 复制代码
# 全局加路径 → A 和 B 全都能找到
include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(A a.cpp)
add_executable(B b.cpp)  # B 也能找到,这可能不是你想要的
4. 最关键的三个关键字

target_include_directories 后面必须跟三个之一:

1) PRIVATE

→ 路径仅给当前目标用

→ 别人链接你时看不到

90% 的情况都用这个!

2) PUBLIC

→ 自己用 + 别人链接你时也能用

→ 给库用

3) INTERFACE

→ 自己不用,只给别人用

→ 纯头文件库用

链接库(CPU vs GPU)

cmake 复制代码
# 核心库
set(ONNXRUNTIME_LIBS onnxruntime)

# 如果开启 CUDA,需要额外链接 Provider 库
if(ENABLE_CUDA)
    # 注意:GPU 版本需要链接这两个额外的库
    list(APPEND ONNXRUNTIME_LIBS onnxruntime_providers_cuda)
    list(APPEND ONNXRUNTIME_LIBS onnxruntime_providers_shared)
endif()
  • set(ONNXRUNTIME_LIBS onnxruntime) : 初始化库变量,包含最基础的 onnxruntime.lib
  • list(APPEND ...) : GPU 部署的坑点
    • ONNX Runtime 的 GPU 实现是模块化的。如果你要用 CUDA,必须链接 onnxruntime_providers_cuda
    • 如果不加这两行,编译可能通过,但运行时会报错 Failed to load shared library 或者回退到 CPU 模式。

生成目标与链接

cmake 复制代码
# 6. 生成可执行文件
add_executable(${PROJECT_NAME} main.cpp)

# 7. 链接库
target_link_libraries(${PROJECT_NAME}
    PRIVATE
    ${OpenCV_LIBS}
    ${ONNXRUNTIME_LIBS}
)
  • add_executable : 生成 .exe 或可执行文件。注意 :这行必须在 target_link_libraries 之前,因为链接是依附于目标的。
  • PRIVATE: 这是一个作用域修饰符。表示这些库只用于编译当前项目,不会传递给依赖当前项目的其他库(虽然这里是顶层项目,但加上是个好习惯)。
  • ${OpenCV_LIBS} : CMake 会自动展开成 opencv_world4xx.lib 或者 opencv_imgproc;opencv_core 等一堆库。

Windows DLL 自动拷贝(工程化神器)

cmake 复制代码
# 8. Windows DLL 自动拷贝
if(WIN32)
    # 拷贝核心 DLL
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime.dll"
        $<TARGET_FILE_DIR:${PROJECT_NAME}>
    )

    # 如果开启了 CUDA,还需要拷贝 Provider 的 DLL
    if(ENABLE_CUDA)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime_providers_cuda.dll"
            "${ONNXRUNTIME_ROOTDIR}/lib/onnxruntime_providers_shared.dll"
            $<TARGET_FILE_DIR:${PROJECT_NAME}>
        )
    endif()
endif()
  • 为什么需要这个?
    • 在 Windows 上,编译出来的 .exe 运行时需要同目录下有 .dll 文件。
    • 如果不拷贝,你每次编译完还得手动去把 dll 复制到 bin 目录,非常低效。
  • add_custom_command(... POST_BUILD ...) :
    • 这是一个构建后钩子。意思是:当你的代码编译链接完成后,CMake 会自动执行后面的命令。
  • copy_if_different: 智能拷贝。只有当源文件比目标文件新(或者目标文件不存在)时才拷贝,避免每次都无脑覆盖,节省时间。
  • $<TARGET_FILE_DIR:...> : 这是一个生成器表达式,它会自动解析成你的 .exe 所在的目录(比如 bin/Release)。

关于set(CMAKE_EXPORT_COMPILE_COMMANDS ON)的使用

这行代码是连接"构建系统"与"开发工具"的桥梁。简单来说,它的作用是告诉 CMake 在编译时生成一个名为 compile_commands.json 的文件

这个文件是编译数据库 ,记录了项目中每一个源文件编译时的完整命令 (包括编译器路径、所有的 -I 头文件路径、-D 宏定义等)。

💡 什么时候需要它?

如果你只是单纯在命令行里用 makeninja 编译运行,这个选项不是必须的

但在以下 3 种"工程化"场景 中,它是必选项

1. 使用 VS Code / CLion 进行开发(最常用)

当你使用 VS Code 写 C++ 代码时,插件(如 C/C++ 或 Clangd)需要知道你的头文件在哪里,定义了哪些宏。

  • 没有它 :编辑器只能瞎猜。它会报一堆红色的波浪线报错(比如 #include <opencv2/...> file not found),即使你的项目明明能编译通过。代码跳转(Go to Definition)也会失效。
  • 有了它 :编辑器读取 compile_commands.json,精准还原编译环境,代码补全、跳转、错误检查瞬间变准。
2. 使用静态代码分析工具

如果你想在项目中集成 clang-tidycppcheck 来检查代码质量。

  • 这些工具需要知道完整的编译参数(比如你用了 -std=c++17 或者定义了 ENABLE_CUDA),否则它们无法正确解析代码,导致误报。
3. 排查复杂的编译错误

有时候编译报错很奇怪,你不知道编译器到底用了什么参数。

  • 你可以直接打开这个 JSON 文件,查看对应 .cpp 文件的那一行命令,看看是不是漏了什么宏定义或者路径。

🛠️ 如何正确使用?

有两种方式开启,推荐方式二

方式一:在 CMakeLists.txt 中写死(不推荐)
cmake 复制代码
# 写在 project() 之前
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 

缺点: 每次配置都会生成,哪怕你只是想简单编译一下。而且如果要把代码提交给不需要这个文件的人,会显得多余。

方式二:在命令行配置时开启(推荐 ✅)

这是最灵活的做法,只在需要时生成。

bash 复制代码
# 在 cmake 配置阶段加上这个参数
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..

总结

set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 是现代 C++ 开发(特别是配合 IDE)的标配。 它能极大提升你的编码体验,让你告别"能编译但编辑器一片红"的痛苦。

对于当前项目是否要加set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

非常需要!强烈建议加上。

结合你正在做的 YOLO 部署项目(涉及 OpenCV、ONNX Runtime、CUDA 跨平台切换),加上这行配置会让你的开发体验提升一个档次。

以下是为什么你的项目特别需要它的三个理由:

1. 解决 VS Code 的"爆红"问题(最重要)

你的项目中使用了大量的条件编译自定义路径

  • 路径复杂 :你硬编码了 E:/FindJob/onnxruntime... 这样的路径。如果不生成 compile_commands.json,VS Code 的 IntelliSense 引擎很难猜到你的头文件在这些非标准目录下,会导致 #include <onnxruntime_cxx_api.h> 报红,即使能编译通过。
  • 宏定义复杂 :你用了 if(ENABLE_CUDA)add_definitions(-DENABLE_CUDA)
    • 如果不加 :VS Code 不知道 ENABLE_CUDA 被定义了,它会把 #ifdef ENABLE_CUDA 里面的代码(比如 CUDA 初始化代码)当成注释或者无效代码,导致代码高亮失效、跳转失效。
    • 加了之后:编辑器会精准识别:"哦,原来这个宏定义了,那我就要检查这段 CUDA 代码的语法错误。"

2. 调试 ONNX Runtime 源码

做部署时,你经常会遇到 ONNX Runtime 报错(比如 OrtStatus 报错)。

  • 有了这个文件,配合 VS Code,你可以直接跳转到 ONNX Runtime 的头文件定义处 ,查看 SessionOptions 到底有哪些参数可以调,而不需要去浏览器搜文档。

3. 跨平台开发的"后悔药"

你现在可能在 Windows 上开发,以后可能要部署到 Linux。

  • 当你把代码迁移到 Linux 时,加上这行配置,配合 VS Code 的 WSLRemote-SSH 插件,它能自动帮你检测 Linux 环境下的路径对不对。如果配置错了,编辑器会立刻提示,而不需要你等到编译报错才发现。

🚀 怎么加?(推荐做法)

不要修改你的 CMakeLists.txt 文件(保持它的纯净性),而是在配置命令里加上它

Windows (PowerShell/CMD) 用户:

powershell 复制代码
# 在运行 cmake 配置时加上这个参数
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

Linux 用户:

bash 复制代码
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..

💡 加完之后的一步操作

生成后,compile_commands.json 会出现在 build 目录下。

为了让 VS Code 读取到它,你需要在 VS Code 的设置(.vscode/c_cpp_properties.json)里加一行:

json 复制代码
{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "compileCommands": "${workspaceFolder}/build/compile_commands.json" 
            // 👆 加上这一行,指向你的生成位置
        }
    ]
}

总结: 加上它,你的代码提示、跳转、错误检查将瞬间变得精准,这是专业 C++ 开发的标配。

源文件配置方式选择

采用

add_executable(${PROJECT_NAME} main.cpp)方式

还是

file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")

add_executable({PROJECT_NAME} {SOURCES})

main.cpp 替换为 file(GLOB ...) 是管理多文件项目的常见做法,但这里有一个巨大的"坑",如果不注意,会让后续开发中非常抓狂。

我们来详细拆解一下这两种写法,并给出工业界最推荐的终极方案

⚠️ 方案一:file(GLOB ...) 的陷阱

cmake 复制代码
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")
add_executable(${PROJECT_NAME} ${SOURCES})

优点:

  • 省事 :你在 src 目录下新建一个 utils.cpp,不需要改 CMakeLists.txt,直接编译就能自动包含进去。

致命缺点(坑):

  • 增量更新失效 :CMake 的 GLOB 是在配置阶段 (运行 cmake .. 时)执行的。
    • 场景 :你正在写代码,突然新建了一个 new_feature.cpp
    • 现象 :你直接点"编译"或 make编译会失败 或者找不到新文件的符号
    • 原因 :因为 Makefile 是在上一次配置时生成的,它不知道今天多了一个文件。你必须重新运行 cmake .. 才能让它感知到新文件。这在频繁新建文件的开发初期非常打断心流。

✅ 方案二:现代 CMake 的最佳实践 (target_sources)

工业界更推荐显式管理源文件,或者使用更现代的命令。

1. 显式列出(最稳健)

虽然看起来笨,但对于几百个文件的项目,这是最可控的。

cmake 复制代码
add_executable(${PROJECT_NAME}
    src/main.cpp
    src/image_processor.cpp
    src/yolo_detector.cpp
)
  • 优点:修改文件列表一定会触发 CMake 重新配置,构建系统极其稳定。
  • 缺点:文件多了写起来累。
2. 使用 target_sources + GLOB(折中方案)

如果你坚持要用 GLOB 的便利性,建议配合 target_sources 使用,并且必须接受"新建文件后要重新配置"这个设定

cmake 复制代码
# 1. 先创建目标
add_executable(${PROJECT_NAME})

# 2. 收集源文件
# 注意:这里建议加上 CONFIGURE_DEPENDS (CMake 3.12+)
# 这会让 CMake 在构建时检查文件变动,解决部分"新建文件不生效"的问题,但会轻微增加配置时间
file(GLOB SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/*.cpp")

# 3. 添加源文件到目标
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})

🚀 针对你 YOLO 项目的最终建议

考虑到你的项目结构(src/ 目录下可能有多个 .cpp),我建议你采用 "显式列出 + 变量管理" 的方式。这样既清晰,又不会遇到 GLOB 的坑。

修改后的 CMakeLists.txt 核心部分:

cmake 复制代码
# -----------------------------------------------------------
# 6. 定义源文件列表 (推荐显式管理)
# -----------------------------------------------------------
# 把 src 目录下的所有 cpp 文件写在这里
# 这样当你删除或重命名文件时,CMake 能立刻感知并报错,避免遗留垃圾代码
set(PROJECT_SOURCES
    src/main.cpp
    src/image_processor.cpp
    # src/yolo_detector.cpp  <-- 以后加新文件,在这里加一行即可
)

# -----------------------------------------------------------
# 7. 生成可执行文件
# -----------------------------------------------------------
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})

# -----------------------------------------------------------
# 8. 包含头文件目录
# -----------------------------------------------------------
target_include_directories(${PROJECT_NAME} PRIVATE 
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${OpenCV_INCLUDE_DIRS}
    ${ONNXRUNTIME_ROOTDIR}/include
)

# -----------------------------------------------------------
# 9. 链接库
# -----------------------------------------------------------
target_link_directories(${PROJECT_NAME} PRIVATE ${ONNXRUNTIME_ROOTDIR}/lib)

target_link_libraries(${PROJECT_NAME} PRIVATE
    ${OpenCV_LIBS}
    ${ONNXRUNTIME_LIBS}
)

总结

  1. 如果处于快速原型期 (疯狂新建文件):用 file(GLOB SOURCES CONFIGURE_DEPENDS ...),但要记得新建文件后重新运行 CMake
  2. 如果处于稳定开发期 (文件结构基本固定):用 set(PROJECT_SOURCES ...) 显式列出。这是最专业、最不容易出错的做法。

我的建议养成显式列出文件的习惯(方案2)对你的长远发展更有利。

在VSCode中编写CMakeLists.txt 哪些部分是会被高亮显示

我直接给你最清晰、最实用、一看就懂 的答案!

你在 VSCode 里写 CMakeLists.txt哪些会高亮、哪些不会,我一次性讲全!

一定会被高亮的内容(核心)

这些是 CMake 语法的关键字/指令任何 CMake 插件都会高亮

1. CMake 命令(蓝色/紫色/绿色)

所有大写/小写命令名都会高亮:

cmake 复制代码
project()
find_package()
add_executable()
target_link_libraries()
include_directories()
set()
if()
else()
endif()
foreach()

这些是核心语法必高亮

2. 变量(黄色/青色)

${} 包裹的变量:

cmake 复制代码
${PROJECT_NAME}
${OpenCV_LIBS}
${CMAKE_CXX_STANDARD}

3. 字符串(红色/橙色)

双引号包裹的文本:

cmake 复制代码
"My Project"
"opencv4"

4. 注释(绿色/灰色)

# 开头:

cmake 复制代码
# 这是注释,一定会高亮

5. 控制流关键字(深蓝色)

cmake 复制代码
if else endif
while
foreach
function
return

不会高亮 / 高亮很弱的内容

这些是你自己定义的内容,插件无法识别:

1. 你自己写的 项目名、文件名

cmake 复制代码
add_executable(
    main   # 普通颜色,不高亮
    main.cpp  # 普通颜色,不高亮
)

2. 自定义变量名

cmake 复制代码
set(MY_VAR 123)  # MY_VAR 不高亮

3. 路径、普通数字

cmake 复制代码
D:/opencv/include
11
20
相关推荐
雪域迷影3 天前
Windows上使用VS2026和CMake编译LearnOpenGL项目源代码
windows·cmake·opengl·vs2026·gthub
瞎折腾啥啊7 天前
CMake FetchContent与ExternalProject
c++·cmake·cmakelists
JMchen1237 天前
集成第三方 C/C++ 库到 Android NDK 项目:OpenCV 与 FFmpeg 实战指南
opencv·ffmpeg·音视频开发·cmake·jni·ndk·abi 兼容性
郝学胜-神的一滴9 天前
从零起步:CMake基础入门与实战跨平台编译
c++·软件工程·软件构建·cmake
AlbertS10 天前
distcc + ccache 编译递归问题排查总结
c++·cmake·gcc·g++·distcc·ccache
Robot_Nav12 天前
CMake、Ament 与 Catkin:ROS 构建系统的前世今生
ros·cmake
瞎折腾啥啊14 天前
CMakeLists.txt 完全详解
cmakelists
CoderMeijun16 天前
CMake 入门笔记
c++·笔记·编译·cmake·构建工具
郝学胜-神的一滴16 天前
墨韵技术|CMake:现代项目构建的「行云流水」之道
c++·程序人生·软件工程·软件构建·cmake