1.引言

如何阅读代码还要单独写一篇文章?难道不是随便用一个IDE就可以了吗?回到上一篇文章里介绍的那个问题,需要修改uboot里board_mmc_init函数里的writel(0x66666666,REG_MFP_GPD_L) ,对于初学者如何在uboot代码里找到这句话呢?当时问我这个问题的网友就有这个困惑。

因为Uboot和Kernel里有非常多数量的文件,另外为了支持多种芯片,在整个目录里存在大量的同名文件、同名函数。所以如果用一般的IDE把整个工程目录加载进去,然后阅读代码,会相当的不方便,你很难理清楚各个函数之间的调用关系。我曾经尝试过在Windows下用SourceInsight去看内核源码,实在看不下去,而且由于文件太多经常卡住。在网上也看到有人通过一些脚本去精简文件数量再配合SourceInsight的,我也尝试过,感觉也不是很好用。见到过几个高手是直接通过VIM阅读,效率很高,我经过几天的摸索,稍微入了一点门,在这里给初学者做个分享,希望对大家有所帮助。

2.工具安装与使用

因为我一开始学的单片机,用Keil软件比较多,咱们就在Ubuntu里构建一个类似于Keil软件常见功能的环境。为了让大家看起来更直观,我找了一个单片机的工程同时放到Ubuntu里和Window下,两边同时对比分析。

我们需要在Ubuntu系统里安装配置以下几个工具。

2.1 ctags

2.1.1 ctags安装配置

以下一段话摘自于维基百科:

Ctags is a programming tool 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, a code search engine, or other utility.

安装方式如下:

sudo apt-get install ctags

验证是否安装成功的方式可以输入

ctags --version

使用

ctags --list-languages

可以查看ctags支持的编程语言

使用

ctags --list-maps

可以查看ctags支持的编程语言对应的文件扩展名

使用

ctags --list-kinds

可以查看ctags识别的语法元素,使用

ctags --list-kinds=c

可单查看C语言识别的语法元素

安装完成之后,想要使用ctags,必须在你想要查看的代码目录中有tags文件。

2.1.2 ctags使用

在执行下述操作前,已经在Ubuntu里~/mcuproject目录下放了一个MCU的工程。

第1步: ctags -R *

生成tags文件。

第2步:需要找到main函数定义在哪里,

先输入vim打开vim窗口,然后在vim命令行窗口输入ts main

它的作用是:Search for a particular tag

再根据提示输入1 回车就跳转到main函数所在的位置了,

有一点需要大家注意的是:一定要在tags所在的目录打开vim,输入ts才能搜到你要找到的tag,在其它目录是不行的,比如我进入到上一级目录,就会提示如下信息了。

对比下Windows里Keil环境下,我通常用如下方式去查找:

搜索结果如下:

看到这里你是不是有个疑问,为什么Ubuntu下搜索main只有一个地方,但是在Keil下搜索出来了6处。

原因是使用ctags搜索的结果是main的定义,而Keil里是只要main这个字符串出现的地方都会被搜索出来。

除了刚才使用的ts命令,还有其他相关命令:

:ts or :tselect  List all of the definitions of the last tag

:tn or :tnext   Go to the next definition for the last tag

:tp or :tprev   Go to the previous definition for the last tag

:tf or :tfirst   Go to the first definition for the last tag

:tl or :tlast    Go to the last definition for the last tag

第3步:ctags两个常用的快捷键

Ctrl-]   Jump to the tag underneath the cursor

Ctrl-t   Jump back up in the tag stack

通过ctrl+] ,取出当前光标下的word作为tag的名字并进行跳转。你需要查看main函数里的BOARD_InitPins()函数定义,直接在vim里,将光标移动到那里,然后ctrl+]就跳转过去了

实现的效果和Keil里点击Go to Definition 效果一致

看完了这个函数,想回到原来的地方怎么办呢,ctrl+t即可,对应Keil中下方红框向左的箭头功能。

但是只有ctags还不行,因为还有下面3个阅读代码过程中的问题没有解决

1)没有类似Keil中下方的工程文件列表,不方便随意选中某个文件浏览

2)没有类似Keil中下方的function功能,方便快速找到一个文件中的函数定义

3)如果浏览到下面这个文件的BOARD_InitPins函数,我想搜索谁调用它的,就没招了。

上述第一个问题,我们通过2.2节的Nerdtree工具实现,第二个问题通过2.3节

的Taglist工具实现,第三个问题通过2.4节的cscope工具实现。

2.2安装配置Nerdtree

2.2.1 Nerdtree安装

The NERD tree : A tree explorer plugin for navigating the filesystem

The NERD tree allows you to explore your filesystem and to open files and directories. It presents the filesystem to you in the form of a tree which you

manipulate with the keyboard and/or mouse. It also allows you to perform

simple filesystem operations.

安装方式是先在https://www.vim.org/scripts/script.php?script_id=1658网站下载压缩包,将解压缩的文件拷贝到~/.vim/中即可,下面是我~/.vim/中的文件:

如果没有.vim 目录的话,自己创建下即可。

2.2.2 Nerdtree使用

在使用前,现在~/.vimrc中添加以下两句话:

map <F2> :NERDTreeToggle<CR>

nnoremap <F3> :NERDTreeFind<CR>

具体什么用途,下文马上解释。

Nerdtree使用方式是在vim打开的文件中,切换到底线命令模式,输入NERDTree,回车就可以了。

显示效果如下,多出来左侧部分就是Nerdtree

如果需要关闭Nerdtree,需要切换到底线命令模式,输入NERDTreeClose,

这样操作显然很麻烦,这时上面map <F2> :NERDTreeToggle<CR> 这句话就起

作用了,我们只需要按F2键就可以来回切换打开与关闭该窗口了。

在Nerdtree打开的情况下,有两个窗口,默认打开后光标是在最左侧的窗口,怎么切换到右侧窗口浏览代码呢?通过Ctrl+w+w在两个窗口切换,我们先切换到右边的窗口,然后进入到CLOCK_EnableClock定义的文件里(还记得上一节的Ctrl-]快捷键吧),进入后显示如下

这时按一下F3快捷键,注意左侧窗口的变化,自动就定位到该函数所在的文件了,可以很清晰的看到所在文件的目录结构。这就是上面添加的第二句话的作用。

另外如果工程里文件很多,你想通过搜索快速找到某个文件,可以使用vim自带的find命令也能完成所需功能。find 会从 path 中搜索文件。所以在使用find之前一定要配置一下path变量(不是PATH环境变量)

具体方法是:在右侧窗口中,进入命令行窗口

:set path=./**

然后

find gpio_led_output.c或

find g[TAB]

即可搜索文件

2.3安装配置Taglist

2.3.1 Taglist安装

Taglist也是vim的一个插件,能将当前vim打开的文件中函数名、变量名等在一个窗口中列出来,并支持通过列出的函数名实现跳转。将Taglist下载下来的压缩包解压缩,将解压缩出来的doc里面的taglist.txt复制到~/.vim/doc/下面,plugin里面的taglist.vim文件拷贝到~/.vim/plugin目录下。这样Taglist这个插件安装完成了。

下载地址在:

https://www.vim.org/scripts/script.php?script_id=273

2.3.2 Taglist使用

在使用前,现在~/.vimrc中添加以下两句话:

map <F4> :TlistToggle <CR>

let Tlist_Use_Right_Window = 1

其中第1句话是建了一个F4的快捷键,用来方便打开和和关闭该插件

第2句话是将该插件窗口放到最后侧。

另外根据需要你还可以选择是否添加以下特性:

let Tlist_Show_One_File = 1       "不同时显示多个文件的tag,只显示当前文件的
let Tlist_Exit_OnlyWindow = 1       "如果taglist窗口是最后一个窗口,则退出vim

按下F4打开Taglis后,整体窗口显示如下:

三部分窗口比例不是很和谐,中间代码窗口太窄,怎么调整窗口大小呢?

在~/.vimrc中添加以下两句话:

map <F6>  :vertical resize +1<CR>

map <F5>  :vertical resize -1<CR>

:vertical resize 是用来调整当前窗口宽度的。

我们在最左侧窗口中先按F5几次,减小当前窗口宽度,

然后到最右侧窗口中也按F5几次,减小当前窗口宽度,

就变成这样了:

另外你也可以在中间窗口通过Ctrl + - 减小字体来显示的更多内容

Ctrl + + 为增大字体

2.4 cscope

2.4.1 cscope安装配置

先看下ctags和cscope的区别:

ctags can be used to take you to the definition of a variable (e.g., a function, variable, or macro). cscope can be used to take you to the call site of a definition (e.g., all function calls, all variable uses, all macro uses).

简而言之,它是 ctags 的加强版,ctags 只能让我们跳转到某个 tag 的定义之处,但是无法让我们知道这个 tag 还在哪里出现过,或者被哪个函数调用过,这时候就需要 cscope 来完成该功能了。

安装方式如下:

sudo apt-get install cscope

验证是否安装成功的方式可以输入

cscope --version

表示安装成功

2.4.2 cscope使用

第1步:使用 cscope 生成数据库文件

cscope -Rbkq

其中参数的含义:

-R 递归,对子目录也建立数据库

-b 只生成数据库,不进入 scope 界面

-k 生成数据库时,不搜索 /usr/include 目录

-q 生成 cscope.in.out 和 cscope.po.out 文件,加快查找速度

第2步:在vim命令行窗口输入:cs add ./cscope.out

第3步:

通用格式为 :cs find -option label

option 可以有很多种模式,在 Vim 中使用 :help cscope-find 来查看 option:

0 or s: Find this C symbol

1 or g: Find this definition

2 or d: Find functions called by this function

3 or c: Find functions calling this function

4 or t: Find this text string

6 or e: Find this egrep pattern

7 or f: Find this file

8 or i: Find files #including this file

比如:

cs find g BOARD_InitPins   会直接跳转到这个函数的定义处

cs find c BOARD_InitPins   会直接跳转到调用这个函数的地方

cs find t BOARD_InitPins   会列出以下5个出现该函数的地方

通过选择不同的数字,可以查看具体不同出现的位置。

这个搜索结果和Keil里搜索的结果一样:

但是这样使用有一个问题:就是我查看一个结果后,如果我还想继续查看其它的结果,还得重新搜索再选择一次。

该问题的解决方法是:

用cscopequickfix,在.vimrc中添加:

set cscopequickfix=c-,d-,e-,g-,i-,s-,t-

在命令行copen打开quickfix窗口,用cclose关闭,cprev、cnext移动

再次cs find t BOARD_InitPins 就会再右下角的窗口里显示,这样查看完一个文件后如果继续查看另外的文件,就可以通过最右下角的窗口切换选择。

这种方式打开的窗口是在右下角,看着不是很舒服,怎么弄成Keil那样放到最下方呢,在中间命令行窗口处输入以下内容,就可以在下方显示了

:botright copen

3.Uboot实战应用

先回到我们之前遇到的那个问题,我是如何在Uboot工程里找到需要修改的那个代码地方的,我们先把上一章改动后的0x0666666改回原来的0x66666666。

第1步:进入到Uboot所在目录

make cscope

第2步:

make ctags

注意上面两步骤没用第二章介绍的方法生成tags和cscope.out文件,原因是因为如果那样操作的话,就把uboot整个文件夹里的所有文件都加进去了,而使用make的方式只生成了实际用到的。

第3步:

vim

:cs add ./cscope.out

第4步:

F2 、F4 把Nerdtree和Taglist窗口打开,通过F5减小下两侧窗口宽度,Ctrl+-缩小字体

:botright copen  打开quickfix窗口

第5步:

:cs find t 0x66666666

我们找到16处,通过简单分析就可以定位到第一个结果就是我们需要的。

你如果是在整个目录去查询,就远远不止这16处了。

通过最右侧的Taglist窗口可以看到它是在board_mmc_init这个函数调用的。

紧接着我们看下是谁调用的这个函数board_mmc_init:

:cs find c board_mmc_init

我们把光标移动到board_mmc_init 处 Ctrl-t 一下,你会发现进入到不是刚才那个函数定义的地方了,变成了下面这里,这是咋回事??

我们再输入:ts board_mmc_init  查看下该函数的定义,发现竟然有三处

不过前两个是weak弱定义,所以直接Ctrl-t 跳转的就是上述的第一个结果

输入:tn 就会跳转到下一个定义,直到找到正确的定义

另外输入ts 就可以看到最后一次tag结果。

使用上面的方法就可以一步步的继续分析Uboot代码,这里不是本篇的重点,不详细介绍了。

4.结束语

本期相关的资料在https://github.com/TopSemic/NUC972_Linux  Lesson19中。

本篇为大家介绍了Linux下使用vim配合4个插件实现Linux代码的高效阅读,因为我也是刚学习,所以肯定有很多更好的使用方法还没有掌握,欢迎大家多交流,共同进步,可以在网页下方留言讨论,或者发邮件:Topsemic@sina.com ,

微信公众号如下,欢迎关注:

5.参考内容

https://blog.csdn.net/Lius_1006/article/details/79524512

https://blog.csdn.net/cnh294141800/article/details/78208409

https://www.vim.org/scripts/script.php?script_id=1658

https://guqian110.github.io/pages/2015/01/25/learning_vim_ctags_cscope_taglist.html

https://blog.csdn.net/dengxiayehu/article/details/6330200

https://yang3wei.github.io/blog/2013/01/29/nerdtree-kuai-jie-jian-ji-lu/

https://zhuanlan.zhihu.com/p/85040099

https://blog.csdn.net/jiayu/article/details/2418147

https://blog.csdn.net/menggucaoyuan/article/details/12950711

https://www.cnblogs.com/luosongchao/p/3254451.html

https://blog.csdn.net/dengxiayehu/article/details/6330200

https://courses.cs.washington.edu/courses/cse451/10au/tutorials/tutorial_ctags.html

https://www.thinbug.com/q/6726783

https://ricostacruz.com/til/navigate-code-with-ctags

https://andrew.stwrt.ca/posts/vim-ctags/

https://courses.cs.washington.edu/courses/cse451/10au/tutorials/tutorial_ctags.html

https://ricostacruz.com/til/navigate-code-with-ctags

https://medium.com/usevim/nerd-tree-guide-bb22c803dcd2

https://catonmat.net/vim-plugins-nerdtree-vim

https://vim.fandom.com/wiki/Resize_splits_more_quickly

https://vi.stackexchange.com/questions/773/how-do-i-change-the-default-size-of-plugin-window-nerdtree-taglist-etc

https://blog.csdn.net/qq_16777851/article/details/81782669

Linux学习系列十九:如何高效的阅读Linux源码相关推荐

  1. 从9个组件开始,教你如何高效的阅读nginx源码?

    从9个组件开始,教你如何高效的阅读nginx源码?|内存池.线程池.内存共享组件实现. http处理流程.phase原理.红黑树.配置文件.惊群.原子操作 专注于服务器后台开发,包括C/C++,Lin ...

  2. 如何更高效地阅读JDK源码

    简介 阅读源码的几个问题: 为什么要看JDK源码 JDK源码的阅读顺序 JDK源码的阅读方法 为什么要看JDK源码 一,JDK源码是其它所有源码的基础,看懂了JDK源码再看其它的源码会达到事半功倍的效 ...

  3. linux can软件,Linux学习系列十:使用CAN

    1.引言 CAN总线由于其高可靠性,被广泛的应用在汽车电子及工业领域.生活中常见的一个使用CAN的地方是汽车OBD接口,它一般位于汽车方向盘的左下角,是一个16针的插座,其中里面就有一个CAN接口,可 ...

  4. 【Python学习系列十九】基于scikit-learn库进行特征选择

    场景:特征选择在模型训练前是非常有意义的,实际上就是先期对特征相关性进行分析. 参考:http://blog.csdn.net/fjssharpsword/article/details/735503 ...

  5. Java学习系列(十九)Java面向对象之数据库编程

    JDBC(Java Data Base Connectivity:java数据库连接):它定义了一组标准的操作数据库的接口,既然是接口,那它就是一种规范,是Java操作数据库的技术规范. Java数据 ...

  6. linux学习第十周总结

    linux学习第十周总结 接着上周的mysql,重点终结日志管理 ,备份还原,主从复制和mysql集群 一.mysql日志管理 事务日志 transaction log 错误日志 error log ...

  7. Android音视频学习系列(十) — 基于FFmpeg + OpenSL ES实现音频万能播放器

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  8. Linux学习系列之Mount

    Linux学习系列之Mount 在Linux中,如果你要使用储存设备 (Mo.硬盘.光驱等) ,就得先将它挂上 (Mount),而当储存设备挂上了之后,就可以把它当成一个目录来进行访问.挂上一个设备使 ...

  9. 生信宝典Linux学习系列文章整理

    欢迎关注天下博客:http://blog.genesino.com/2017/10/sxbd-linux-summary/ 生信宝典推出的Linux从入门到常用命令.软件安装方法.数据处理方法都在这了 ...

最新文章

  1. 这一次,你能彻底搞懂 Flink!
  2. 遇事不决,XGBoost,梯度提升比深度学习更容易赢得Kaggle竞赛
  3. java中io流案例_Java IO流的简单使用 通俗易懂 超详细 【内含案例】
  4. BeetleX实现HTTP协议详解
  5. Invoke and BeginInvoke BeginInvoke和EndInvoke方法 (转)3
  6. 蓝桥杯 ALGO-11算法训练 瓷砖铺放(递归/动态规划)
  7. python 残差图_利用pyFOAM残差的输出
  8. 命令提示符(文件操作基础)
  9. java实现电脑端拨号+播放语音功能
  10. Downloaded file failed signature verification and may have been tampered with....
  11. Nodejs开发微信公众号--获取access_token
  12. c语言源代码下载TGAM,2018年江西理工大学C语言程序设计竞赛(初级组)一
  13. Python3.6+jieba+wordcloud 爬取豆瓣影评生成词云
  14. 第五章 树16 AcWing 1628. 判断红黑树
  15. 安卓桌面壁纸_梅糖桌面安卓手机版下载-梅糖桌面app官方版下载v2.2安卓版
  16. 索骥馆-DIY操作系统之《30天自制操作系统》扫描版[PDF]
  17. 百果园“两驾马车、三根支柱”商业模式大揭秘
  18. 【前端修炼场】 — 这些标签你学会了么?快速拿下 “hr”
  19. 被绕晕了,嵌入式用C好还是用C++好
  20. 串口服务器中文使用文档,MOXA串口服务器中文使用文档

热门文章

  1. 一本C语言的好书——《C语言的科学与艺术》
  2. 长整型加法和乘法c语言,c语言大数加法,乘法,阶乘!
  3. IoT模组使用笔记(二):EC21、EC200指令流程、设置休眠、升级模组、切换运营商等
  4. java加载中文词向量_Chinese Word Vectors:目前最全的中文预训练词向量集合
  5. mysql帐套仅限_请教一下Banq,关于多帐套的问题
  6. 【末日血战】上古时代英雄的荣光—— 樱泷 平民配置月度BOSS攻略
  7. 毫米波传感器原理介绍:测速
  8. 不甘眼前,勇敢跳槽!毕业生销售转行软件测试的自学逆袭之路!
  9. 阿里云提示安全组与 VPC 不匹配问题解决方案
  10. 可以自定义公式的计算器_什么是公积金贷款计算器?