Linux 内核和常规 C 项目(从开发人员的角度来看)之间的主要区别如下:
- 内核是一个非常大的项目(所以你应该选择要索引的代码)
- 它具有依赖于架构的代码(并且您一次只对一种特定架构感兴趣;不应对其他架构建立索引)
- 它有非常具体的编码风格 https://www.kernel.org/doc/Documentation/process/coding-style.rst你应该坚持(并且 vim 应该配置为相应地显示代码)
- 它不使用 C 标准库,而是有自己的类似例程(因此您的索引工具不应索引 libc 标头)
安装索引工具
为了导航内核代码,我建议cscope
and ctags
工具。要安装它们,请运行以下命令:
$ sudo aptitude install cscope exuberant-ctags
一点解释:
-
cscope
:将用于导航代码(在功能之间切换等)。它能够跳转到符号定义、查找所有符号用法等。
-
ctags
: 需要用于Tagbar
插件(将进一步讨论)和Omni completion
(vim 中的自动完成机制);也可用于导航。ctags
不像 cscope 那样是 C 代码导航的好选择,因为ctags
只能跳转到符号定义(而不能跳转到其调用者)。
创建索引数据库
现在您应该索引您的内核源文件。这里有两种方法:手动创建索引或使用内核中的可用脚本。如果您不确定哪种方式最适合您,我建议使用内核脚本,因为它在幕后做了很多巧妙的技巧(例如忽略非构建源并将头文件移到结果列表顶部)。
但首先,为您的架构/板配置和构建内核,因为构建的文件稍后可以用来改进索引过程。
索引与scripts/tags.sh
内核有相当好的脚本(scripts/tags.sh
)用于创建内核索引数据库。一个应该使用make cscope
and make tags
规则来创建索引,而不是直接运行该脚本。
Example:
$ make O=. ARCH=arm SUBARCH=omap2 COMPILED_SOURCE=1 cscope tags
where
-
O=.
- 使用绝对路径(如果您想加载在内核目录之外创建的 cscope/ctags 索引文件,例如用于开发树外内核模块,则很有用)。如果你想使用相对路径(即你只在内核目录中进行开发),只需省略该参数
-
ARCH=...
- 选择要索引的CPU架构。请参阅下面的目录arch/
以供参考。例如,如果ARCH=arm
, then arch/arm/
目录将被索引,其余的arch/*
目录将被忽略
-
SUBARCH=...
- 选择要索引的子架构(即与板相关的文件)。例如,如果SUBARCH=omap2
, only arch/arm/mach-omap2/
and arch/arm/plat-omap/
目录将被索引,其余机器和平台将被忽略。
-
COMPILED_SOURCE=1
- 仅索引已编译的文件。您通常只对构建中使用的源文件(因此已编译)感兴趣。如果您还想对未构建的文件建立索引,只需忽略此选项即可。
-
cscope
- 建立cscope索引的规则
-
tags
- 建立ctags索引的规则
手动索引
内核脚本(tags.sh
)可能无法正常工作,或者您可能希望对索引过程有更多控制。在这些情况下,您应该手动索引内核源代码。
关于手动索引的见解取自here http://cscope.sourceforge.net/large_projects.html.
首先你需要创建cscope.files
文件,其中将列出您要索引的所有文件。例如,我使用 next 命令列出 ARM 架构的文件(arch/arm
),特别是对于 OMAP 平台(不包括其他平台以保持导航方便):
find $dir \
-path "$dir/arch*" -prune -o \
-path "$dir/tmp*" -prune -o \
-path "$dir/Documentation*" -prune -o \
-path "$dir/scripts*" -prune -o \
-path "$dir/tools*" -prune -o \
-path "$dir/include/config*" -prune -o \
-path "$dir/usr/include*" -prune -o \
-type f \
-not -name '*.mod.c' \
-name "*.[chsS]" -print > cscope.files
find $dir/arch/arm \
-path "$dir/arch/arm/mach-*" -prune -o \
-path "$dir/arch/arm/plat-*" -prune -o \
-path "$dir/arch/arm/configs" -prune -o \
-path "$dir/arch/arm/kvm" -prune -o \
-path "$dir/arch/arm/xen" -prune -o \
-type f \
-not -name '*.mod.c' \
-name "*.[chsS]" -print >> cscope.files
find $dir/arch/arm/mach-omap2/ \
$dir/arch/arm/plat-omap/ \
-type f \
-not -name '*.mod.c' \
-name "*.[chsS]" -print >> cscope.files
对于 x86 架构(arch/x86
)你可以使用这样的东西:
find $dir \
-path "$dir/arch*" -prune -o \
-path "$dir/tmp*" -prune -o \
-path "$dir/Documentation*" -prune -o \
-path "$dir/scripts*" -prune -o \
-path "$dir/tools*" -prune -o \
-path "$dir/include/config*" -prune -o \
-path "$dir/usr/include*" -prune -o \
-type f \
-not -name '*.mod.c' \
-name "*.[chsS]" -print > cscope.files
find $dir/arch/x86 \
-path "$dir/arch/x86/configs" -prune -o \
-path "$dir/arch/x86/kvm" -prune -o \
-path "$dir/arch/x86/lguest" -prune -o \
-path "$dir/arch/x86/xen" -prune -o \
-type f \
-not -name '*.mod.c' \
-name "*.[chsS]" -print >> cscope.files
Where dir
变量可以具有以下值之一:
-
.
:如果您只想在内核源代码目录中工作;在这种情况下,这些命令应该从内核源代码的根目录运行
-
内核源代码目录的绝对路径:如果你要开发一些树外内核模块;在这种情况下,脚本可以从任何地方运行
我正在使用第一个选项(dir=.
),因为我没有开发任何树外模块。
现在,当cscope.files
文件已准备就绪,我们需要运行实际索引:
$ cscope -b -q -k
Where -k
参数告诉cscope
不索引 C 标准库(因为内核不使用它)。
现在是时候创建了ctags
索引数据库。为了加速这个阶段,我们将重用已经创建的cscope.files
:
$ ctags -L cscope.files
Ok, cscope
and ctags
索引数据库已建立,您可以删除cscope.files
文件,因为我们不再需要它:
$ rm -f cscope.files
接下来的文件包含索引数据库(例如cscope
and ctags
):
- cscope.in.out
- cscope.out
- cscope.po.out
- tags
将它们保存在内核源目录的根目录中。
vim 插件
NOTE:进一步我展示如何使用pathogen用于处理 Vim 插件。但现在 Vim 8 发布了,人们可以使用原生包加载 https://shapeshed.com/vim-packages/出于同样的目的。
接下来我们要为 vim 安装一些插件。为了更好地掌握它,我鼓励您使用pathogen插入。它让您只需git clone
vim 插件到你的~/.vim/bundle/
并使它们保持隔离,而不是混合来自不同插件的文件~/.vim
目录。
Install pathogen就像它所描述的那样here https://github.com/tpope/vim-pathogen.
不要忘记做接下来的事情(如同一链接中所述):
将其添加到您的vimrc
:
execute pathogen#infect()
如果您是 Vim 新手并且缺乏vimrc
, vim ~/.vimrc
并粘贴以下超简单示例:
execute pathogen#infect()
syntax on
filetype plugin indent on
为 vim 安装 cscope 映射
Vim 已经有 cscope 支持(参见:help cscope
)。您可以使用以下命令跳转到符号或文件:cs f g kfree
。虽然不是那么方便。要加速操作,您可以使用快捷方式(这样您可以将光标放在某些功能上,按某些组合键并跳转到功能)。为了添加 cscope 的快捷方式,您需要获取cscope_maps.vim
file.
要安装它,请使用pathogen你可以克隆this https://github.com/joe-skb7/cscope-maps回购到你的~/.vim/bundle
:
$ git clone https://github.com/joe-skb7/cscope-maps.git ~/.vim/bundle/cscope-maps
Now you should be able to navigate between functions and files in vim using shortcuts. Open some kernel source file, put your keyboard cursor on some function call, and press Ctrl+\ followed by g. It should bring you to the function implementation. Or it can show you all available function implementations, then you can choose which one to use: .
对于其余的键映射,请参阅cscope_maps.vim https://github.com/joe-skb7/cscope-maps/blob/master/plugin/cscope_maps.vim#L52 file.
您还可以在 vim 中使用命令,例如:
:cs f g kmalloc
See :help cscope
了解详情。
ctags注释
ctags still can be useful for navigation, for example when looking for some #define
declaration. You can put cursor on this define usage and press g followed by Ctrl+]. See this answer https://stackoverflow.com/a/1749621/3866447 for details.
cscope注释
下一个技巧可用于查找结构宣言在内核中:
:cs f t struct device {
请注意,上述命令依赖于特定的结构声明样式(在内核中使用),因此我们知道结构声明始终具有以下形式:struct some_stuct {
。这个技巧可能不适用于其他编码风格的项目。
树外模块开发说明
如果您正在开发树外模块,您可能需要加载cscope
and ctags
内核目录中的数据库。它可以通过 vim 中的下一个命令来完成(在命令模式下)。
加载外部cscope数据库:
:cs add /path/to/your/kernel/cscope.out
加载外部 ctags 数据库:
:set tags=/path/to/your/kernel/tags
vimrc
需要对您的进行一些修改~/.vimrc
也是为了更好地支持内核开发。
首先,让我们用垂直线突出显示第 81 列(因为内核编码要求您应将行长度保持在最多 80 个字符):
" 80 characters line
set colorcolumn=81
"execute "set colorcolumn=" . join(range(81,335), ',')
highlight ColorColumn ctermbg=Black ctermfg=DarkRed
如果您还想突出显示 80 多个列,请取消注释第二行。
内核编码风格禁止尾随空格,因此您可能需要突出显示它们:
" Highlight trailing spaces
" http://vim.wikia.com/wiki/Highlight_unwanted_spaces
highlight ExtraWhitespace ctermbg=red guibg=red
match ExtraWhitespace /\s\+$/
autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@<!$/
autocmd InsertLeave * match ExtraWhitespace /\s\+$/
autocmd BufWinLeave * call clearmatches()
内核编码风格
为了让 vim 尊重内核编码风格,你可以拉出现成可用的插件:vim Linux 编码风格 https://github.com/vivien/vim-linux-coding-style/commits/master.
有用的插件
接下来的插件很常用,因此您会发现它们也很有用:
- NERDTree https://github.com/scrooloose/nerdtree
- Tagbar https://github.com/majutsushi/tagbar
- 文件行 https://github.com/bogado/file-line
- vim 航空公司 https://github.com/bling/vim-airline
这些也是有趣的插件,但您可能需要为内核配置它们:
-
合成的 https://github.com/scrooloose/syntastic
- YCM https://github.com/Valloric/YouCompleteMe
全方位完成
Vim 7(及更高版本)已经内置了自动完成支持。它调用Omni completion
. See :帮助新的全能完成 http://vimdoc.sourceforge.net/htmldoc/version7.html#new-omni-completion了解详情。
在像内核这样的大项目上,Omni 完成工作的速度相当慢。如果您仍然需要它,您可以启用它,将下一行添加到您的~/.vimrc
:
" Enable OmniCompletion
" http://vim.wikia.com/wiki/Omni_completion
filetype plugin on
set omnifunc=syntaxcomplete#Complete
" Configure menu behavior
" http://vim.wikia.com/wiki/VimTip1386
set completeopt=longest,menuone
inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
inoremap <expr> <C-n> pumvisible() ? '<C-n>' :
\ '<C-n><C-r>=pumvisible() ? "\<lt>Down>" : ""<CR>'
inoremap <expr> <M-,> pumvisible() ? '<C-n>' :
\ '<C-x><C-o><C-n><C-p><C-r>=pumvisible() ? "\<lt>Down>" : ""<CR>'
" Use Ctrl+Space for omni-completion
" https://stackoverflow.com/questions/510503/ctrlspace-for-omni-and-keyword-completion-in-vim
inoremap <expr> <C-Space> pumvisible() \|\| &omnifunc == '' ?
\ "\<lt>C-n>" :
\ "\<lt>C-x>\<lt>C-o><c-r>=pumvisible() ?" .
\ "\"\\<lt>c-n>\\<lt>c-p>\\<lt>c-n>\" :" .
\ "\" \\<lt>bs>\\<lt>C-n>\"\<CR>"
imap <C-@> <C-Space>
" Popup menu hightLight Group
highlight Pmenu ctermbg=13 guibg=LightGray
highlight PmenuSel ctermbg=7 guibg=DarkBlue guifg=White
highlight PmenuSbar ctermbg=7 guibg=DarkGray
highlight PmenuThumb guibg=Black
" Enable global scope search
let OmniCpp_GlobalScopeSearch = 1
" Show function parameters
let OmniCpp_ShowPrototypeInAbbr = 1
" Show access information in pop-up menu
let OmniCpp_ShowAccess = 1
" Auto complete after '.'
let OmniCpp_MayCompleteDot = 1
" Auto complete after '->'
let OmniCpp_MayCompleteArrow = 1
" Auto complete after '::'
let OmniCpp_MayCompleteScope = 0
" Don't select first item in pop-up menu
let OmniCpp_SelectFirstItem = 0
And use Ctrl+Space for auto completion.
养眼的外观
256色
首先您要确保您的终端支持 256 色。例如,可以使用以下方式实现urxvt-256 https://en.wikipedia.org/wiki/Rxvt-unicode终端。为了gnome-terminal
您只需将下一行添加到您的~/.bashrc
:
export TERM="xterm-256color"
完成后将下一行添加到您的~/.vimrc
:
set t_Co=256
配色方案
现在下载您喜欢的方案~/.vim/colors
并在其中选择它们~/.vimrc
:
set background=dark
colorscheme hybrid
使用哪种配色方案是强烈基于意见的问题。我可以推荐mrkn256 https://github.com/mrkn/mrkn256.vim, hybrid https://github.com/w0ng/vim-hybrid and 晒过的 https://github.com/altercation/vim-colors-solarized对于初学者。
Font
有很多适合编程的好字体。许多 Linux 程序员都使用Terminus http://terminus-font.sourceforge.net/shots.html字体,初学者可以尝试一下。
已知的缺点
vim 中仍然缺少一些功能。
- cscope/ctags 不能使用以下定义
include/generated/autoconf.h
并忽略未构建的代码。对所有代码进行索引以在编码时将其用作参考仍然可能有用。
- 没有宏扩展(嗯,有is some function http://vim.wikia.com/wiki/Macro_expansion_C/C%2B%2B在那里(基于
gcc -E
),但我不确定它是否适用于内核)。
我所知道的唯一可以处理这些问题的 IDE 是带有 CDT 的 Eclipse https://wiki.eclipse.org/HowTo_use_the_CDT_to_navigate_Linux_kernel_source.