You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用CMake生成多份compile_commands.json?解决头文件补全失效问题

解决CMake生成的compile_commands.json对include目录无效的问题,以及多份生成方案

我之前也碰到过一模一样的问题——用CMake生成的编译数据库只覆盖src目录,include里的头文件完全没有自动补全,折腾了好一阵才搞定,给你分享几个实用的方案:

一、让CMake为include目录的头文件生成编译条目

问题的根源是compile_commands.json里只记录了实际被编译的源文件(也就是src里的.cpp/.c文件)的编译参数,include里的头文件因为没有被直接编译,所以没有对应的条目,LSP(比如clangd)没法识别它们的上下文。

解决这个最简单的办法是让CMake把include里的头文件也当作“虚拟编译目标”处理,这样就会在数据库里生成对应的条目:

# 在根目录的CMakeLists.txt末尾添加
file(GLOB_RECURSE PROJECT_HEADERS include/*.h include/*.hpp)
add_custom_target(
    project_headers
    SOURCES ${PROJECT_HEADERS}
)

这个project_headers是个不会实际编译的空目标,但CMake会把所有头文件的路径和项目的包含参数写入compile_commands.json,LSP就能识别到include目录的文件了。

二、直接给LSP配置额外的包含路径

如果不想改动CMakeLists,也可以直接在Vim的LSP客户端里添加include目录的路径,强制让补全工具识别:

  • 如果你用的是clangd(最常用的C/C++补全后端),可以在项目根目录创建.clangd文件:
CompileFlags:
  Add: [-I./include]
  • 要是用coc.nvim的coc-clangd插件,就打开:CocConfig,添加:
{
  "clangd.arguments": ["-I${workspaceFolder}/include"]
}

这种方法不需要修改CMake配置,适合快速解决问题。

三、关于生成多份compile_commands.json的问题

CMake本身是每个构建目录生成一份编译数据库的,比如你如果分别在build/Debugbuild/Release下运行cmake,每个目录都会有自己的compile_commands.json,对应不同的构建配置。

如果是想把同一份数据库复制到多个目录(比如src和include各放一份),可以用CMake的 post-build 命令自动复制:

# 替换成你的实际目标名称
add_custom_command(
    TARGET your_main_target POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/compile_commands.json ${CMAKE_SOURCE_DIR}/src/
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/compile_commands.json ${CMAKE_SOURCE_DIR}/include/
)

不过说实话,更推荐的做法是让LSP直接指向build目录里的那份数据库,比如在Vim里设置clangd的参数:

let g:clangd_args = ['-compile-commands-dir=' . getcwd() . '/build']

这样不用复制文件,每次构建后数据库自动更新,LSP也能实时获取最新的编译参数。

内容的提问来源于stack exchange,提问作者Spencer Duball

火山引擎 最新活动