Конфигурация Vim для разработки ядра Linux

Развитие ядра на самом деле отличается от традиционной разработки проекта C (с моей точки зрения, как новичок). Итак, я всегда задаюсь вопросом, что такое vim-конфигурация хакера ядра.

Самое главное, что как перейти к исходному дереву ядра в vim.. Я пробовал ctags, однако он работает ужасно.

Может кто-нибудь дать мне подсказку?

Ответ 1

Основные различия между ядром Linux и обычным проектом C (с точки зрения разработчика) следующие:

  • Ядро - очень большой проект (поэтому вы должны выбрать, какой код индексировать)
  • он имеет код, зависящий от архитектуры (и вас интересует только одна конкретная архитектура за раз, другие архитектуры не должны индексироваться)
  • он имеет очень специфический стиль который вы должны придерживаться (и vim должен быть настроен для отображения кода соответственно).
  • он не использует стандартную библиотеку C, но вместо этого имеет свои собственные аналогичные процедуры (поэтому ваш инструмент индекса не должен индексировать заголовки libc)

Установка инструментов индексирования

Для навигации по коду ядра я бы посоветовал инструменты cscope и ctags. Чтобы установить их, выполните следующую команду:

$ sudo aptitude install cscope exuberant-ctags

Небольшое объяснение:

  • cscope: будет использоваться для навигации по коду (переключение между функциями и т.д.).
  • ctags: необходим для плагина Tagbar (будет обсуждаться далее) и для Omni completion (механизм автоматического завершения в vim); может также использоваться для навигации

Создание базы данных индексов

Теперь вы должны индексировать исходные файлы ядра. Здесь есть два подхода: создать индекс вручную или использовать доступный script в ядре. Если вы не уверены в том, какой путь лучше всего подходит вам, я рекомендую пойти с ядром script, так как он выполняет множество аккуратных трюков за кулисами (например, игнорирование неиспользуемых источников и перемещение файлов заголовков поверх списка результатов).

Но прежде всего, сконфигурируйте и постройте ядро ​​для вашей архитектуры/платы, так как встроенные файлы могут использоваться позже для улучшения процесса индексирования.

Индексирование с помощью scripts/tags.sh

Ядро имеет неплохую script (scripts/tags.sh) для создания базы данных индекса ядра. Для создания индекса следует использовать правила make cscope и make tags, вместо того, чтобы напрямую запускать этот script.

Пример:

$ make O=. SRCARCH=arm SUBARCH=omap2 COMPILED_SOURCE=1 cscope tags

где

  • O=. - использовать абсолютные пути (полезно, если вы хотите загрузить созданные индексы cscope/ctags вне каталога ядра, например, для разработки модулей ядра, не входящих в дерево). Если вы хотите использовать относительные пути (т.е. Вы собираетесь делать разработку только в каталоге ядра), просто опустите этот параметр
  • SRCARCH=... - выберите архитектуру процессора для индексирования. См. Справочники в разделе arch/ для справки. Например, если SRCARCH=arm, то каталог arch/arm/ будет проиндексирован, остальные каталоги arch/* будут проигнорированы
  • SUBARCH=... - выберите суб-архитектуру (например, файлы, связанные с платой), которые будут проиндексированы. Например, если SUBARCH=omap2 будут индексироваться только каталоги arch/arm/mach-omap2/ и arch/arm/plat-omap/, остальные машины и платформы будут проигнорированы.
  • COMPILED_SOURCE=1 - индексировать только скомпилированные файлы. Вас обычно интересуют только исходные файлы, используемые в вашей сборке (поэтому скомпилированы). Если вы хотите также индексировать файлы, которые не были созданы, просто опустите эту опцию.
  • cscope - правило для создания индекса cscope
  • tags - правило для создания индекса ctags

Индексирование вручную

Ядро script (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 может иметь одно из следующих значений:

  • .: если вы собираетесь работать только в каталоге исходного кода ядра; в этом случае эти команды должны запускаться из корневого каталога исходного кода ядра
  • абсолютный путь к каталогу исходного кода вашего ядра: если вы собираетесь разработать некоторый модуль ядра вне дерева; в этом случае script можно запустить из любого места

Я использую первый вариант (dir=.), потому что я не разрабатываю какие-либо модули из дерева.

Теперь, когда файл 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 plugins

ПРИМЕЧАНИЕ. Далее я расскажу, как использовать патоген для обработки плагинов 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

Установка cscope-карт для vim

В нем уже есть поддержка cscope (см. :help cscope). Вы можете перейти к символу или файлу с помощью команд типа :cs f g kfree. Это не очень удобно. Чтобы ускорить работу, вы можете использовать ярлыки вместо этого (чтобы вы могли навести курсор на какую-то функцию, нажмите комбинацию клавиш и перейдите к функции). Чтобы добавить ярлыки для cscope, вам нужно получить файл cscope_maps.vim.

Чтобы установить его с помощью патогена, вы можете просто клонировать this repo на ваш ~/.vim/bundle:

$ git clone https://github.com/joe-skb7/cscope-maps.git ~/.vim/bundle/cscope-maps

Теперь вы можете перемещаться между функциями и файлами в vim с помощью ярлыков. Откройте исходный файл ядра, поместите курсор на какой-либо вызов функции и нажмите Ctrl + \, а затем g. Это должно привести вас к реализации функции. Или он может показать вам все доступные реализации функций, тогда вы можете выбрать, какой из них использовать: cscope-struct.

Для остальных отображений ключей см. cscope_maps.vim файл.

Вы также можете использовать команды в vim, например:

:cs f g kmalloc

Подробнее см. :help cscope.

ctags note

ctags все равно могут быть полезны для навигации, например, при поиске некоторого объявления #define. Вы можете поместить курсор на это определение использования и нажать g, а затем Ctrl + ]. Подробнее см. этот ответ.

примечание cscope

Следующий трюк можно использовать для поиска структуры объявления в ядре:

: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

Для улучшения поддержки разработки ядра необходимо также внести некоторые изменения в ваш ~/.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.

Полезные плагины

Следующие плагины обычно используются, поэтому вы можете найти их полезными:

Также это интересные плагины, но вам может потребоваться настроить их для ядра:

Выполнение Omni

Vim 7 (и выше) уже имеет встроенную поддержку автозавершения. Он вызывает Omni completion. Подробнее см. : 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://stackoverflow.com/info/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 <[email protected]> <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 цветов

Прежде всего, вы хотите быть уверены, что ваш терминал поддерживает 256 цветов. Например, это может быть достигнуто с помощью urxvt-256. Для gnome-terminal вы можете просто добавить следующую строку в свой ~/.bashrc:

export TERM="xterm-256color"

Как только это будет сделано, введите следующую строку в ~/.vimrc:

set t_Co=256

Цветовая схема

Теперь загрузите схемы, которые вы предпочитаете ~/.vim/colors, и выберите их в ~/.vimrc:

set background=dark
colorscheme hybrid

Какая цветовая схема для использования - это основа, основанная на мнениях. Я могу порекомендовать mrkn256, hybrid и solarized для стартеров.

Шрифт

Есть много хороших шрифтов для программирования там. Многие программисты в Linux используют Terminus шрифт, вы можете попробовать его для начала.

Известные недостатки

Некоторые функции по-прежнему отсутствуют в vim.

  • cscope/ctags не могут использовать определения из include/generated/autoconf.h и игнорировать код, который не был создан. По-прежнему может быть полезно, чтобы все индексированные коды использовали его в качестве ссылки при кодировании.
  • Нет макрорасширения (ну, там есть какая-то функция там (на основе gcc -E), но я не уверен, что он будет работать для ядра).

Единственная IDE, которую я знаю для обработки этих проблем, - Eclipse с CDT.