工欲善其事,必先利其器
在阅读大量linux c代码的开始。我们先要吧几个更有利于阅读的工具装好。
我用的是vim所以介绍vim + catgs + cscope
1什么是ctags
Ctags is a program that generates an index (or tag) file of names found in source and header files of various programming languages. Depending on the language, functions, variables, class members, macros and so on may be indexed. These tags allow definitions to be quickly and easily located by a text editor or other utility. Alternatively, there is also an output mode that generates a cross reference file, listing information about various names found in a set of language files in human-readable form.
2安装
apt-get rpm 源码安装
怎样装都行,只要你能装上
3用法:
1)进入源码所在目录:
# cd /usr/src/linux
(2)生成针对源码的tags,因为ctags确省不把 作为tag所以要加--c-types=+px(见注1)
# ctags -R --c-types=+px
[/home/brimmer/src]$ ctags -R --c-types=+px
"-R"表示递归创建,也就包括源代码根目录下的所有子目录下的源程序。"tags"文件中包括这些对象的列表:
l 用#define定义的宏
l 枚举型变量的值
l 函数的定义、原型和声明
l 名字空间(namespace)
l 类型定义(typedefs)
l 变量(包括定义和声明)
l 类(class)、结构(struct)、枚举类型(enum)和联合(union)
l 类、结构和联合中成员变量或函数
VIM用这个"tags"文件来定位上面这些做了标记的对象,下面介绍一下定位这些对象的方法:
1) 用命令行。在运行vim的时候加上"-t"参数,例如:
[/home/brimmer/src]$ vim -t foo_bar
这个命令将打开定义"foo_bar"(变量或函数或其它)的文件,并把光标定位到这一行。
2) 在vim编辑器内用":ta"命令,例如:
:ta foo_bar
3) 最方便的方法是把光标移到变量名或函数名上,然后按下"Ctrl-]"。用"Ctrl-o"退回原来的地方。
注意:运行vim的时候,必须在"tags"文件所在的目录下运行。否则,运行vim的时候还要用":set tags="命令设定"tags"文件的路径,这样vim才能找到"tags"文件。
*29.1* 使用标签
什么是标签?标签就是一个标识符被定义的地方。一个例子就是 C 或者 C++ 程序中的函
数定义。标签列表可以保存在一个标签文件中。Vim 可以通过它来从任何地方跳转到该标签,
也就是一个标识符被定义的地方。
在当前目录下为所有的 C 文件生成标签文件,使用下面的这个命令:
ctags *.c
"ctags" 是一个独立的程序。大多数 Unix 系统上都已经安装了它。如果你还没有安装,
可以在这里找到 "Exuberant ctags":
http://ctags.sf.net
现在你可以使用下面的命令跳转到一个函数定义的地方:
:tag startlist
这个命令会找到函数 "startlist",即使该函数是在另一个文件中。
CTRL-] 命令会跳转到当前光标下单词的标签。这样浏览毫无头绪的 C 代码会变得更容
些易。举个例子,假设你在函数 "write_block" 中。你可以看到它调用了函数
"write_line"。但 "write_line" 做了什么呢?将光标置于调用 "write_line" 的地方然
后按 CTRL-],你就跳转到了这个函数的定义的地方了。
"write_line" 函数调用了 "write_char"。你需要知道它做了什么。将光标定位到调
用 "write_char" 的地方然后按 CTRL-],你就到了定义"write_char" 的地方。
:tags" 命令显示你经过的标签列表:
:tags
# TO tag FROM line in file/text
1 1 write_line 8 write_block.c
2 1 write_char 7 write_line.c
>
现在介绍向回跳转。 CTRL-T 命令跳转到上一个标签。在上例中,你会回到 "write_line"
函数调用 "write_char" 的地方。
这个命令接受一个计数参数,用来表示跳转回去的标签个数。你已经向前跳转,现在
又跳转了回去。现在我们再一次向前跳转。下面的命令跳转到标签列表中最上面的标签:
:tag
你可以在前面加上要向前跳转的标签个数。比如:":3tag"。 CTRL-T 同样可以加上一个
计数参数。
通过这些命令,你可以用 CTRL-] 延着调用树向前跳转, 用 CTRL-T 向回跳转,用
":tags" 命令显示当前位置。
分 割 窗 口
":tag" 命令会将当前窗口的文件替换为包含新函数的文件。怎样才能同时查看两个文件
呢?你可以使用 ":split" 命令将窗口分开然后再用 ":tag" 命令。Vim 有个缩写命令可
以做到这些:
:stag tagname
使用下面的命令可以分割当前窗口并跳转到光标下的标签:
CTRL-W ]
如果指定了计数参数,新窗口将包含指定的那么多行。
多 个 标 记 文 件
如果在多个目录中都有文件,你可以在每一个目录下创建一个标签文件。Vim 只能跳转到
那个目录下的标签。
通过设定 'tags' 选项,你可以使用多个相关的标签文件。 比如:
:set tags=./tags,./../tags,./*/tags
这会使 Vim 找到当前文件所在目录及其父目录和所有子目录下的标签文件。
这已经是不少的标签文件了,但也许仍不够。比如,当编辑 "~/proj/src" 目录下的
一个文件时,你无法找到 "~/proj/sub/tags" 目录下的标签文件。对这种情况,Vim
提供了一个查找整个目录树下标签文件的方法,比如:
:set tags=~/proj/**/tags
多 个 匹 配
当一个函数(或类中的方法)被定义多次, ":tags" 命令会跳转到第一处。如果在当前
文件中存在匹配,那它将会被首先使用。
你现在可以跳转到同一个标签的其它匹配处:
:tnext
重复执行这个命令可以找到更多的匹配。如果存在很多匹配,你可以选择要跳转到哪一
个:
:tselect tagname
Vim 会为你展示一个选择列表:
# pri kind tag file
1 F f mch_init os_amiga.c
mch_init()
2 F f mch_init os_mac.c
mch_init()
3 F f mch_init os_msdos.c
mch_init(void)
4 F f mch_init os_riscos.c
mch_init()
Enter nr of choice (<CR> to abort):
你现在可以输入要跳转到的匹配代号(在第一列)。其它列的信息可以让你知道匹配在何
处被定义。
现在打开 Vim 并在一个垂直分割窗口中编辑这个文件:
vim
:vsplit functions
*29.2* 预览窗口
当编辑含有函数调用的代码时,你需要使用正确的调用参数。要获知所要传递的值,你可以
查看这个函数是如何定义的。标签机制对此十分适用。如果定义可在另一个窗口内显示那
就更好了。对此我们可以利用预览窗口。
打开一个预览窗口来显示函数 "write_char":
:ptag write_char
Vim 会打开一个窗口,跳转到 "write_char" 标签。然后它会回到原来的位置。这样你可
以继续输入而不必使用 CTRL-W 命令。
如果函数名出现在文本中,你可以用下面的命令在预览窗口中得到其定义:
CTRL-W }
有一个脚本可以自动显示光标处的标签定义。请参考 |CursorHold-example| 。
用下面的命令关闭预览窗口:
:pclose
要在预览窗口中编辑一个指定的文件,用 ":pedit" 。这在编辑头文件时很有用,比如:
:pedit defs.h
最后, "psearch" 可用来查找当前文件和任何包含文件中的单词并在预览窗口中显示匹
配。这在使用没有标签文件的库函数时十分有用。例如:
:psearch popen
这会在预览窗口中显示含有 popen() 原型的 "stdio.h" 文件:
FILE *popen __P((const char *, const char *));
你可以用 'previewheight' 选项指定预览窗口打开时的高度。
*************************************************************************************************************
这下更厉害了, 用Cscope自己的话说 - "你可以把它当做是超过频的ctags", 其功能和强大程度可见一斑吧, 关于它的介绍我就不详细说了, 如果你安装好了前 文介绍的中文帮助手册, 用下面的命令看看介绍吧: :help if_cscop.txt 我在这里简单摘抄一点, 供还在犹豫的朋友看看: Cscope 是一个交互式的屏幕下使用的工具,用来帮助你: * 无须在厚厚的程序清单中翻来翻去就可以认识一个 C 程序的工作原理。 * 无须熟悉整个程序就可以知道清楚程序 bug 所要修改的代码位置。 * 检查提议的改动 (如添加一个枚举值) 可能会产生的效果。 * 验证所有的源文件都已经作了需要的修改;例如给某一个现存的函数添 加一个参数。 * 在所有相关的源文件中对一个全局变量改名。 * 在所有相关的位置将一个常数改为一个预处理符号。 它被设计用来回答以下的问题: * 什么地方用到了这个符号? * 这是在什么地方定义的? * 这个变量在哪里被赋值? * 这个全局符号的定义在哪里? * 这个函数在源文件中的哪个地方? * 哪些函数调用了这个函数? * 这个函数调用了哪些函数? * 信息 "out of space" 从哪来? * 这个源文件在整个目录结构中处于什么位置? * 哪些文件包含这个头文件?使用cscope请添加如下内容,这样Ctrl-]的跳转将由cscope的tags进行分析
- 修改一下$HOME/.vimrc文件
if has("cscope") set csprg=/usr/bin/cscope set csto=0 set cst set nocsverb " add any database in current directory if filereadable("cscope.out") cs add cscope.out " else add database pointed to by environment elseif $CSCOPE_DB != "" cs add $CSCOPE_DB endif set csverb set cscopetag set cscopequickfix=s-,g-,c-,d-,t-,e-,f-,i- endif
,cscope使用
- 建立cscope使用的索引文件
- 在你需要浏览源码的根目录下(如你想用cscope看linux源码)使用下面命令:
- #: cscope -Rbkq<回车>
- R 表示把所有子目录里的文件也建立索引
- b 表示cscope不启动自带的用户界面,而仅仅建立符号数据库
- q生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
- k在生成索引文件时,不搜索/usr/include目录
- 在源码根目录下打开任意.c文件,使用如下命令:
- Ctrl+]将跳到光标所在变量或函数的定义处 Ctrl+T返回
- :cs find s ---- 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
:cs find g ---- 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
:cs find d ---- 查找本函数调用的函数
:cs find c ---- 查找调用本函数的函数
:cs find t: ---- 查找指定的字符串
:cs find e ---- 查找egrep模式,相当于egrep功能,但查找速度快多了
:cs find f ---- 查找并打开文件,类似vim的find功
一般源文件中生成索引文件
为了方便使用,编写了下面的脚本来更新cscope和ctags的索引文件:#!/bin/sh find . -name "*.h" -o -name "*.c" -o -name "*.cc" > cscope.files cscope -bkq -i cscope.files ctags -R
这个命令会生成三个文件:cscope.out, cscope.in.out, cscope.po.out。
其中cscope.out是基本的符号索引,后两个文件是使用"-q"选项生成的,可以加快cscope的索引速度。
这个脚本,首先使用find命令,查找当前目录及子目录中所有后缀名为".h", ".c"和".c"的文件,并把查找结果重定向到文件cscope.files中。然后cscope根据cscope.files中的所有文件,生成符号索引文件。最后一条命令使用ctags命令,生成一个tags文件,在vim中执行":help tags"命令查询它的用法。它可以和cscope一起使用。
下面我们来操练一下, 查找函数vim_strsave()的定义, 用命令: :cs find g vim_strsave (--- 图8 ---) 按下回车后会自动跳转到vim_strsave()的定义处. 此时你肯定会说Ctags也可 以做到这个呀, 那么下面说的这个Ctags就无法做到了, 我想查找vim_strsave()到 底在那些地方被调用过了, 用命令: :cs find c vim_strsave
s: 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
g: 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
d: 查找本函数调用的函数
c: 查找调用本函数的函数
t: 查找指定的字符串
e: 查找egrep模式,相当于egrep功能,但查找速度快多了
f: 查找并打开文件,类似vim的find功能
i: 查找包含本文件的文
cscope -Rbkq
这个命令会生成三个文件:cscope.out, cscope.in.out, cscope.po.out。
其中cscope.out是基本的符号索引,后两个文件是使用”-q”选项生成的,可以加快cscope的索引速度。
上面所用到的命令参数,含义如下:
-b: 只生成索引文件,不进入cscope的界面
-k: 在生成索引文件时,不搜索 / usr / include目录
-q: 生成cscope . in . out和cscope . po . out文件,加快cscope的索引速度
*******************************************************************************************************************
taglist是vim的一个很牛的插件
很好安装
依靠ctags生成的tags文件
在vim的窗口侧边显示函数,等信息
这样可以让阅读程序对程序的架构一目了然
安装:
(2)解压得到两个文件
# unzip -d taglist taglist_42.zip
# cd taglist
# tree
.
|-- doc
| `-- taglist.txt
`-- plugin
`-- taglist.vim
(3)安装
cp doc/taglist.txt /usr/share/vim/vim61/doc/
cp plugin/taglist.vim /usr/share/vim/vim61/plugin/
(4)配置和使用
cd /usr/share/vim/vim61/doc/
启动vim,用 “:helptags .”(注意,这里有空格)来配置好帮助文件
重启vim,用“:TlistToggle”来打开和关闭taglist窗口。
可以用“:help taglist”来获得更多帮助信
其实解压出来的doc文件夹中的taglist.txt中就有安装的教程
就是将/doc/taglist.txt和/plugin/taglist.vim考到.vim文件夹中
.vim文件夹在本用户home目录下,没有的话建一个
配置:
"设置taglist在vim启动的时候自动打开
let Tlist_Auto_Open=1
"当只有taglist的窗口是自动退出vim
let Tlist_Exit_OnlyWindow=1
let Tlist_Use_Right_Window = 1 "在右侧窗口中显示taglist窗口下面介绍常用的taglist配置选项,你可以根据自己的习惯进行配置:
- Tlist_Ctags_Cmd选项用于指定你的Exuberant ctags程序的位置,如果它没在你PATH变量所定义的路径中,需要使用此选项设置一下;
- 如果你不想同时显示多个文件中的tag,设置Tlist_Show_One_File为1。缺省为显示多个文件中的tag;
- 设置Tlist_Sort_Type为”name“可以使taglist以tag名字进行排序,缺省是按tag在文件中出现的顺序进行排序。按tag出现的范围(即所属的namespace或class)排序,已经加入taglist的TODO List,但尚未支持;
- 如果你在想taglist窗口是最后一个窗口时退出vim,设置Tlist_Exit_OnlyWindow为1;
- 如果你想taglist窗口出现在右侧,设置Tlist_Use_Right_Window为1。缺省显示在左侧。
- 在gvim中,如果你想显示taglist菜单,设置Tlist_Show_Menu为1。你可以使用Tlist_Max_Submenu_Items和Tlist_Max_Tag_Length来控制菜单条目数和所显示tag名字的长度;
- 缺省情况下,在双击一个tag时,才会跳到该tag定义的位置,如果你想单击tag就跳转,设置Tlist_Use_SingleClick为1;
- 如果你想在启动vim后,自动打开taglist窗口,设置Tlist_Auto_Open为1;
- 如果你希望在选择了tag后自动关闭taglist窗口,设置Tlist_Close_On_Select为1;
- 当同时显示多个文件中的tag时,设置Tlist_File_Fold_Auto_Close为1,可使taglist只显示当前文件tag,其它文件的tag都被折叠起来。
- 在使用:TlistToggle打开taglist窗口时,如果希望输入焦点在taglist窗口中,设置Tlist_GainFocus_On_ToggleOpen为1;
- 如果希望taglist始终解析文件中的tag,不管taglist窗口有没有打开,设置Tlist_Process_File_Always为1;
- Tlist_WinHeight和Tlist_WinWidth可以设置taglist窗口的高度和宽度。Tlist_Use_Horiz_Window为1设置taglist窗口横向显示;
在taglist窗口中,可以使用下面的快捷键:
<CR> 跳到光标下tag所定义的位置,用鼠标双击此tag功能也一样 o 在一个新打开的窗口中显示光标下tag <Space> 显示光标下tag的原型定义 u 更新taglist窗口中的tag s 更改排序方式,在按名字排序和按出现顺序排序间切换 x taglist窗口放大和缩小,方便查看较长的tag + 打开一个折叠,同zo - 将tag折叠起来,同zc * 打开所有的折叠,同zR = 将所有tag折叠起来,同zM [[ 跳到前一个文件 ]] 跳到后一个文件 q 关闭taglist窗口 <F1> 显示帮助可以用”:TlistOpen“打开taglist窗口,用”:TlistClose“关闭taglist窗口。或者使用”:TlistToggle“在打开和关闭间切换。在我的vimrc中定义了下面的映射,使用<F9>键就可以打开/关闭taglist窗口:
map <silent> <F9> :TlistToggle<cr>Taglist插件还提供了很多命令,你甚至可以用这些命令创建一个taglist的会话,然后在下次进入vim时加载此会话