Douglas Su Douglas Su - 4 months ago 19
Linux Question

Vim configuration for Linux kernel development

Kernel development is actually different from a traditional C project development (from my view, as a newbie). So, I always wonder what is the vim configuration of a kernel hacker.

The most important is that how to navigate kernel source tree in vim.. I tried

, however, it works terribly.

Can someone give me a clue?


Main differences between Linux kernel and regular C project (from developer's point of view) are next:

  • kernel is very big project (so you should choose which code to index)
  • it has architecture dependent code (and you are only interested in one specific architecture at a time; other architectures shouldn't be indexed)
  • it has very specific coding style you should stick to (and vim should be configured to display code accordingly)
  • it doesn't use C standard library, but instead has it's own similar routines (so your index tool shouldn't index libc sources)

Installing indexing tools

To navigate kernel code I can propose you to use cscope and ctags tools. To install them run next command:

$ sudo aptitude install cscope exuberant-ctags

A little explanation:

  • cscope: will be used to navigate the code (switch between functions, etc.)
  • ctags: needed for Tagbar plugin (will be discussed further) and for Omni completion (auto completion mechanism in vim); can be also used for navigation

Creating index database

Now you should index your kernel. That's the tricky part. Insights were taken from here.

First you need to create cscope.files file which would list all files you want to index. For example, I'm using next commands to list files for ARM architecture (arch/arm), and particularly for OMAP platform (excluding rest of platforms to keep navigation easy):

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

For x86 architecture (arch/x86) you can use something like this:

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 variable can have one of next values:

  • .: if you are gonna work only in kernel source code directory; in this case those commands should be run from root directory of kernel source code
  • absolute path to your kernel source code directory: if you are gonna develop some out-of-tree kernel module; in this case script can be run from anywhere

I'm using first option (dir=.), because I'm not developing any out-of-tree modules.

Now when cscope.files file is ready, we need to run actual indexing:

$ cscope -b -q -k

Where -k parameter tells cscope to not index C standard library (as kernel doesn't use it).

Now it's time to create ctags index database. To accelerate this stage, we're gonna use already created cscope.files:

$ ctags -L cscope.files

Ok, cscope and ctags index databases are built, and you can remove cscope.files file, as we don't need it anymore:

$ rm -f cscope.files

Next files contain index databases (for cscope and ctags):

- cscope.out
- cscope.po.out
- tags

Keep them in root of kernel sources directory.

EDIT: as Andy Shevchenko pointed out, you can also use make cscope rule to build cscope index, and make tags rule to build ctags index. To select architecture to build index for you can use ARCH variable. For example, for ARM you can use next commands:

$ ARCH=arm make cscope
$ ARCH=arm make tags

For x86 architecture it will be ARCH=x86.

I prefer to use my manual commands (above) for listing files, though, as it gives you more flexibility, so you can skip some sources from indexing (like platforms different from yours).

vim plugins

Next we are gonna install some plugins for vim. To have a better grasp on it, I encourage you to use pathogen plugin. It allows you to just git clone vim plugins to your ~/.vim/bundle/ and keep them isolated, rather than mixing files from different plugins in ~/.vim directory.

Install pathogen like it's described here.

Don't forget to do next stuff (as it's described at the same link):

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

Installing cscope maps for vim

Vim already has cscope support in it (see :help cscope). You can jump to symbol or file using commands like :cs f g kfree. It's not so convenient though. To accelerate things you can use shortcuts instead (so you can put your cursor on some function, press some key combination and jump to function). In order to add shortcuts for cscope you need to obtain cscope_maps.vim file.

To install it using pathogen you can just clone this repo to your ~/.vim/bundle:

$ git clone ~/.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-struct.

For the rest of key mappings see cscope_maps.vim file.

You can also use commands in vim like:

:cs f g kmalloc

See :help cscope for details.

ctags note

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 for details.

cscope note

Next trick can be used to find structure declaration in kernel:

:cs f t struct device {

out-of-tree modules development note

If you are developing out-of-tree module, you will probably need to load cscope and ctags databases from your kernel directory. It can be done by next commands in vim (in command mode).

Load external cscope database:

:cs add /path/to/your/kernel/cscope.out

Load external ctags database:

:set tags=/path/to/your/kernel/tags


Some modifications need to be done to your ~/.vimrc as well, in order to better support kernel development.

First of all, let's highlight 81th column with vertical line (as kernel coding requires that you should keep your lines length at 80 characters max):

" 80 characters line
set colorcolumn=81
"execute "set colorcolumn=" . join(range(81,335), ',')
highlight ColorColumn ctermbg=Black ctermfg=DarkRed

Uncomment second line if you want to make 80+ columns highlighted as well.

Trailing spaces are prohibited by kernel coding style, so you may want to highlight them:

" Highlight trailing 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()

Kernel coding style

To make vim respect kernel coding style, you can pull ready to use plugin: vim-linux-coding-style.

Useful plugins

Next plugins are commonly used, so you can find them useful as well:

Also these are interesting plugins, but you may need to configure them for kernel:

Omni completion

Vim 7 (and up) already has auto completion support built in it. It calls Omni completion. See :help new-omni-completion for details.

Omni completion works rather slow on such a big project as kernel. If you still want it, you can enable it adding next lines to your ~/.vimrc:

" Enable OmniCompletion
filetype plugin on
set omnifunc=syntaxcomplete#Complete

" Configure menu behavior
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
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.

Eye candy appearance

256 colors

First of all you want to be sure that your terminal supports 256 colors. For example, it can be achieved using urxvt-256 terminal. For gnome-terminal you can just add next line to your ~/.bashrc:

export TERM="xterm-256color"

Once it's done put next line to your ~/.vimrc:

set t_Co=256

Color scheme

Now download schemes you prefer to ~/.vim/colors and select them in ~/.vimrc:

set background=dark
colorscheme hybrid

Which color scheme to use is strongly opinion based matter. I may recommend mrkn256, hybrid and solarized for starters.


There are a lot of good fonts for programming out there. Many programmers on Linux use Terminus font, you can try it for starters.

Known shortcomings

Some features are still missing in vim.

  1. cscope/ctags can't use definitions from include/generated/autoconf.h and ignore code that wasn't built. It is still may be useful to have all code indexed to use it as reference when coding.
  2. There is no macro expansion (well, there is some function out there (based on gcc -E), but I'm not sure if it's gonna work for kernel).

The only IDE I know to handle those issues is Eclipse with CDT.