本文引用自 http://forum.ubuntu.org.cn/viewtopic.php?f=68&t=343460
http://blog.chinaunix.net/uid-20416834-id-120183.html 感谢作者们
gnu global是一个类似cscope的工具,也能提供源文件之间的交叉索引。
其独到之处在于,当生成索引文件以后,再修改整个项目里的一个文件,然后增量索引的过程非常快。
安装过程省略。
安装好以后,有global、gtags、gtags-cscope三个命令。global是查询,gtags是生成索引文件,gtags-cscope是与cscope一样的界面。
example:
$ gtags
这样就生成了整个目录的索引文件,包括GTAGS、GRTAGS、GPATH三个文件。
你也可以先用find命令生成一个文件列表,叫gtags.files,然后再执行gtags,就会只索引gtags.files里的文件。
example:
$ find . -name "*.[ch]" > gtags.files
$ gtags
查询使用的命令是global和gtags-cscope。前者是命令行界面,后者是与cscope兼容的ncurses界面。这里就不多介绍了,重点是如何在vim里查询:
首先进入vim,然后:
example
:cs add GTAGS
然后就可以像cscope一样,用cs find g等命令进行查询了。
当我们更改了某个文件以后,比如project/subdir1/subdir2/file1.c,想更新索引文件(索引文件是project/GTAGS),只需这样:
example:
$ vim file1.c
$ global -u
global -u这个命令会自动向上找到project/GTAGS,并更新其内容。而gtags相对于cscope的优势就在这里:增量更新单个文件的速度极快,几乎是瞬间完成。有了这个优势,我们就可以增加一个autocmd,每次:w的时候自动更新索引文件。
我的设置如下:
" 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文件的,用法如下:
然后找到的文件就会都添加到当前buffer的最后。
比如,我们用git刚下下来一整套kernel的源码,放在linux-2.6目录下,然后我想生成列表文件,就可以这样:
:FindFiles **/*.[ch] arch/x86 arch/arm block crypto ...
:w
只增加自己想要的目录,而不要的就不增加。
2. 我添加了三条autocmd,其中:
au BufAdd *.[ch] call FindGtags(expand('<afile>'))
这两条命令会在你打开一个c文件的时候,自动向上查找GTAGS文件,找到以后就会执行:cs add命令添加这个GTAGS文件。
这条命令会在你修改一个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了。
Global源码标签工具支持C,C++,YACC,JAVA,PHP4,ASM。并且可以与shell,vi,emacs,浏览器,doxygen等等配合使用。也是款不错的工具。
$cd /usr/src/linux
$gtags
-
$ls G* GPATH GRTAGS GSYMS GTAGS
-
$global start_kernel arch/alpha/boot/bootp.c arch/alpha/boot/bootpz.c arch/alpha/boot/main.c init/main.c
查询函数引用:-r
-
$global -r start_kernel arch/blackfin/mach-bf548/head.S arch/frv/kernel/debug-stub.c arch/mn10300/kernel/gdb-stub.c ...
使用POSIX标准正则
-
$global 'ah[46]_init' net/ipv4/ah4.c net/ipv6/ah6.c
显示函数详细信息 -x
-
$global -x ah4_init ah4_init 321 net/ipv4/ah4.c static int __init ah4_init(void)
显示文件所在绝对路径 -a
-
$global -a ah4_init /usr/src/linux-source-2.6.26/net/ipv4/ah4.c
查看'GTAGS'没有定义的符号 -s
-
global -xs X |more X 161 arch/alpha/kernel/setup.c #define WEAK(X) \ X 39 arch/arm/common/dmabounce.c #define DO_STATS(X) do { X ; } while (0) X 41 arch/arm/common/dmabounce.c #define DO_STATS(X) do { } while (0) ...
有点类似egrep命令 -g
-
$global -xg 'Linus Torvalds' | more Linus%20Torvalds 8 arch/alpha/boot/bootp.c * based significantly on the arch/alpha/boot/main.c of Linus Torvalds Linus%20Torvalds 9 arch/alpha/boot/bootpz.c * based significantly on the arch/alpha/boot/main.c of Linus Torvalds Linus%20Torvalds 4 arch/alpha/boot/main.c * Copyright (C) 1994, 1995 Linus Torvalds ...
按文件名查找 -P
-
$global -P 'head\.S$' arch/alpha/boot/head.S arch/alpha/kernel/head.S arch/arm/boot/compressed/head.S arch/arm/kernel/head.S ...
显示文件中对象 -f
-
$global -f net/ipv4/af_inet.c DEFINE_SNMP_STAT 119 net/ipv4/af_inet.c DEFINE_SNMP_STAT(struct linux_mib, net_statistics) __read_mostly; inet_autobind 174 net/ipv4/af_inet.c static int inet_autobind(struct sock *sk) inet_listen 194 net/ipv4/af_inet.c int inet_listen(struct socket *sock, int backlog) ...
限制在当前目录查找 -l
-
$cd net/ipv4/ $global -l ah[46]_init ah4.c
3.其它用法例子
-
$ find . -type f -print >/tmp/list # make a file set $ vi /tmp/list # customize the file set $ gtags -f /tmp/list
给只读文件夹生成源码标签数据库,例如cdrom上的源码,数据库文件不能放在当前目录下,这种情况可以使用GTAGSROOT环境变量
-
$ mkdir /var/dbpath $ cd /cdrom/src # the root of source tree $ gtags /var/dbpath # make tag files in /var/dbpath $ export GTAGSROOT=`pwd` $ export GTAGSDBPATH=/var/dbpath $ global func
设置多个搜寻目录
-
$ pwd /develop/src/mh # this is a source project $ gtags $ ls G*TAGS GRTAGS GTAGS $ global mhl uip/mhlsbr.c # mhl() is found $ global strlen # strlen() is not found $ (cd /usr/src/lib; gtags) # library source $ (cd /usr/src/sys; gtags) # kernel source $ export GTAGSLIBPATH=/usr/src/lib:/usr/src/sys $ global strlen ../../../usr/src/lib/libc/string/strlen.c # found in library $ global access ../../../usr/src/sys/kern/vfs_syscalls.c # found in kernel
查询某个对象全名称 -c
$global -c start_k
start_kcs_transaction
start_kernel
start_kernel_proc
start_kernel_thread
4.与应用程序配合使用
-
$gtags $htags
完成后在当前目录下多个HTML目录。htags有很多选项,如果不熟悉的话,建议使用--suggest选项
-
$mkdir ~/.vim $mkdir ~/.vim/plugin $cp /usr/share/doc/global/examples/gtags.vim.gz ~/.vim/plugin/ $cd ~/.vim/plugin $gzip -d gtags.vim.gz
vim+gtags简单用法:
:Gtags start_kernel //打开函数浏览
[Quickfix List]操作
:cn //切换下一个文件
:cp //切换前一个文件
:ccN //N为数字,切换到指定序号文件
:cl //查看整个列表
:h quickfix //list帮助
-
$vim '+Gtags start_kernel'