介绍一下gnu global,比cscope更方便更快速的索引工具

12 篇文章 1 订阅

http://forum.ubuntu.org.cn/viewtopic.php?f=68&t=343460

貌似vim众很少用gnu global啊,都只见着emacs众在用,我觉得有必要在vim众中推广一下。

gnu global是一个类似cscope的工具,也能提供源文件之间的交叉索引。

其独到之处在于,当你生成索引文件以后,再修改整个项目里的一个文件,然后增量索引的过程非常快。

安装过程就不说了,根据各自发行版不同,自个儿装吧。

安装好以后,有global、gtags、gtags-cscope三个命令。global是查询,gtags是生成索引文件,gtags-cscope是与cscope一样的界面。

example:
代码:
$ cd project/
$ gtags


这样就生成了整个目录的索引文件,包括GTAGS、GRTAGS、GPATH三个文件。

你也可以先用find命令生成一个文件列表,叫gtags.files,然后再执行gtags,就会只索引gtags.files里的文件。

example:
代码:
$ cd project/
$ find . -name "*.[ch]" > gtags.files
$ gtags


查询使用的命令是global和gtags-cscope。前者是命令行界面,后者是与cscope兼容的ncurses界面。这里就不多介绍了,重点是如何在vim里查询:

首先进入vim,然后:

example
代码:
:set cscopeprg=gtags-cscope
:cs add GTAGS


然后就可以像cscope一样,用cs find g等命令进行查询了。

当我们更改了某个文件以后,比如project/subdir1/subdir2/file1.c,想更新索引文件(索引文件是project/GTAGS),只消这样:

example:
代码:
$ cd project/subdir1/subdir2/
$ vim file1.c
$ global -u


global -u这个命令会自动向上找到project/GTAGS,并更新其内容。而gtags相对于cscope的优势就在这里:增量更新单个文件的速度极快,几乎是瞬间完成。有了这个优势,我们就可以增加一个autocmd,每次:w的时候自动更新索引文件。

我的设置如下:
代码:
" settings of cscope.
" I use GNU global instead cscope because global is faster.
set cscopetag
set cscopeprg=gtags-cscope
set cscopequickfix=c-,d-,e-,f-,g0,i-,s-,t-
nmap <silent> <leader>j <ESC>:cstag <c-r><c-w><CR>
nmap <silent> <leader>g <ESC>:lcs f c <c-r><c-w><cr>:lw<cr>
nmap <silent> <leader>s <ESC>:lcs f s <c-r><c-w><cr>:lw<cr>
command! -nargs=+ -complete=dir FindFiles :call FindFiles(<f-args>)
au VimEnter * call VimEnterCallback()
au BufAdd *.[ch] call FindGtags(expand('<afile>'))
au BufWritePost *.[ch] call UpdateGtags(expand('<afile>'))
 
function! FindFiles(pat, ...)
     let path = ''
     for str in a:000
         let path .= str . ','
     endfor
 
     if path == ''
         let path = &path
     endif
 
     echo 'finding...'
     redraw
     call append(line('$'), split(globpath(path, a:pat), '\n'))
     echo 'finding...done!'
     redraw
endfunc
 
function! VimEnterCallback()
     for f in argv()
         if fnamemodify(f, ':e') != 'c' && fnamemodify(f, ':e') != 'h'
             continue
         endif
 
         call FindGtags(f)
     endfor
endfunc
 
function! FindGtags(f)
     let dir = fnamemodify(a:f, ':p:h')
     while 1
         let tmp = dir . '/GTAGS'
         if filereadable(tmp)
             exe 'cs add ' . tmp . ' ' . dir
             break
         elseif dir == '/'
             break
         endif
 
         let dir = fnamemodify(dir, ":h")
     endwhile
endfunc
 
function! UpdateGtags(f)
     let dir = fnamemodify(a:f, ':p:h')
     exe 'silent !cd ' . dir . ' && global -u &> /dev/null &'
endfunction


解释几句:

1. 我增加了一个命令叫FindFiles,是用来生成gtags.files文件的,用法如下:

代码:
:FindFiles {pattern} subdir1 subdir2 ...


然后找到的文件就会都添加到当前buffer的最后。

比如,我们用git刚下下来一整套kernel的源码,放在linux-2.6目录下,然后我想生成列表文件,就可以这样:

代码:
:e gtags.files
:FindFiles **/*.[ch] arch/x86 arch/arm block crypto ...
:w


只增加自己想要的目录,而不要的就不增加。

2. 我添加了三条autocmd,其中:

代码:
au VimEnter * call VimEnterCallback()
au BufAdd *.[ch] call FindGtags(expand('<afile>'))


这两条命令会在你打开一个c文件的时候,自动向上查找GTAGS文件,找到以后就会执行:cs add命令添加这个GTAGS文件。

代码:
au BufWritePost *.[ch] call UpdateGtags(expand('<afile>'))


这条命令会在你修改一个c文件并:w以后,自动进入c文件所在目录并执行"global -u"更新索引文件。

最后,还有一个问题,cscope有一个-f参数,这个参数可以指定cscope.out文件的路径。而gtags-cscope的哲学不一样,它是自己一路向上寻找GTAGS文件,所以没有-f参数。而vim调用:cs add的时候,是会使用-f参数的。这样,当:cs add GTAGS文件的时候,就不能指定当前目录的子目录以外的路径。这也导致:cs add命令只能使用一个GTAGS文件。

针对这个问题,我写了一个vim的patch http://forum.ubuntu.org.cn/viewtopic.php?f=68&t=342099,在fork出gtags-cscope子进程以后会把子进程chdir()到GTAGS文件所在的目录,这样就OK了。




diff -r f33296ed67ea src/if_cscope.c
--- a/src/if_cscope.c	Wed Aug 17 20:33:23 2011 +0200
+++ b/src/if_cscope.c	Thu Aug 18 10:13:26 2011 +0800
@@ -960,7 +960,27 @@
 
 	/* run the cscope command; is there execl for non-unix systems? */
 #if defined(UNIX)
-	(void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
+#include <unistd.h>
+#include <libgen.h>
+
+        if (strcmp(prog, "gtags-cscope") == 0)
+        {
+            char *fname = NULL, *dname = NULL;
+
+            fname = strdup(csinfo[i].fname);
+            if (fname)
+            {
+                dname = dirname(fname);
+                (void)chdir(dname);
+                free(fname);
+            }
+
+            (void)sprintf(cmd, "exec %s -dl", prog);
+        }
+        else
+        {
+            (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname);
+        }
 #else
 	/* WIN32 */
 	(void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname);


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值