简介
cscope是一款用于浏览C源码的工具,类似于ctags,但强大得多。
下文以leveldb代码库为例,讲述cscope的使用方法。
创建cscope数据库
在代码库的根目录下执行:
$ cscope -Rbq
将产生cscope.out、cscope.in.out和cscope.po.out三个文件。
各个选项的含义如下:
-b:仅构建交叉引用(cross-reference)文件,即数据库,然后退出,而不会进入下面的交互界面:
-R:递归解析所有的子目录。
-q:通过倒排索引加速符号的查找过程。该选项会导致cscope额外产生cscope.in.out和cscope.po.out两个文件。
$ file cscope.out
cscope.out: cscope reference data version 15 with inverted index
相关命令
所有的cscope命令都以:cscope(:cs)开头。:表示这些命令均在vim的一般模式下执行。
以下逐一介绍cscope的子命令。
add(增加一个新的cscope数据库/连接)
用法
:cs add {file|dir} [pre-path] [flags]
例子
# 当前在./table目录,把根目录下的cscope.out加进来:
:cs add ../cscope.out /home/xhb/code/os/test-leveldb/leveldb-master -C
# 此时执行查找操作,会得到两个匹配项:
# /home/xhb/code/os/test-leveldb/leveldb-master/include/leveldb/table_builder.h
# /home/xhb/code/os/test-leveldb/leveldb-master/table/table_builder.cc
匹配项中的/home/xhb/code/os/test-leveldb/leveldb-master即为add指定的pre-path参数,而-C指定了搜索时忽略大小写。
如果不指定pre-path呢?
:cs add ../cscope.out
# 则查找结果就是:
# include/leveldb/table_builder.h
# table/table_builder.cc
如果当前目前下有cscope.out文件,则打开vim时会自动加载该数据库。
只有把cscope数据库加到vim中,才能进行后续的find操作。
find(查找)
用法
cs find {querytype} {name}
querytype(!!)
0或s:查找这个(指name参数,下同)C符号。
1或g:查找这个定义。
2或d:查找被这个函数调用的函数。
3或c:查找调用该函数的函数。
4或t:查找这个文本字符串。
6或e: 查找这个egrep的pattern。
7或f:查找这个文件。
8或i:查找#include了这个文件的所有文件。
除了4和6,其他类型下的name参数前面的空格都被忽略。
如果匹配项只有一个,则直接跳转到那里;如果有多个,则可以选择跳到哪一个。
例子
查找文件名中包含builder的文件:
:cs find f builder
# 结果如下:
Cscope tag: builder
# line filename / context / line
1 1 db/builder.cc <<<unknown>>>
2 1 db/builder.h <<<unknown>>>
3 1 include/leveldb/table_builder.h <<<unknown>>>
4 1 table/block_builder.cc <<<unknown>>>
5 1 table/block_builder.h <<<unknown>>>
6 1 table/table_builder.cc <<<unknown>>>
对于#include的头文件,如果在当前目录下找不到,cscope甚至会搜索标准目录(/usr/include/等)。比如:
:cs find f stdlib.h
# 结果如下:
Cscope tag: stdlib.h
# line filename / context / line
1 1 /usr/include/stdlib.h <<<unknown>>>
2 1 /usr/include/bits/stdlib.h <<<unknown>>>
基于当前光标所在处的单词进行查找:
# 当前光标停留在filter_policy上
:cs find f <cfile>
# 直接跳转到include/leveldb/filter_policy.h
# 当前光标停留在WriteBlock上
:cs find t <cword>
# 效果等同于:cs find t WriteBlock
其他辅助用法
Ctrl-t(!!)
假设A调用了B,B调用了C,我们刚开始在A处,通过:cs find g B跳到了B的定义,再跳到了C的定义,则通过Ctrl-t,我们可以回到B,再回到A。这里实际上维护了一个栈。
:scscope(:scs)(!!)
与:cs做的事情一样,但它会有分屏的效果。
# 水平分屏
:scs find f block_builder.cc
# 垂直分屏
:vert scs find f table_builder.cc
对于多个分屏的窗口,常用的操作有:
Ctrl-w Ctrl-w:在不同窗口间跳转。
hide:关闭当前窗口。
only:仅保留当前窗口。
show(显示所有的cscope连接)
:cs show
# 结果如下:
# pid database name prepend path
0 8380 cscope.out <none>
8380为cscope进程的ID,通过ps可以看到vim进程为cscope进程的父进程,通过lsof可以看到它们之间通过pipe通信。
kill(断开cscope连接)
:cs show
# 结果如下:
# pid database name prepend path
0 8380 cscope.out <none>
# 则可以这样断开该连接:
:cs kill 0
# 而断开全部连接是这样:
:cs kill -1
reset(重新初始化所有cscope连接)
cscope选项
使用:set设置所有的选项。理想的做法是在启动文件(如.vimrc)中做这件事,因为一些cscope变量只在.vimrc中有效,vim启动后再设置它们将没有效果。
cscopeprg(csprg)
指定执行cscope的命令,默认就是"cscope"。比如:
:set csprg=/usr/bin/cscope。
cscopequickfix(csqf)
是否使用quickfix窗口显示cscope的结果。需要在编译vim时指定+quickfix,才能启用该选项。默认值为""。
比如:set cscopequickfix=s-,c-,d-,i-,t-,e-,s/c/d/i/t/e即:cs find的querytype,其后的标志可以有+(将结果追加到quickfix窗口)、-(清空上一次的结果)、0(不使用quickfix。这里对于querytype=f,没有指定也相当于标志为0)。
例子
对于querytype=f,不指定标志时:
:set cscopequickfix=s-,c-,d-,i-,t-,e-
# 没有对querytype=f指定使用quickfix窗口,所以:cs find f builder的结果以位置列表(location list)的方式显示
Cscope tag: builder
# line filename / context / line
1 1 builder.cc <<<unknown>>>
2 1 builder.h <<<unknown>>>
3 1 table_builder.h <<<unknown>>>
4 1 block_builder.cc <<<unknown>>>
5 1 block_builder.h <<<unknown>>>
6 1 table_builder.cc <<<unknown>>>
对于querytype=f,指定标志为-时:
:set cscopequickfix=s-,c-,d-,i-,t-,e-,f-
# 此时执行:cs find f builder,在vim窗口底部会显示:
(1 of 6): <<<unknown>>>
使用quickfix窗口的好处是,可以在搜索结果的多个匹配项间进行跳转,而位置列表的方式则只能选择一个项。
关于多个quickfix窗口的命令,常用的如下(!!):
:cnext/:cn:切换到下一个。
:cprev/:cp:切换到上一个。
:clist:列出所有项。
:cr:切换到第一个。
:cla:切换到最后一个。
对于querytype=f,指定标志为+时:
:set cscopequickfix=s-,c-,d-,i-,t-,e-,f+
# 则:cs find f builder每次的结果都会“累加”,比如执行10次就会有6*10=60个匹配项
cscopetag(cst)
设置之后,:tag/Ctrl-]/vim -t将使用:cstag,而不是默认的:tag,即cscope数据库和tag文件均用于搜索。
:set cst # :set nocst(默认)
在cscope数据库中搜索时,:cstag和:cs find g等价;在tag文件中搜索时,:cstag和:tjump等价。
cscopetagorder/csto
指定:cstag的搜索顺序。0表示先搜索cscope数据库,若不匹配,再搜索tag文件,1则相反。
:set csto=1 # 默认为0
cscopeverbose/csverb
若不设置(默认),则增加cscope数据库时,将不会打印成功或失败信息。
:set csverb
:set nocsverb
cscopepathcomp/cspc
指定在查找结果中显示多少级文件路径。默认值0表示显示全路径(不是linux系统的全路径,比如如果没有设置pre-path,则block_builder.cc的全路径是table/block_builder.cc),1表示只显示文件名,等等。
例子:
:set cspc=3
# :cs find f table_builder的查找结果:
Cscope tag: table_builder
# line filename / context / line
1 1 include/leveldb/table_builder.h <<<unknown>>>
2 1 table/table_builder.cc <<<unknown>>>
:set cspc=1
# :cs find f table_builder的查找结果:
Cscope tag: table_builder
# line filename / context / line
1 1 table_builder.h <<<unknown>>>
2 1 table_builder.cc <<<unknown>>>
快捷键映射
TODO
参考资料
- vim(7.2) :help cscope
- cscope man page
- http://cscope.sourceforge.net/
- https://www.cs.oberlin.edu/~kuperman/help/vim/windows.html