轉自:https://juejin.cn/post/6971437759701450765
這一篇聊聊我們如何通過 vim
瀏覽代碼
代碼瀏覽最重要的就是跟蹤代碼, 跟蹤定義, 跟蹤聲明, 跟蹤調用, 跟蹤引用...
vim 的跟蹤通常可以通過兩種方式實現:
- tags: 通過
ctags
工具生成 tags 文件 - cscope 數據庫: 通過
cscope
或gtags-cscope
生成 cscope 數據庫
兩種方法各有優缺點, 而且可以搭配使用, 並不沖突. 下面逐個介紹.
ctags
ctags
定義: 產生標記文件以幫助在源文件中定位對象. 包含以下對象:
class names
(類名)macro definitions
(宏定義)enumeration names
(枚舉名)enumerators
(枚舉變量)function definitions
(函數定義)function prototypes
/declarations
(函數定義 / 聲明)class
,interface
,struct
, andunion data members
(類, 接口, 結構體, 聯合體)structure names
(結構體名)typedefs
(別名)union names
(聯合體名)variables
(definitions
andexternal declarations
) 變量
安裝 ctags
我們一般所說的 ctags 分為兩種
- Exuberant Ctags: 這個是正統的
Ctags
, 但是年久失修, 上一次更新還是 2009 年 - Universal Ctags: 是老
Exuberant Ctags
的一個fork
版本, 繼承了其所有優點, 並且直到現在還在活躍更新
綜上所述, 建議安裝 Universal Ctags
, 使用如下方式安裝即可
brew install --HEAD universal-ctags/universal-ctags/universal-ctags
復制代碼
生成 tags
使用 ctags -R –c++-kinds=+px –fields=+iaS –extra=+q .
可以將當前目錄下的所有文件內容進行處理生成 ./tags
文件, 這些選項的作用如下:
-R
: ctags 循環生成子目錄的 tags--c++-kinds=+pxl
:ctags
記錄c++
文件中的函數聲明和各種外部和前向聲明 (l
表示記錄局部變量, 可以認為是local
的縮寫)--fields=+iaS
:ctags
要求描述的信息, 其中 i 表示如果有繼承, 則標識出父類; a 表示如果元素是類成員的話, 要標明其調用權限 (即是 public 還是 private); S 表示如果是函數, 則標識函數的 signature.extra=+q
: 強制要求ctags
做如下操作: 如果某個語法元素是類的一個成員,ctags
默認會給其記錄一行, 可以要求ctags
對同一個語法元素再記一行, 這樣可以保證在 VIM 中多個同名函數可以通過路徑不同來區分.
配置 tags 路徑
生成了 tags
文件后, 我們要讓 vim 找的到當前瀏覽的文件所對應的是哪個 tags
文件, 我們在 ~/.vimrc
中應該加上這樣的配置
set tags=./tags;,tags 復制代碼
前半部分 ./.tags;
代表在文件的所在目錄下查找名字為 .tags
的符號文件, 后面一個分號代表查找不到的話向上遞歸到父目錄, 直到找到 tags
文件或者遞歸到了根目錄還沒找到; 逗號分隔的后半部分 tags
是指同時在 vim
的當前目錄 (:pwd
命令返回的目錄, 可以用 :cd ..
命令改變) 下面查找 tags
文件.
使用 tags
tags
的使用非常簡單, 把光標移動到某個元素上, CTRL+]
就會跳轉到對應的定義, CTRL+o
可以回退到原來的地方.
另外也有一些其他的 tags
相關命令可以使用:
:tag func
: 跳轉到func
函數實現的地方:tnext
: 下一個標簽匹配處:tprev
: 上一個標簽匹配處:tfirst
: 第一個標簽匹配處:tlast
: 最后一個標簽匹配處:tags
: 所有匹配的標簽:tselect
: 顯示所有匹配的標簽並讓你選擇指定的
cscope
cscope
是類似於 ctags
一樣的工具, 但可以認為是 ctags
的增強版, 因為她比 ctags
能夠做更多的事:
- 符號在哪里使用的?
- 符號在哪里定義的?
- 變量從哪里得到它的值的?
- 全局變量的定義?
- 這個函數在源代碼中的什么文件中?
- 什么函數調用了這個函數?
- 這個函數調用了什么函數?
- 消息
out of space
來自哪里? - 這個源文件在目錄中的結構?
- 哪些文件包含了這個頭文件?
cscope 如何使用
在終端中的項目路徑中使用 cscope -Rbkq
:
R
: 表示把所有子目錄里的文件也建立索引b
: 表示cscope
不啟動自帶的用戶界面, 而僅僅建立符號數據庫q
: 生成cscope.in.out
和cscope.po.out
文件, 加快 cscope 的索引速度k
: 在生成索引文件時, 不搜索/usr/include
目錄
通常我們使用 cscope -Rb
可以在當前路徑下得到 cscope.out
cs 是 cscope 的簡寫命令, 后面也是如此.
然后在 vim
中使用 :cs add cscope.out
: 添加一個新的 cscope 數據庫鏈接. 之后便可以在 vim
中使用 :cs ...
的一系列命令了
:cs show
: 查看當前已經鏈接的 cscope 數據庫鏈接:cs a ...
: Find assignments to this symbol:cs c ...
: Find functions calling this function:cs d ...
: Find functions called by this function:cs e ...
: Find this egrep pattern:cs f ...
: Find this file:cs g ...
: Find this definition:cs i ...
: Find files #including this file:cs s ...
: Find this C symbol:cs t ...
: Find this text string
gtags
gtags
, 全名為 gnu global
, 是一個類似 cscope
的工具(不是 ctags
的替代品!), 也能提供源文件之間的交叉索引. 其獨到之處在於, 當生成索引文件以后, 再修改整個項目里的一個文件, 然后增量索引的過程非常快.
安裝
brew install global
復制代碼
安裝好以后, 有 global
, gtags
, gtags-cscope
三個命令. global
是查詢, gtags
是生成索引文件, gtags-cscope
是與 cscope
一樣的界面.
gtags
環境配置
gtags
是支持使用 ctags/universal-ctags
或者 pygments
來作為分析前端支持 50+ 種語言. 使用 ctags/universal-ctags
作為前端只能生成定義索引不能生成引用索引, 因此我們要安裝 pygments
, 保證你的 $PATH
里面有 python
, 接着:
pip install pygments
復制代碼
保證在環境里里要設置過如下兩個環境變量:
export $GTAGSLABEL = 'native-pygments' export $GTAGSCONF = '/path/to/share/gtags/gtags.conf' 復制代碼
第一個 GTAGSLABEL
告訴 gtags
默認 C/C++/Java
等六種原生支持的代碼直接使用 gtags
本地分析器, 而其他語言使用 pygments
模塊. 第二個環境變量必須設置, 否則會找不到 native-pygments
和 language map
的定義, Mac 下的路徑為 /usr/local/share/gtags
, 可以把它拷貝成 ~/.globalrc
實際使用 pygments
時, gtags
會啟動 python
運行名為 pygments_parser.py
的腳本, 通過管道和它通信, 完成源代碼分析, 故需保證 gtags
能在 $PATH
里調用 python
, 且這個 python
安裝了 pygments
模塊.
gtags
使用
$ cd project/ $ gtags 復制代碼
gtags
遍歷子目錄, 從源碼文件中提取符號, 這樣就生成了整個目錄的索引文件, 包括 GTAGS
, GRTAGS
, GPATH
三個數據庫文件.
GTAGS
: 定義數據庫GRTAGS
: 引用數據庫GPATH
: 路徑名數據庫
也可以先用 find
命令生成一個文件列表, 叫 gtags.files
, 然后再執行 gtags
, 就會只索引 gtags.files
里的文件.
$ cd project/ $ find . -name "*.[ch]" > gtags.files $ gtags 復制代碼
gtags-cscope
在 vim
中的使用
查詢使用的命令是 global
和 gtags-cscope
. 前者是命令行界面, 后者是與 cscope
兼容的 ncurses
界面. 這里就不多介紹了, 重點是如何在 vim
里查詢:
首先進入 vim, 然后:
:set cscopeprg=gtags-cscope :cs add GTAGS 復制代碼
然后就可以像 cscope
一樣, 用 cs find g
等命令進行查詢了.
gtags-cscope
還有一個優點就是我后台更新了 gtags
數據庫, 不需要像 cscope
一樣調用 cs reset
重啟 cscope
子進程, gtags-cscope
一旦連上永遠不用重啟, 不管你啥時候更新數據庫, gtags-cscope
進程都能隨時查找最新的符號.
當我們更改了某個文件以后, 比如 project/subdir1/subdir2/file1.c
, 想更新索引文件 (索引文件是 project/GTAGS
), 只需這樣:
$ cd project/subdir1/subdir2/ $ vim file1.c $ global -u 復制代碼
global -u
這個命令會自動向上找到 project/GTAGS
, 並更新其內容. 而 gtags
相對於 cscope
的優勢就在這里: 增量更新單個文件的速度極快, 幾乎是瞬間完成. 有了這個優勢, 我們就可以增加一個 autocmd
, 每次 :w 的時候自動更新索引文件.
gutentags
- 一個將 ctags
, cscope
, gtags
串起來的一個自動化工具
gutentags
可以為我們生成數據庫並自動 cs add
添加 gtags
數據庫到 vim
, 在你配置好它之后, 一切皆在后台線程默默完成, 什么都不需要再操心. 可以參考 我的 gutentags
配置
編輯一個項目還好, 如果同時編輯兩個以上的項目, gutentags
會把兩個數據庫都連接到 vim
里, 於是你搜索一個符號, 兩個項目的結果都會同時出現, 基本沒法用了.
這時, 我們可以搭配 skywind3000/gutentags_plus 一起使用, 這個腳本讓已經加載過的數據庫不會重復加載, 非本項目的數據庫會得到即時清理, 所以你根本感覺不到 gtags
的存在, 只管始用 GscopeFind g
命令查找定義, GscopeFind s
命令查找引用, 既不用 care gtags
數據庫加載問題更不用關心何時更新, 你只管寫你的代碼, 打開你要閱讀的項目, 隨時都能通過 GscopeFind
查詢最新結果, 並放入 quickfix
窗口中:
這個小腳本末尾還還定義了一系列快捷鍵:
<leader>cg
: 查看光標下符號的定義<leader>cs
: 查看光標下符號的引用<leader>cc
: 查看有哪些函數調用了該函數<leader>cf
: 查找光標下的文件<leader>ci
: 查找哪些文件 include 了本文件<leader>cd
: Functions called by this function<leader>ct
: Find text string under cursor<leader>ce
: Find egrep pattern under cursor<leader>ca
: Find places where current symbol is assigned<leader>cz
: Find current word in ctags database
設置排除文件類型
ctags
排除與 gtags
排除不一致, 需要手動在 $GTAGSCONF
中設置 skip
最后
我的 vim 配置倉庫: HanleyLee/dotvim
本文作者 Hanley Lee, 首發於 閃耀旅途, 如果對本文比較認可, 歡迎 Follow
作者:HanleyLee
鏈接:https://juejin.cn/post/6971437759701450765
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。