内核开发实际上不同于传统的C项目开发(从我看来,作为一个新手)。 所以,我总是想知道内核黑客的vimconfiguration是什么。
最重要的是,如何在VIM中导航内核源码树。我试过ctags
,但是,它工作起来非常糟糕。
有人能给我一个线索吗?
接下来是Linux内核和普通C项目的主要区别(从开发者的角度)
浏览内核代码,我会建议cscope
和ctags
工具。 要安装它们,运行下一个命令:
$ sudo aptitude install cscope exuberant-ctags
一点解释:
cscope
:将用于导航代码(在函数之间切换等) ctags
:需要为Tagbar
插件(将进一步讨论)和Omni completion
(vim中的自动完成机制); 也可以用于导航 现在你应该索引你的内核源文件。 这里有两种方法:手动创建索引或在内核中使用可用的脚本。 如果您不确定哪种方式最适合您,我推荐使用内核脚本,因为它在后台执行了许多巧妙的技巧(如忽略未构建的源代码和在结果列表顶部移动头文件)。
但首先,为您的架构/主板配置和构建内核,因为以后可以使用构建的文件来改进索引过程。
scripts/tags.sh
索引 内核有相当不错的脚本( scripts/tags.sh
)来创建内核索引数据库。 一个应该使用make cscope
并且make tags
规则来创建索引,而不是直接运行该脚本。
例:
$ make O=. SRCARCH=arm SUBARCH=omap2 COMPILED_SOURCE=1 cscope tags
哪里
O=.
– 使用绝对路径(如果您想要在内核目录之外加载创建的cscope / ctags索引文件(例如,用于开发树内核模块),则很有用)。 如果你想使用相对路径(即你只会在内核目录中进行开发),只需省略该参数即可 SRCARCH=...
– 选择CPU架构进行索引。 请参阅arch/
目录以供参考。 例如,如果SRCARCH=arm
,那么arch/arm/
目录将被索引, arch/*
目录的其余部分将被忽略 SUBARCH=...
– 选择要建立索引的子体系结构(即板相关文件)。 例如,如果SUBARCH=omap2
,只有arch/arm/mach-omap2/
和arch/arm/plat-omap/
目录会被索引,其余的机器和平台将被忽略。 COMPILED_SOURCE=1
– 仅索引编译的文件。 你通常只对你的构建中使用的源文件感兴趣(因此编译)。 如果你想索引还没有建立的文件,只需省略此选项。 cscope
– 制作cscope索引的规则 tags
– 规则,使ctags指数 内核脚本( tags.sh
)可能无法正常工作(例如,当您的主板有不同的mach-omap2
目录,如mach-omap2
和plat-omap
),或者您可能想要更多地控制索引过程。 在这种情况下,你应该手动索引内核源代码。
手动索引的见解是从这里采取的。
首先,您需要创建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
和ctags
):
- cscope.in.out - cscope.out - cscope.po.out - tags
将它们保存在内核源码目录的根目录下。
注 :进一步我展示了如何使用病原体来处理Vim插件。 但是现在Vim 8已经发布了,可以使用本地包加载来达到同样的目的。
接下来我们要为vim安装一些插件。 为了更好地掌握它,我鼓励你使用病原体插件。 它允许你只将git clone
vim插件放到你的~/.vim/bundle/
并保持它们的隔离,而不是混合来自~/.vim
目录中不同插件的文件。
像这里描述的那样安装病原体 。
不要忘记做下一个东西(就像在同一个链接中描述的那样):
添加到您的
vimrc
:execute pathogen#infect()
如果你是Vim的新手,并且缺少一个
vimrc
,vim ~/.vimrc
并粘贴下面这个超级简单的例子:execute pathogen#infect() syntax on filetype plugin indent on
Vim已经有了cscope的支持(参见:help cscope
)。 您可以使用如下命令跳转到符号或文件:cs fg kfree
。 虽然不太方便 为了加快速度,你可以使用快捷方式(所以你可以把你的光标放在某个功能上,按下一些组合键并跳转到功能)。 为了添加cscope的快捷方式,你需要获得cscope_maps.vim
文件。
要使用病原体进行安装,您可以将此 repo克隆到~/.vim/bundle
:
$ git clone https://github.com/joe-skb7/cscope-maps.git ~/.vim/bundle/cscope-maps
现在,你应该能够使用快捷方式在vim中的函数和文件之间导航。 打开一些内核源文件,将你的键盘光标放在某个函数调用上,然后按Ctrl + \,然后按g 。 它应该带给你的功能实现。 或者它可以显示所有可用的功能实现,那么你可以选择使用哪一个: 。
对于其他键映射,请参阅cscope_maps.vim文件。
你也可以在vim中使用命令:
:cs fg kmalloc
有关详细信息,请参阅:help cscope
。
ctags仍然可以用于导航,例如,当寻找一些#define
声明。 你可以把光标放在这个定义的用法上,然后按g然后按Ctrl + ] 。 看到这个答案的细节。
下一个技巧可以用来在内核中查找结构声明 :
:cs ft struct device {
请注意,上面的命令依赖于特定的struct声明样式(在内核中使用),所以我们知道struct声明总是具有这种形式: 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 completion
。 有关详细信息,请参阅:help new-omni-completion 。
Omni完成在像kernel这样的大项目上工作起来相当缓慢。 如果你仍然需要它,你可以启用它,将下一行添加到你的~/.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() ? "\<Cy>" : "\<Cg>u\<CR>" inoremap <expr> <Cn> pumvisible() ? '<Cn>' : \ '<Cn><Cr>=pumvisible() ? "\<lt>Down>" : ""<CR>' inoremap <expr> <M-,> pumvisible() ? '<Cn>' : \ '<Cx><Co><Cn><Cp><Cr>=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>Cn>" : \ "\<lt>Cx>\<lt>Co><cr>=pumvisible() ?" . \ "\"\\<lt>cn>\\<lt>cp>\\<lt>cn>\" :" . \ "\" \\<lt>bs>\\<lt>Cn>\"\<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 + 空格来自动完成。
首先你要确保你的终端支持256色。 例如,可以使用urxvt-256终端来实现。 对于gnome-terminal
你可以添加下一行到你的~/.bashrc
:
export TERM="xterm-256color"
一旦完成,把下一行放到~/.vimrc
:
set t_Co=256
现在下载你喜欢的模式~/.vim/colors
并在~/.vimrc
选择它们:
set background=dark colorscheme hybrid
使用哪种配色方案是强烈的基于观点的事项。 我可能会推荐mrkn256 , 混合和日光照射的初学者。
那里有很多好的字体可供编程。 Linux上的许多程序员使用Terminus字体,你可以试试它的初学者。
有些功能在vim中仍然缺失。
include/generated/autoconf.h
定义,而忽略那些没有构建的代码。 编码时将所有代码编入索引以作为参考仍然是有用的。 gcc -E
),但我不知道它是否会为内核工作)。 我知道唯一处理这些问题的IDE是Eclipse和CDT 。