Ответ 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_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.