在Emacs中使用GNU Global
背景
在我平时用Emacs编写C代码时,经常需要进行代码的跳转,主要需求为函数定义的跳转,某个具体函数的调用查找,某个结构体的定义跳转以及结构体中具体某一项的跳转等,GNU Global就能完全满足我的这个需求,所以习惯了Emacs的人可以将Source Insight扔开了。
GNU Global简介
GNU Global全称为GNU Global source code tagging system,官方定义为GNU Global是一个可以跨越各种环境的代码标记系统,例如在Emacs,VI,Less Viewer,Bash Shell甚至在Web浏览器中使用。可以通过GNU Global查找局部变量,函数,宏,结构体,类并且方便的跳转到你想要的位置,在进行大型项目开发时,GNUL Global可以包含许多子目录,#ifdef语句和许多main函数,它有点向平时经常使用的ctags和etags,但是有和这两个tag工具比起来GNU Global有以下两点更为强大:
- 和编辑器不具有强绑定关系,所以可以很方便的将其用于各种编辑环境,无论是Emacs的忠实使用者还是Vim的粉丝都可以尽情的使用它来进行代码跳转
- 具有比较强大的查找定义和引用的能力,对于代码阅读来说这个能力已经足够了
GNU Global具有强大的跨平台能力,无论是在Linux还是在BSD系统还是Windows都可以使用。GNU Global具有以下功能:
- 内置6种语法分析程序(定义和引用)C,C++,Yacc,Java,PHP4和汇编
- 通过Ctags的语法解析插件可以支持25中语言(定义和引用)Awk, Dos batch, COBOL, C, C++, C#, Erlang,Fortran, Java, JavaScript, Lisp, Lua, Pascal, Perl, PHP, Python, Ruby, Matlab, OCaml, Scheme, Tcl, TeX, Verilog, Vhdl and Vim
- 在各种不同的编辑环境中能够以相同的方式工作,例如
- Shell命令行
- Bash Shell
- Vi编辑器(Vim)
- Less Viewer
- Emacs编辑器(Emacs,Mule,XEmacs)
- Web浏览器
- Doxygen文档系统
- 通过特殊的符号表快速查找局部变量
- 不仅能够查找定义还可以查找引用
- 允许重复的tags
- 给出匹配的路径
- 默认分层查找
- 不仅仅实在代码级别查找,还可以在库中查找
- 生成补全列表
- 支持多种格式输出
- 允许指定标记文件
- 支持POSIX 1003.2正则表达式
- 支持idutils作为外部搜索引擎
- 生成的tag文件独立于各种体系结构
- 支持随时更新tag文件
- 支持新语言的语法解析插件
- 支持自定义gtags.conf
- 使用压缩格式来节省空间
- 支持C/S环境(TRAMP)
- 默认忽略可执行文件,隐藏文件和特殊文件
- 内置cscope程序(gtags-cscope)
- 内置grep命令(使用-g)
- 能够很好的处理循环符号链
GNU Global使用
命令行下使用GLOBAL,在开始使用之前可以看一下FAQ
$more /your/gtags/path/FAQ
|
的代码时,只需要执行以下命令
$cd ~/code/kernel/
$gtags -v
|
执行完之后会发现,在kernel目录下产生了3个tag文件分别是GPATH,GRTAGS,GTAGS,
GTAGS是定义的数据库,GRTAGS是引用的数据库,GPATH是路径的数据库。
基本用法,加入下面的是我们的目录树
/home/user/ | |-ROOT/ <- the root of source tree (GTAGS,GRTAGS,...) | |- README ..... +---------------+ | |The function of| | +---------------+ |- DIR1/ | | | |- fileA.c ..... +---------------+ | | |main(){ | | | | func1();| | | | func2();| | | |} | | | +---------------+ | | | |- fileB.c ..... +---------------+ | |func1(){ ... } | | +---------------+ |- DIR2/ | |- fileC.c ..... +---------------+ |#ifdef X | |func2(){ i++; }| |#else | |func2(){ i--; }| |#endif | |func3(){ | | func1();| |} | +---------------+ |
相关函数,需要注意的是只能在生成TAG文件的目录及其子目录中搜索:
$ cd /home/user/ROOT $ global func1 DIR1/fileB.c # func1() is defined in fileB.c $ cd DIR1 $ global func1 fileB.c # relative path from DIR1 $ cd ../DIR2 $ global func1 ../DIR1/fileB.c # relative path from DIR2 |
使用global的-r选项获取相关引用:
$ global -r func2 ../DIR1/fileA.c # func2() is referred from fileA.c |
$ cd /home/user/ROOT $ global 'func[1-3]' DIR1/fileB.c # func1, func2 and func3 are matched DIR2/fileC.c |
$ global func2 DIR2/fileC.c $ global -x func2 func2 2 DIR2/fileC.c func2(){ i++; } func2 4 DIR2/fileC.c func2(){ i--; } |
$ global -a func1 /home/user/ROOT/DIR1/fileB.c |
$ global -xs X X 1 DIR2/fileC.c #ifdef X |
$ global -xg '#ifdef' #ifdef 1 DIR2/fileC.c #ifdef X |
-l选项只在当前目录搜索,使用-P选项可以搜索特定模式的路径;
如果想在库中搜索相关符号,则需要在每一个GTAGSLIBPATH中执行gtags
命令:
$ 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 $ ln -s /usr/src/lib . $ ln -s /usr/src/sys . $ gtags $ global strlen lib/libc/string/strlen.c $ global access sys/kern/vfs_syscalls.c |
$ global -c kmem # maybe k..k.. kmem..
kmem_alloc
kmem_alloc_pageable
kmem_alloc_wait
kmem_free
kmem_free_wakeup
kmem_init
kmem_malloc
kmem_suballoc # This is what I need!
$ global kmem_suballoc
../vm/vm_kern.c
$ funcs()
> {
> local cur
> cur=${COMP_WORDS[COMP_CWORD]}
> COMPREPLY=(`global -c $cur`)
> }
$ complete -F funcs global
$ global kmem_<TAB><TAB>
kmem_alloc kmem_alloc_wait kmem_init
kmem_alloc_nofault kmem_free kmem_malloc
kmem_alloc_pageable kmem_free_wakeup kmem_suballoc
$ global kmem_s<TAB>
$ global kmem_suballoc
../vm/vm_kern.c
|
GNU Global在Emacs中的使用
- 安装配置Emacs
$HOME/.emacs +------------------------------------------------------ |(setq load-path (cons "/home/owner/global" load-path)) |(autoload 'gtags-mode "gtags" "" t) (global-set-key (kbd "M-<f1>") 'gtags-find-file) (global-set-key (kbd "M-<f2>") 'gtags-find-tag) (global-set-key (kbd "M-<f3>") 'gtags-find-rtag) (global-set-key (kbd "M-<f4>") 'gtags-find-symbol) (global-set-key (kbd "M-<f5>") 'gtags-find-with-grep) |
- 安装好之后在emacs中可以通过M-x使用如下命令
在浏览器中显示当前屏幕 跳转到输入的文件处 通过grep命令搜索 在tag文件中搜索引用 在tag文件中搜索符号 在tag文件中搜索定义 从当前表达式获得tag名并跳转 以当前位置作为tag跳转 在另一个窗口中打开tag跳转 搜索文件并查询 tag名字补全 开启gtags mode 显示当前文件的tag 从栈中移动到上一个点 从tag列表中选择一个tag 选择一个tag 通过某个事件选择tag 在其他window中选择tag 访问tag文件根目录 |
gtags-display-browser
gtags-find-file
gtags-find-pattern
gtags-find-rtag
gtags-find-symbol
gtags-find-tag
gtags-find-tag-by-event
gtags-find-tag-from-here
gtags-find-tag-other-window
gtags-find-with-grep
gtags-find-with-idutils
gtags-make-complete-list
gtags-mode
gtags-parse-file
gtags-pop-stack
gtags-select-mode
gtags-select-tag
gtags-select-tag-by-event
gtags-select-tag-other-window
gtags-visit-rootdir
|
-------------------------------
问道,修仙
-------------------------------