GNU Global Source Code Tag System
时间:2010-04-24 来源:buxoman
GNU Global是一个源码阅读的好工具。能独立使用,而且与Emacs结合的很好。准备花点儿时间学习一下。而且要阅读和学习操作系统代码,没有一个像Souce Insight一样好用的代码阅读工具,难度真的不小。
下面就把学习时的一些要点记录下来。
1. 工程的概念。
Global把一个目录及其子目录当作一个工程。
2. 准备工作
最首要的工作是,在源代码的根目录下执行gtags程序。
手册举了一个FreeBSD的例子:
$cd/usr/src/usr.bin/vi
$gtags
结果:gtags将把这个vi目录及其所有子目录下的文件当作一个Project(工程),在这个根目录下生成四个数据库文件,分别是:GPATH, GRTAGS, GSYMS, GTAGS。呵呵,都是G开头的。
手册对这四个文件的作用有个说明,分别是:
GPATH 路径名称数据库;
GRTAGS 引用数据库;
GTAGS 定义数据库;
GSYMS 符号数据库,存放没有出现在GTAGS中的符号;
这些数据库可是要些存储空间的。手册用FreeBSD7内核做例子,给出了数据库存储空间:
source code (/usr/src/sys) 123 MB
GPATH 1 MB
GTAGS 26 MB
GRTAGS 22 MB
GSYMS 23 MB
-------------------------------------
total of tag files 72MB
(呵呵,我正打算看看FB8的sys目录呢,这个例子正好给我提供现实参考)
好,到了这里,先实地操作一把,尝尝鲜!
3. 在Windows XP上安装global
我在Windows XP上看代码。所以先从http://www.gnu.org/software/global/下给出的一个链接,下载到了Windows版本的global和htags。把htags替换global原本自己的,据说是修正了一个BUG。我也不知道,反正替换了就得了。
到Freebsd的sys目录下试一把:
D:\FreeBSD\release8\sys>gtags
(要等几分钟)
D:\FreeBSD\release8\sys>dir
2010-04-24 22:04 1,425,408 GPATH
2010-04-24 22:05 32,710,656 GRTAGS
2010-04-24 22:05 27,394,048 GSYMS
2010-04-24 22:04 29,122,560 GTAGS
呵呵,不错。做饭的米准备好了。接着就等烧火的EMACS咯。
先看看我的global安装目录的内容吧:
C:\Application>tree /F glo581wb
结果显示:
C:\APPLICATION\GLO581WB
├─bin
│ global.exe
│ gozilla.exe
│ gtags-cscope.exe
│ gtags-parser.exe
│ gtags.exe
│ htags-old.exe
│ htags.exe
│
├─manifest
│ glo581wb.mft
│ glo581wb.ver
│
└─share
├─gtags
│ │ AUTHORS
│ │ bless.sh.tmpl
│ │ BOKIN_MODEL
│ │ BOKIN_MODEL_FAQ
│ │ ChangeLog
│ │ COPYING
│ │ DONORS
│ │ FAQ
│ │ ghtml.cgi.tmpl
│ │ global.cgi.tmpl
│ │ globash.rc
│ │ gtags-cscope.vim
│ │ gtags.conf
│ │ gtags.el
│ │ gtags.pl
│ │ gtags.vim
│ │ INSTALL
│ │ LICENSE
│ │ NEWS
│ │ README
│ │ README.win32
│ │ style.css
│ │ THANKS
│ │
│ └─icons
│ back.png
│ bottom.png
│ c.png
│ dir.png
│ first.png
│ help.png
│ index.png
│ last.png
│ left.png
│ n_bottom.png
│ n_first.png
│ n_last.png
│ n_left.png
│ n_right.png
│ n_top.png
│ pglobe.png
│ right.png
│ text.png
│ top.png
│
├─info
│ global.info
│
└─man
└─cat1
global.1
gozilla.1
gtags-cscope.1
gtags-parser.1
gtags.1
htags.1
4. 在Emacs中配置global
先把global安装目录下的gtags.el拷贝到emacs安装目录下的lisp目录。
在Emacs中有两种办法启动gtags。
(1) 手动 M-x gtags-mode RET
(2) 启动C模式时自动启动
(require 'gtags)
(setq c-mode-hook
'(lambda ()
(gtags-mode 1)))
这种启动的gtags模式,是minor模式,不是major模式,不过正好与C模式配套使用。
先试一试看看是否可用了。打开一个C文件,在一个结构体类型名上执行M-x gtags-find-tag RET <name> RET。在提示输如名称时,能自动选择光标所在的名称。最后回车后直接跳到了结构的定义处。真不错!
【注:M-. 这个按键绑定到函数gtags-find-tag】
好了,现在应该开始利用Emacs+global傲游于代码的汪洋大海中了!
5. 查找数据类型的定义
我试着在uint8_t这个类型上执行查找,结果Emacs专门用一个窗口显示出了多处定义:
uint8_t 52 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 65 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 77 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 52 boot/efi/include/ia64/efibind.h typedef unsigned __int8 uint8_t;
uint8_t 65 boot/efi/include/ia64/efibind.h typedef unsigned char uint8_t;
uint8_t 77 boot/efi/include/ia64/efibind.h typedef unsigned char uint8_t;
uint8_t 42 dev/mxge/mxge_mcp.h typedef unsigned char uint8_t;
uint8_t 36 geom/virstor/binstream.h #define uint8_t unsigned char
uint8_t 50 netinet/in.h typedef __uint8_t uint8_t;
uint8_t 58 sys/stdint.h typedef __uint8_t uint8_t;
uint8_t 84 sys/types.h typedef __uint8_t uint8_t;
把光标移动到你想去的定义处,按回车就跳转到了那个文件中这个类型的定义。
【这个专门窗口的模式叫做GTAGS SELECT MODE(gtags 选择模式)】
或许你还想看看上面多处定义中的其它处定义,怎么回到这个列表去呢?执行M-x gtags-pop-stack就可以了。
【按键M-*绑定到函数gtags-pop-stack】
看完了某结构的定义,大部分情况下是立即返回到原来的代码处继续阅读。怎么做呢?其实很简单,跟上面一样,仍然gtags-pop-stack就可以了。(似乎gtags在每一次跳转前都把当前位置坐了bookmark放到一个栈结构中了)。可以连续执行这个动作,直到你第一次进行查找的地方。跟source insight的功能一样。
在显示符号定义位置的时候,文件名和路径都显示出来了,这个路径是相对于源代码根目录的路径。是可以修改的,相关变量是gtags-path-style, 可以取三种值root(默认值,相对于源码根目录), relative(相对于当前目录), absolute(绝对路径)。
【对变量的修改,可以用M-x customize-variable命令; 比较unix风格一点的,是在.emacs文件里配置:
(setqgtags-mode-hook
’(lambda()
(setqgtags-path-style’relative)))
】
6. 查找一个函数被引用的地方
有时候要看一个函数被哪些函数调用了,在Emacs中执行M-x gtags-find-rtags。
比如查看函数nd6_llinfo_settimer的引用,得到很多结果,在gtags选择模式窗口中显示:
nd6_llinfo_settimer 495 netinet6/nd6.c nd6_llinfo_settimer(ln, INT_MAX);
nd6_llinfo_settimer 498 netinet6/nd6.c nd6_llinfo_settimer(ln, ln->ln_ntick);
nd6_llinfo_settimer 518 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 544 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 561 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 565 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 571 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 1022 netinet6/nd6.c nd6_llinfo_settimer(ln, -1);
nd6_llinfo_settimer 1044 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 1047 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 1147 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 1861 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 401 netinet6/nd6.h void nd6_llinfo_settimer __P((struct llentry *, long));
7. 若用gtags-find-tag没有找到某个符号的定义,那么就试一试gtags-find-symbol
8. 查找字符串,可以试一试 gtags-find-with-grep.
9. 还支持正则表达式呢: Find Symbol: ^put_ <== 查找以put_开头的符号
10. 也支持自动补全,就是在提示你输出待查找的符号名称时可以使用。【要是能在编辑的时候使用那该多爽啊!完全可以抛弃source insight了!】
下面就把学习时的一些要点记录下来。
1. 工程的概念。
Global把一个目录及其子目录当作一个工程。
2. 准备工作
最首要的工作是,在源代码的根目录下执行gtags程序。
手册举了一个FreeBSD的例子:
$cd/usr/src/usr.bin/vi
$gtags
结果:gtags将把这个vi目录及其所有子目录下的文件当作一个Project(工程),在这个根目录下生成四个数据库文件,分别是:GPATH, GRTAGS, GSYMS, GTAGS。呵呵,都是G开头的。
手册对这四个文件的作用有个说明,分别是:
GPATH 路径名称数据库;
GRTAGS 引用数据库;
GTAGS 定义数据库;
GSYMS 符号数据库,存放没有出现在GTAGS中的符号;
这些数据库可是要些存储空间的。手册用FreeBSD7内核做例子,给出了数据库存储空间:
source code (/usr/src/sys) 123 MB
GPATH 1 MB
GTAGS 26 MB
GRTAGS 22 MB
GSYMS 23 MB
-------------------------------------
total of tag files 72MB
(呵呵,我正打算看看FB8的sys目录呢,这个例子正好给我提供现实参考)
好,到了这里,先实地操作一把,尝尝鲜!
3. 在Windows XP上安装global
我在Windows XP上看代码。所以先从http://www.gnu.org/software/global/下给出的一个链接,下载到了Windows版本的global和htags。把htags替换global原本自己的,据说是修正了一个BUG。我也不知道,反正替换了就得了。
到Freebsd的sys目录下试一把:
D:\FreeBSD\release8\sys>gtags
(要等几分钟)
D:\FreeBSD\release8\sys>dir
2010-04-24 22:04 1,425,408 GPATH
2010-04-24 22:05 32,710,656 GRTAGS
2010-04-24 22:05 27,394,048 GSYMS
2010-04-24 22:04 29,122,560 GTAGS
呵呵,不错。做饭的米准备好了。接着就等烧火的EMACS咯。
先看看我的global安装目录的内容吧:
C:\Application>tree /F glo581wb
结果显示:
C:\APPLICATION\GLO581WB
├─bin
│ global.exe
│ gozilla.exe
│ gtags-cscope.exe
│ gtags-parser.exe
│ gtags.exe
│ htags-old.exe
│ htags.exe
│
├─manifest
│ glo581wb.mft
│ glo581wb.ver
│
└─share
├─gtags
│ │ AUTHORS
│ │ bless.sh.tmpl
│ │ BOKIN_MODEL
│ │ BOKIN_MODEL_FAQ
│ │ ChangeLog
│ │ COPYING
│ │ DONORS
│ │ FAQ
│ │ ghtml.cgi.tmpl
│ │ global.cgi.tmpl
│ │ globash.rc
│ │ gtags-cscope.vim
│ │ gtags.conf
│ │ gtags.el
│ │ gtags.pl
│ │ gtags.vim
│ │ INSTALL
│ │ LICENSE
│ │ NEWS
│ │ README
│ │ README.win32
│ │ style.css
│ │ THANKS
│ │
│ └─icons
│ back.png
│ bottom.png
│ c.png
│ dir.png
│ first.png
│ help.png
│ index.png
│ last.png
│ left.png
│ n_bottom.png
│ n_first.png
│ n_last.png
│ n_left.png
│ n_right.png
│ n_top.png
│ pglobe.png
│ right.png
│ text.png
│ top.png
│
├─info
│ global.info
│
└─man
└─cat1
global.1
gozilla.1
gtags-cscope.1
gtags-parser.1
gtags.1
htags.1
4. 在Emacs中配置global
先把global安装目录下的gtags.el拷贝到emacs安装目录下的lisp目录。
在Emacs中有两种办法启动gtags。
(1) 手动 M-x gtags-mode RET
(2) 启动C模式时自动启动
(require 'gtags)
(setq c-mode-hook
'(lambda ()
(gtags-mode 1)))
这种启动的gtags模式,是minor模式,不是major模式,不过正好与C模式配套使用。
先试一试看看是否可用了。打开一个C文件,在一个结构体类型名上执行M-x gtags-find-tag RET <name> RET。在提示输如名称时,能自动选择光标所在的名称。最后回车后直接跳到了结构的定义处。真不错!
【注:M-. 这个按键绑定到函数gtags-find-tag】
好了,现在应该开始利用Emacs+global傲游于代码的汪洋大海中了!
5. 查找数据类型的定义
我试着在uint8_t这个类型上执行查找,结果Emacs专门用一个窗口显示出了多处定义:
uint8_t 52 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 65 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 77 boot/efi/include/i386/efibind.h typedef unsigned char uint8_t;
uint8_t 52 boot/efi/include/ia64/efibind.h typedef unsigned __int8 uint8_t;
uint8_t 65 boot/efi/include/ia64/efibind.h typedef unsigned char uint8_t;
uint8_t 77 boot/efi/include/ia64/efibind.h typedef unsigned char uint8_t;
uint8_t 42 dev/mxge/mxge_mcp.h typedef unsigned char uint8_t;
uint8_t 36 geom/virstor/binstream.h #define uint8_t unsigned char
uint8_t 50 netinet/in.h typedef __uint8_t uint8_t;
uint8_t 58 sys/stdint.h typedef __uint8_t uint8_t;
uint8_t 84 sys/types.h typedef __uint8_t uint8_t;
把光标移动到你想去的定义处,按回车就跳转到了那个文件中这个类型的定义。
【这个专门窗口的模式叫做GTAGS SELECT MODE(gtags 选择模式)】
或许你还想看看上面多处定义中的其它处定义,怎么回到这个列表去呢?执行M-x gtags-pop-stack就可以了。
【按键M-*绑定到函数gtags-pop-stack】
看完了某结构的定义,大部分情况下是立即返回到原来的代码处继续阅读。怎么做呢?其实很简单,跟上面一样,仍然gtags-pop-stack就可以了。(似乎gtags在每一次跳转前都把当前位置坐了bookmark放到一个栈结构中了)。可以连续执行这个动作,直到你第一次进行查找的地方。跟source insight的功能一样。
在显示符号定义位置的时候,文件名和路径都显示出来了,这个路径是相对于源代码根目录的路径。是可以修改的,相关变量是gtags-path-style, 可以取三种值root(默认值,相对于源码根目录), relative(相对于当前目录), absolute(绝对路径)。
【对变量的修改,可以用M-x customize-variable命令; 比较unix风格一点的,是在.emacs文件里配置:
(setqgtags-mode-hook
’(lambda()
(setqgtags-path-style’relative)))
】
6. 查找一个函数被引用的地方
有时候要看一个函数被哪些函数调用了,在Emacs中执行M-x gtags-find-rtags。
比如查看函数nd6_llinfo_settimer的引用,得到很多结果,在gtags选择模式窗口中显示:
nd6_llinfo_settimer 495 netinet6/nd6.c nd6_llinfo_settimer(ln, INT_MAX);
nd6_llinfo_settimer 498 netinet6/nd6.c nd6_llinfo_settimer(ln, ln->ln_ntick);
nd6_llinfo_settimer 518 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 544 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 561 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 565 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 571 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)ndi->retrans * hz / 1000);
nd6_llinfo_settimer 1022 netinet6/nd6.c nd6_llinfo_settimer(ln, -1);
nd6_llinfo_settimer 1044 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 1047 netinet6/nd6.c nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
nd6_llinfo_settimer 1147 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 1861 netinet6/nd6.c nd6_llinfo_settimer(ln,
nd6_llinfo_settimer 401 netinet6/nd6.h void nd6_llinfo_settimer __P((struct llentry *, long));
7. 若用gtags-find-tag没有找到某个符号的定义,那么就试一试gtags-find-symbol
8. 查找字符串,可以试一试 gtags-find-with-grep.
9. 还支持正则表达式呢: Find Symbol: ^put_ <== 查找以put_开头的符号
10. 也支持自动补全,就是在提示你输出待查找的符号名称时可以使用。【要是能在编辑的时候使用那该多爽啊!完全可以抛弃source insight了!】
相关阅读 更多 +