vscode_intellisence

简介

最近C++代码越写越多,也有不少同学问我这种炫酷的C++代码提示是怎么在Mac上实现的。我自己日常会使用NVim来作为主力编辑器,而使用VSCode来进行断点调试和提交Git Commits。我会以MacOS系统为例配置这两种方案,大家根据自己需求,选择其中一种即可(推荐VSCode)

Sec. 1 VSCode

首先是要安装 C/C++ 拓展,启动VSCode以后在拓展里搜索安装即可。然后让我们找个(或者新建)一个空的文件夹,例如我选择了 ~/Code/clang/playground,使用VSCode打开它。接着新建 .vscode 文件夹,在该文件夹下新建文件 c_cpp_properties.json 文件:

{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${default}",
                "${workspaceFolder}"
                "/usr/local/opt/root/include/root",
            ],
            "compilerPath": "/usr/bin/g++",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

所有你需要进行智能提示的库,你都要写到 “includePath” 中,例如在上面的例子我添加了root库的inlude路径。另外你可能需要更改 “compilerPath” ,你可以在终端里输入 which g++ 来看到g++的路径。然后让我们来测试一下它是否能够工作,新建一个 main.cc 文件,如下:

#include <TFile.h>
#include <TCanvas.h>
#include <TGraph.h>
#include <TAxis.h>

int main() {
    int n = 20;
    // create canvas and graph
    auto c1 = new TCanvas("c1","A Simple Graph Example",200,10,700,500);
    auto gr = new TGraph(n);
    // set mock sin data
    for(int i=0; i<n ;i++)
        gr->SetPoint(i, i*0.1, 10*sin(i*0.1+0.2));
    // set graph styles
    gr->SetLineColor(2);
    gr->SetLineWidth(4);
    gr->SetMarkerColor(4);
    gr->SetMarkerStyle(21);
    gr->SetTitle("a simple graph");
    gr->GetXaxis()->SetTitle("X title");
    gr->GetYaxis()->SetTitle("Y title");
    gr->Draw("ACP");

    // write canvas as a pdf file
    c1->SaveAs("curve.pdf");
}

其实你在编写上面这段代码的时候,已经能够使用代码补全与智能提示了。编写完成以后,你可以手动使用g++来编译并且运行它。

# compile main program
g++ -std=c++17 main.cc -o main.o `root-config --cflags --libs`
# run it!
./main.o

那么现在我们已经把root的开发环境搭建好了,大部分简单的数据分析都可以通过新建 mainxx.cc 并且手动编译运行的方法来做,你也完全可以自己在这个基础上集成更多的第三方库(e.g. Pythia8, FastJet, etc.)。接下来我们要实现断点调试,这在你debug的时候极其有用(再也不用std::cout了!),你需要在 .vscode 目录下新建两个文件,分别是 launch.jsontasks.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "g++ - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}.o",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "lldb",
            "preLaunchTask": "C/C++: g++ build active file"
        }
    ]
}
{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: g++ build active file",
            "command": "/usr/bin/g++",
            "args": [
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}.o",
                "-std=c++17",
                "-stdlib=libc++",

                "-I/usr/local/opt/root/include/root/",
                "-L/usr/local/opt/root/lib/root/",
                "-lCore", "-lImt", "-lRIO", "-lNet", "-lHist", "-lGraf",
                "-lGraf3d", "-lGpad", "-lROOTVecOps", "-lTree", "-lTreePlayer",
                "-lRint", "-lPostscript", "-lMatrix", "-lPhysics", "-lMathCore",
                "-lThread", "-lMultiProc", "-lROOTDataFrame",
                "-lpthread", "-lm", "-ldl"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        }
    ],
    "version": "2.0.0"
}

需要注意root运行库的编译参数其实是很多的,如果你不需要使用root库,那可以把args里从 "-I/usr/local/opt/root/include/root/" 开始后面的几行删去,之后打开你的 main.cc 文件,尝试在行数上打个断点,点击VSCode左侧面板的运行按钮,就可以直接运行并且Debug代码啦!甚至你可以设置条件断点,例如:

vscode_debug

现在的目录结构如下:

playground
│
└─── .vscode
│      c_cpp_properties.json
│      lauhch.json
│      tasks.json
│
└─── main.cc
└─── main.o
└─── curve.pdf

大概讲一下这几个文件的作用:

  • c_cpp_properties.json 这个文件主要是用来配置代码补全与智能提示的,一般而言你只需要配置 include path 即可。
  • tasks.json 这个文件主要是当你点击VSCode左侧的运行按钮时,其实也是需要编译的,它掌管着编译所需要提供的参数路径等。
    1. 第一是库的 include path,e.g. -I/path_of_include
    2. 第二是库的 lib path,e.g. -L/path_of_lib
    3. 第三是告诉 linker,e.g. -lpythia8

Sec. 2 NVim

vim_intellisence

Good news to Vimer! 这部分仅推荐给Vim爱好者使用,一般用户看到这里就可以关掉了。经过我的测试发现,NVim + VimPlug + coc.nvim + ccls 能够获得极好的代码编辑体验!流畅、轻量、稳定,还能结合 TMux 来获得本地/服务器上相同的编辑体验。

这里只说一下MacOS上的安装,Linux用户安装很类似,具体请阅读各部分Github Readme上给出的安装方法。

# install nvim
brew install nvim
# install vim-plug
sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
       https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
# install nodejs, required by coc.nvim
brew install node
# install yarn, required by coc.nvim
brew install yarn
# install ccls
brew install ccls

接着就是使用 vim-plug 来安装 coc.nvim,注意NVim的配置文件是在 ~/.config/nvim/init.vim 中的。以下是基础的配置,你可以作为参考,我还安装了 ctrlp 快速搜索文件插件,与 gruvbox 配色。

call plug#begin('~/.local/share/nvim/plugged')
Plug 'kien/ctrlp.vim'
Plug 'morhetz/gruvbox'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
call plug#end()

set encoding=utf-8

syntax enable
set background=dark
colorscheme gruvbox

set autoindent
set tabstop=4
set softtabstop=4
set shiftwidth=4
set fileformat=unix

set nu
set cursorline
set hlsearch 
set mouse=v

保存完毕以后,在终端打开nvim(输入nvim回车即可,你会看到一些错误信息,别在意,插件安装完毕以后就消失了),输入 :PlugInstall 开始安装这些插件与配色。

你可以在 Language-Server 中找到支持代码补全和提示的语言,这里我们只考虑C++,所以之前只安装了ccls,其他的语言大家可以根据自己需要酌情安装。再次打开nvim,输入 :CocConfig,将以下内容保存好:

{
	"languageserver": {
		"ccls": {
			"command": "ccls",
			"filetypes": ["c", "cc", "cpp", "c++", "objc", "objcpp"],
			"rootPatterns": [".ccls", "compile_commands.json", ".git/", ".hg/"],
			"initializationOptions": {
					"cache": {
						"directory": "/tmp/ccls"
					},
					"clang": {
						"extraArgs": [
							"-isystem/usr/local/include",
							"-isystem/Library/Developer/CommandLineTools/usr/include/c++/v1",
							"-isystem/Library/Developer/CommandLineTools/usr/lib/clang/12.0.0/include",
							"-isystem/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include",
							"-isystem/Library/Developer/CommandLineTools/usr/include"
						]
					}
				}
		}
	}
}

需要注意的是,这里的 “extraArgs” 仅针对 MacOS BigSur 系统,因为标准库的路径在BigSur中被更改了(Linux用户请把extraArgs这段参数删去)。

完成所有的安装和配置以后,让我们回到之前的 ~/Code/clang/playground 文件夹中(参看上一小节)。新建一个 .ccls 文件,它包含了代码补全与智能提示的库包含路径:

clang
-std=c++17
-stdlib=libc++
-I/usr/local/opt/root/include/root

你现在可以尝试用nvim来编辑文件,例如上一小节中的 main.cc 文件,可以有很cooooool的补全和提示。我还没有探索过如何用这一套组合进行编译/Debug,如果你能找到很好的方法请一定要告诉我。