内核开发实际上与传统的C项目开发有所不同(从我这个新手的角度来看)。因此,我一直想知道内核黑客的vim配置是什么。
最重要的是如何在vim中导航内核源代码树。我尝试过ctags
,但是效果非常糟糕。
是否有人可以给我一些提示?
内核开发实际上与传统的C项目开发有所不同(从我这个新手的角度来看)。因此,我一直想知道内核黑客的vim配置是什么。
最重要的是如何在vim中导航内核源代码树。我尝试过ctags
,但是效果非常糟糕。
是否有人可以给我一些提示?
从开发者的角度来看,Linux内核和常规C项目之间的主要区别如下:
为了浏览内核代码,我建议使用cscope
和ctags
工具。要安装它们,请运行以下命令:
$ sudo aptitude install cscope exuberant-ctags
简单解释一下:
cscope
:用于浏览代码(切换函数等)。它能够跳转到符号定义,查找所有符号用法等。ctags
:需要用于Tagbar
插件(稍后将进行讨论)和vim
中的自动完成机制Omni completion
;也可以用于导航。对于C代码导航,ctags
并不像cscope那样好,因为ctags
只能跳转到符号定义而不能跳转到其调用者。现在,您应该对内核源文件进行索引。这里有两种方法:手动创建索引或使用内核中可用的脚本。如果您不确定哪种方法最适合您,建议使用内核脚本,因为它在幕后执行了许多巧妙的技巧(例如忽略未构建的源文件并将标头文件移动到结果列表的顶部)。
但首先,为您的体系结构/板配置和构建内核,因为构建文件可以稍后用于改善索引过程。
scripts/tags.sh
进行索引内核有一个相当好的脚本(scripts/tags.sh
)用于创建内核索引数据库。应该使用 make cscope
和 make tags
规则来创建索引,而不是直接运行该脚本。
示例:
$ make O=. ARCH=arm SUBARCH=omap2 COMPILED_SOURCE=1 cscope tags
这里是关于 where
的一些参数解释:
O=.
- 使用绝对路径(如果你希望在内核目录之外加载已创建的 cscope/ctags 索引文件,比如用于开发目录中的 out-of-tree 内核模块),如果你只想在内核目录中进行开发,则可以省略该参数。ARCH=...
- 选择要索引的 CPU 架构。参见 arch/
目录下的子目录。例如,如果 ARCH=arm
,则会索引 arch/arm/
目录,其余的 arch/*
目录将被忽略。SUBARCH=...
- 选择要索引的子架构(即与板相关的文件)。例如,如果 SUBARCH=omap2
,则只会索引 arch/arm/mach-omap2/
和 arch/arm/plat-omap/
目录,其余的机器和平台将被忽略。COMPILED_SOURCE=1
- 只索引编译过的文件。通常你只对你构建使用的源文件感兴趣(因此是编译的)。如果你还想索引未构建的文件,只需省略此选项即可。cscope
- 用于创建 cscope 索引的规则tags
- 用于创建 ctags 索引的规则内核脚本 (tags.sh
) 可能无法正确工作,或者你可能想更好地控制索引过程。在这些情况下,你应该手动索引内核源代码。
手动索引的见解可从这里获得。
首先需要创建 cscope.files
文件,其中列出了你要索引的所有文件。例如,我使用以下命令列出 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
dir
变量可能有以下几个值:
.
:如果你只在内核源代码目录中工作,那么这些命令应该从内核源代码的根目录运行。我使用第一个选项 (dir=.
),因为我没有开发任何 out-of-tree 模块。
现在当 cscope.files
文件准备好后,我们需要运行实际的索引:
$ cscope -b -q -k
-k
参数告诉cscope
不要索引C标准库(因为内核并不使用它)。
现在是创建ctags
索引数据库的时候了。为了加速此过程,我们将重用已经创建的cscope.files
:
$ ctags -L cscope.files
好的,cscope
和ctags
索引数据库已经建立完成,你可以删除cscope.files
文件,因为我们不再需要它了:
$ rm -f cscope.files
- cscope.in.out
- cscope.out
- cscope.po.out
- tags
将它们放在内核源代码目录的根目录中。
注意:接下来我会展示如何使用pathogen处理Vim插件。但是现在Vim 8已经发布,可以使用本地包加载来达到相同的目的。
接下来我们将安装一些Vim插件。为了更好地掌握它,我鼓励您使用pathogen插件。它允许您只需将vim插件git clone
到您的~/.vim/bundle/
并使其保持隔离,而不是将来自不同插件的文件混合在~/.vim
目录中。
像这里描述的那样安装pathogen。
不要忘记执行下面的操作(就像在同一个链接中描述的那样):
Add this to your
vimrc
:
execute pathogen#infect()
If you're brand new to Vim and lacking a
vimrc
,vim ~/.vimrc
and paste in the following super-minimal example:
execute pathogen#infect() syntax on filetype plugin indent on
Vim已经支持cscope(请参阅:help cscope
)。您可以使用命令,如:cs f g kfree
跳转到符号或文件。但这样不太方便。为了加速操作,您可以使用快捷方式(将光标放在某个函数上,按下某个键组合并跳转到该函数)。要添加cscope的快捷方式,您需要获取cscope_maps.vim
文件。
要使用pathogen安装它,您只需将此存储库克隆到您的~/.vim/bundle
中即可:
$ git clone https://github.com/joe-skb7/cscope-maps.git ~/.vim/bundle/cscope-maps
:cs f g kmalloc
请查看:help cscope
以获取详细信息。
即使在查找某些#define
声明时,ctags仍可以用于导航。您可以将光标放在此定义的使用上,然后按g,接着按Ctrl+]。详情请参见此答案。
下一个技巧可用于在内核中查找结构体声明:
:cs f t struct device {
struct some_stuct {
。这个技巧可能在其他编码风格的项目中无法使用。
如果您正在开发外部模块,则可能需要从内核目录加载cscope
和ctags
数据库。可以通过以下命令在vim中(命令模式下)完成:
加载外部cscope数据库:
:cs add /path/to/your/kernel/cscope.out
加载外部ctags数据库:
:set tags=/path/to/your/kernel/tags
为了更好地支持内核开发,您需要对~/.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-coding-style。
下面的插件通常被广泛使用,所以您可能也会觉得它们很有用:
以下是一些有趣的插件,但您可能需要根据内核进行配置:
Vim 7(及以上版本)已经内置了自动完成支持,它称之为Omni自动补全
。详见:help 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://dev59.com/ZnRB5IYBdhLWcg3wyqKo
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
使用 Ctrl+Space 进行自动完成。
首先,您要确保您的终端支持 256 种颜色。例如,可以使用 urxvt-256 终端来实现此目的。对于 gnome-terminal
,您只需将下一行添加到您的 ~/.bashrc
中即可:
export TERM="xterm-256color"
完成后,将下面这行代码加入到你的~/.vimrc
文件中:
set t_Co=256
现在下载您喜欢的配色方案到~/.vim/colors
文件夹,并在~/.vimrc
中选择它们:
set background=dark
colorscheme hybrid
include/generated/autoconf.h
中的定义,并忽略未构建的代码。将所有代码索引以将其用作编码参考仍然可能是有用的。gcc -E
),但我不确定它是否适用于内核)。
make cscope
即可完成任务。 - 0andriymake cscope
,我看了一下。决定继续使用手动命令列出文件,但是真的改进了它们(也在我的答案中进行了更改)。我的命令(现在)似乎会产生更少的索引文件(特别是针对ARM架构),而且它们也更加灵活(例如,我删除了kvm
和xen
子系统的索引,因为我不使用它们)。 - Sam Protsenkomake cscope
的备注。谢谢! - Sam Protsenko