Компиляция программ.
Прежде чем заняться созданием собственной среды разработки, стоит получить представление о том, какими утилитами
предстоит пользоваться при работе с проектом. В самом простейшем случае, когда исходный текст программы находится в
одном-единственном файле, можно не тратя время в шелле запустить GCC, чтобы, в случае отсутствия ошибок,
откомпилировать и слинковать программу и получить исполняемый бинарный файл:
g++ -o resultname source.cpp
Когда количество исходных файлов превышает один, такой подход нецелесообразен. Чтобы автоматизировать процесс
создания исполняемого файла, используют программу GNU make, которая стала стандартом де-факто в области управления
компиляцией. В составе пакета MinGW есть утилита mingw32-make.exe, которая является портом GNU make. Эта утилита
использует спецификацию из Makefile, чтобы откомпилировать исходные тексты программы и произвести сборку. Makefile
содержит записи, которые условно представимы в виде описаний: ЦЕЛЬ -> ЗАВИСИМОСТЬ -> КОМАНДА. Где ЦЕЛЬ — обычно
имя файла генерируемого программой GNU make, ЗАВИСИМОСТЬ — файл или группа файлов используемых для порождения цели
и КОМАНДА — действие, которое выполняет GNU make для того, чтобы получить ЦЕЛЬ из множества ЗАВИСИМОСТИ.
Ниже представлен пример простого Makefile, в котором описывается, что исполняемый файл decoder зависит от объектных
файлов main.o и decoder.o, а также зависимости файлов между собой и правила их компиляции и сборки.
decoder : main.o decoder.o
g++ -o decoder main.o decoder.o
main.o : main.cpp decoder.h
g++ -c main.cpp
decoder.o : decoder.cpp decoder.h
g++ -c decoder.cpp
clean :
rm decoder main.o decoder.o
Для того, чтобы создать исполняемый файл decoder, надо набрать в шелле:
make
Для удаления исполняемого файла и очистки каталога от объектных файлов надо выполнить команду:
make clean
Детальное описание использования GNU make можно
прочитать здесь.
qmake.
Библиотека Qt предоставляет в распоряжение программиста утилиту qmake, которая автоматизирует процесс создания
Makefile для GNU make. Запуск:
qmake -project
в директории с исходными файлами приведёт к генерации файла проекта, который будет использован в дальнейшем утилитой
qmake для генерации целевых Makefile -ов используемых GNU make: дальнейший запуск qmake без параметров создаст
директории release и debug, файлы Makefile, Makefile.Debug, Makefile.Release, которые используются для сборки debug и
release версий программой GNU make. Более подробную информацию о qmake можно получить вызвав Qt Assistant.
Пошаговая отладка программ.
Ключ компилятора -ggdb заставляет последний скомпилировать программу с отладочной информацией необходимой для
пошаговой отладки с помощью программы GNU gdb:
g++ -ggdb -o resultname source.cpp
Выполнение команды:
gdb resultname
приведёт к запуску дебаггера GNU gdb и загрузке в него символьной таблицы отлаживаемого
файла resultname. После старта дебаггер переходит в интерактивный режим и ожидает ввода команд от
пользователя.
test1.cpp:
int main(int, char**)
{
int a = 10;
a++;
a *= 7;
a--;
return 0;
}
g++ --ggdb -o result test1.cpp
gdb result.exe
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-mingw32"...
(gdb) list
1 int main(int, char**)
2 {
3 int a = 10;
4 a++;
5 a *= 7;
6 a--;
7
8 return 0;
9 }
(gdb) break main
Breakpoint 1 at 0x401305: file test1.cpp, line 2.
(gdb) run
Starting program: D:\test/result.exe
gdb: do_initial_child_stuff: process 2588
gdb: kernel event for pid=2588 tid=3448 code=CREATE_PROCESS_DEBUG_EVENT)
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
...
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_BREAKPOINT at 0x77f65a58
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_BREAKPOINT at 0x00401305
Breakpoint 1, main () at test1.cpp:2
2 {
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401400
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_BREAKPOINT at 0x0040130a
3 int a = 10;
(gdb) watch a
Hardware watchpoint 2: a
(gdb) continue
Continuing.
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
еgdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401311
Program received signal SIGTRAP, Trace/breakpoint trap.
main () at test1.cpp:4
4 a++;
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401314
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401316
Hardware watchpoint 2: a
Old value = 2
New value = 11
main () at test1.cpp:5
5 a *= 7;
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401319
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x0040131b
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x0040131e
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401320
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401323
Hardware watchpoint 2: a
Old value = 11
New value = 77
main () at test1.cpp:6
6 a--;
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401326
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401328
Hardware watchpoint 2: a
Old value = 77
New value = 76
main () at test1.cpp:8
8 return 0;
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x0040132d
9 }
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x0040132e
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0x0040132e in main () at test1.cpp:9
9 }
(gdb) next
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401237
0x00401237 in __mingw_CRTStartup ()
(gdb) next
Single stepping until exit from function __mingw_CRTStartup,
which has no line number information.
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401239
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x004017f0
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_BREAKPOINT at 0x0040123e
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x00401241
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXCEPTION_DEBUG_EVENT)
gdb: Target exception EXCEPTION_SINGLE_STEP at 0x004018b0
gdb: child_resume.SetThreadContext: thread 2588.0xd78
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: kernel event for pid=2588 tid=3448 code=EXIT_PROCESS_DEBUG_EVENT)
Program exited normally.
ContinueDebugEvent (cpid=2588, ctid=3448, DBG_CONTINUE);
gdb: child_close, inferior_ptid=3448
(gdb)
Вывод GNU gdb достаточно многословен. В реальности применяют один из существующих фронтендов к gdb, который фильтрует
вывод gdb и показывает параллельно исполнению кода текущее положение в исходном тексте программы. Ниже в статье будет
показан процесс использования IDE для пошаговой
отладки. Здесь вы можете найти краткий справочник по
командам GNU gdb.
Qt Designer.
Qt Designer
Пользовательский графический интерфейс можно создавать "руками" создавая в коде необходимые виджеты и размещая их "на
глаз" в родительских контейнерах, но это отнимает много времени и становится слишком утомительным, если требуется
сделать интерфейс, сложность которого превышает "примитивную". Библиотека позволяет упростить и автоматизировать процесс
создания GUI предоставляя в распоряжение пользователям программу Qt Designer. Эта программа позволяет создавать
диалоговые окна и виджеты (элементы управления) и сохранять их в виде xml файлов с расширением .ui. В состав утилит
библиотеки входит uic - User Interface Compiler, который из xml файлов создаёт C++ заголовочные файлы
содержащие декларации оконных классов. При использовании qmake вызов uic происходит автоматически, так, что всё, что
остаётся сделать программисту, это подключить заголовочный файл в коде программы и написать код, создающий и
инициализирующий необходимые объекты.
Qt включает в себя достаточно большой набор виджетов, чтобы обеспечить стандартную функциональность графического
интерфейса, кроме того, позволяет пользователю разрабатывать и использовать собственные элементы управления. Для
меж-объектного взаимодействия Qt применяет механизм сигналов и слотов как альтернативу механизму обратных вызовов,
принятого в большинстве оконных библиотек. Суть механизма заключается в привязке объектов инициирующих сигналы с
объектами содержащими слоты, между которыми установили привязку. Связывать сигналы и слоты виджетов, если есть такая
необходимость, можно достаточно удобным способом непосредственно в Qt Designer. Более подробную информацию о механизме
сигналов и слотов можно найти в Qt Assistant.
Пример
редактирования диалогового окна
Разместив элементы управления, сделав необходимую привязку между сигналами и слотами и сохранив результат в .ui
файле, требуется перегенерировать файл проекта, вызвав qmake -project, после чего в файл проекта добавятся созданные .ui
файлы и, далее при вызове qmake будут созданы make файлы, при обработке которых, GNU make
вызовет uic, который создаст необходимые заголовочные файлы. До вызова GNU make, для того чтобы
задействовать в программе созданные объекты, необходимо подключить заголовочные файлы, которые будут созданы при вызове
GNU make, и создать необходимые объекты. Более подробная информация, а также пример простого приложения, использующего
результат работы Qt Designer можно найти в Qt Assistant.
Вступление.
До сих пор опускалась одна очень важная деталь: чем создавать и редактировать исходные тексты программ. Пора
исправить этот пробел. Стандартные редакторы идущие вместе с операционной системой Windows: Notepad и Wordpad не
подходят для обработки исходных текстов. Точнее сказать, они вообще ни для чего не подходят, т.к. попросту неудобны для
работы. К счастью, существует множество альтернатив стандартным текстовым редакторам, среди которых, есть что выбирать.
К редактору для программиста предъявляются особые требования. Помимо удобного редактора текста, во-первых, он должен
уметь делать специфичные вещи связанные с разработкой, такие как: подсветка текста, удобная навигация по коду, интеграция
с окружением, чтобы можно было не переключаясь из редактора проводить процесс сборки и отладки и прочее, а во-вторых,
должен иметь возможность гибкой настройки себя, чтобы пользователь мог избежать ненужного раздражения в работе.
GNU Emacs умеет всё. Не просто перечисленное, что должен уметь редактор для программиста, а вообще всё, что есть в
области работы с текстовой информацией. Кроме того, GNU Emacs работает везде, что очень важно для многих, т.к. зачастую
приходится работать в непривычном окружении. Достаточно указать GNU Emacs, где брать файл конфигурации и пользователь
получает в своё распоряжение привычную среду для работы. GNU Emacs написан на языках C и ELisp и представляет собой
ELisp интерпретатор, предоставляющий пользователю возможность переопределять любую ELisp функцию, что позволяет как
угодно гибко настроить редактор под собственные нужды.
Для начинающего пользователя, возможно, GNU Emacs покажется слишком сложным для освоения: для конфигурации редактора
применяется незнакомый язык ELisp, клавиатурные комбинации напоминают сложные распальцовки, состоящие из
последовательностей нажатий нескольких клавиш, кроме того, возможно, для некоторых внешний вид редактора покажется
отталкивающим.
Но, это так только на первый взгляд. Некоторая сложность освоения полностью компенсируется удобством работы, экономя
потом многие часы. Клавиатурные комбинации вбиваются "в пальцы", результат работы дизайнеров выражающийся в красивом
тулбаре или подмигивающей скрепке становится ненужным (справедливости ради, внешний вид тулбара тоже можно полностью
изменить, использовав собственные иконки и привязки), а язык ELisp оказывается интуитивно-понятным, не требующим
предварительного чтения здоровенных руководств.
Установка GNU Emacs и предварительные шаги.
На этой странице находится актуальная версия (на
данный момент 22.0.50.1) GNU Emacs для Windows (около 23Мб). Выберите пункт: "Download latest EmacsW32+Emacs patched"
— это пропатченная версия Emacs для более удобного использования в среде Windows.
Установка не должна вызвать каких-то сложностей. Просто принимаем всё по-умолчанию, что предлагает установщик.
Что необходимо знать для дальнейшего чтения. Клавиатурные комбинации используемые в Emacs принято давать в виде
C-..., M-..., C-M-..., где "C" означает клавишу
"Ctrl", "M" (Meta) означает клавишу "Alt" или "Esc", запись C-x означает нажатие и удерживание
клавиши "Ctrl" и последующее нажатие "x", а M M l означает последовательное без удерживаний
нажатие клавиш Meta Meta l. Там где встречается комбинация Meta-key,
используется "Alt", а там где Meta key — "Esc". Для комбинаций
C-key1 C-key2 клавишу "Ctrl" между нажатиями "key1" и "key2" отпускать необязательно. Домашним
каталогом для Emacs, обозначаемым при операциях с файлами "~/" является директория "Documents and Settings/user
name/Application Data/" на диске, где установлен Windows. Название директории приведено для английской версии Windows.
Файлом конфигурации загружаемым при старте Emacs, является файл ~/.emacs, который будет создан автоматически после
первого сохранения опций, доступного через меню "Options -> Save options", при условии, что были
изменены какие-либо настройки.
Итак, заставим создать Emacs файл конфигурации. Выберем пункт
"Options -> Show/Hide -> Column Numbers", чтобы Emacs отображал колонку текущей позиции
курсора. Затем сохраним изменения: "Options -> Save options". Посмотрите результат, открыв файл
"~/.emacs", используя C-x C-f. В результате появится файл конфигурации, в котором будут
содержаться следущие строки:
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(column-number-mode t))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
Эти два блока генерируются автоматически и должны существовать в единственном экземпляре в файле
конфигурации. Некоторые настройки мы будем задавать в этих блоках, чтобы сохранить возможность переключать опции из
меню, большинство же настроек, будут задаваться вполне нормальным способом с помощью конструкции (setq variable
value).
Прежде чем продолжить, настоятельно рекомендую потратить двадцать минут на чтение руководства на родном языке,
доступного через вызов М-х help-with-tutorial-spec-language, для того, чтобы не возникало совсем
детских вопросов при работе с Emacs. Кроме того, первое время полезно держать под рукой
распечатку краткого справочника по наиболее
используемым клавиатурным привязкам XEmacs, большинство из которых совпадает с клавиатурными привязками Emacs.
Базовая настройка, не требующая дополнительных пакетов.
Есть вещи, настроенные по-умолчанию в Emacs, которые я не принял. Мне неудобно выделение текста с
помощью C-SPC, вместо него, я использую привычную комбинацию с помощью клавиши "Shift" и команд
перемещения курсора (здесь и далее строки из ~/.emacs файла):
;; text selection
(cua-selection-mode t)
Установка этого режима, кроме того, включит transient-mark-mode, отвечающий за подсветку выделенной области, так, что
не будет необходимости дополнительно устанавливать transient-mark-mode.
По-умолчанию Emacs создаёт и сохраняет текст в ANSI кодировке. Используемая версия редактора скомпилирована с
поддержкой MULE - пакета обеспечивающего интернационализацию. Как приемлимый вариант, я выбрал среду с UTF-8 кодировкой,
во-первых, при сохранении текста содержащего только латинские символы он будет сохранён как обычный ANSI текст,
во-вторых, UTF-8 позволяет работать одновременно как с кириллицей, так и с умляутами и символами с аксцентом, а в
третьих, GCC понимает файлы в данной кодировке, так что не возникнет проблем при написании программ с комментариями на
русском языке, к примеру. Наконец, утилиты Windows XP Pro понимают эту кодировку (Home Edition не распознаёт
UTF-8). "Родная" Unicode- кодировка для Windows это UTF-16-LE, при желании можно выбрать её, но в этом случае не
получится иметь ANSI текст при использовании букв только латинского алфавита и понимает ли GCC UTF-16-LE или нет, я не
выяснял. Для ввода кириллицы, я как владелец ноутбука с немецкой клавиатурой не желающий ни обезображивать последнюю
наклейками с русскими буквами, ни учить дополнительно слепой десяти пальцевый ввод используя йцукен- раскладку, использую
транслитерацию латинских символов при вводе. Настройка языковой среды и метода ввода:
;; Mule cyrillic config
(set-language-environment 'UTF-8)
(setq default-input-method "cyrillic-translit")
Для переключения метода ввода, ввиду невозможности задействовать стандартную комбинацию C-M-\
на моей клавиатуре, я переназначил переключение на последовательность C-x C-y:
;; C-x C-y switchs input method
(global-set-key (kbd "\C-x \C-y") 'toggle-input-method)
Следущее, что мне не нужно, это стартовое сообщение, его отключение:
;; Prevent the startup message
(setq inhibit-startup-message t)
Если фрейм разделён на несколько окон (попробуйте C-x 2), Emacs по-умолачанию показывает
"неактивные" курсоры во всех остальных окнах, мне больше нравится отображение принятое по-умолчанию в XEmacs, когда
показывается только один курсор в текущем, активном окне. Для достижения этого требуется внести значение переменной
cursor-in-non-selected-windows в список custom-set-variables:
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(column-number-mode t)
;; inhibit hallow cursors in inactive windows
'(cursor-in-non-selected-windows nil))
Так же беру способ переключения между окнами внутри текущего фрейма из XEmacs, когда переключение осуществляется
клавишами C-TAB:
;; C-tab switchs to a next window
(global-set-key [(control tab)] 'other-window)
Есть одна вещь жутко раздражавшая меня: прыжковый скроллинг при достижении курсора нижней или верхней границ
экрана. Я предпочитаю "консервативный" способ, когда при скроллинге происходит сдвиг на одну строку, кроме того, мне
удобно иметь "отступ" при скроллинге, когда последний происходит не при достижении границы экрана, а на несколько строк
раньше:
;; conservatively scrolling
(setq scroll-conservatively 50)
(setq scroll-margin 4)
При работе с исходными текстами программ я предпочитаю иметь отступ в виде табуляции длинной в два символа и всегда,
а не только при вводе, при попадании курсора на скобку, подсвечивать парную ей, кроме того, я немного изменил цвет
подсветки парных скобок:
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(column-number-mode t)
;; inhibit hallow cursors in inactive windows
'(cursor-in-non-selected-windows nil))
'(show-paren-mode t)
'(standard-indent 2)
'(tab-width 2))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(show-paren-match ((((class color) (background light)) (:background "#bfe8df")))))
Одной из замечательных особенностей Emacs является умение форматировать исходные тексты. Причём, не только по команде
для выбранного текста (Вам не нравится стиль в котором написана программа кем-то, когда приходится править чужие
исходники? Не проблема — выделите текст и наберите команду M-x indent-region), но и
непосредственно при его наборе, когда курсор достигает "электрик-символов" происходит форматирование текущей строки. В
стиле отступов используемом по-умолчанию для c++-mode меня всё устраивает кроме отступа для подоператоров (термин из
документации Emacs, означающий строки после операторов if, else, while, do, switch, for, try, catch, finally,
synchronized и т.д.) и case- меток. Установка нужных значений:
;; c-style
(c-set-offset 'substatement-open 0)
(c-set-offset 'case-label 0)
Расширение возможностей редактора.
У Emacs есть собрат - XEmacs, который возник в результате форка первого из-за несогласия некоторых разработчиков GNU
Emacs с его создателем Ричардом Столманом в вопросе дальнейшего направления развития редактора. Главное отличие XEmacs от
Emacs для пользователей заключается в наличии в нём пакетного менеджера позволяющего не заботится о ручной установке
модулей, которые пишутся к редактору и дальнейшем отслеживании их версий. Второе "большое" отличие заключается в наличии
табов в XEmacs, и их отсутствии в Emacs. Впрочем, это нисколько не недостаток, т.к. табы в Emacs всё же имеются. Надо
лишь поставить необходимый модуль. Здесь
лежит исходный текст модуля, позволяющего работать с табами в Emacs. Для того, чтобы его установить, необходимо создать
в директории, в которой Emacs может найти модули, файл с именем tabbar.el и скопировать в него содержимое, доступное по
данной ссылке. Примером подобной директории является site-lisp, которую можно найти в директории с установленным
Emacs. Для активации модуля надо прописать в ~/.emacs:
;; tabs
(require 'tabbar)
(tabbar-mode t)
(global-set-key [(control shift tab)] 'tabbar-forward)
(global-set-key [(control meta shift tab)] 'tabbar-backward)
Табы в Emacs
Последние две строки создают привязку клавиш к командам переключения вкладок. Табы группируются по режимам, которые
установлены в содержащихся в них фреймах. Двойная стрелочка на скриншоте — при клике на неё переключает отображение
табов в выбранном режиме и отображение режимов всех фреймов, которые открыты в редакторе.
tabbar.el не единственный модуль обеспечивающий табы в Emacs. Точнее сказать, существует модуль, облегчающий операции
с файлами и буферами. На этой странице
находится исходный текст модуля ido.el, после создания файла пропишите в файл конфигурации:
;; ido
(require 'ido)
(ido-mode t)
Этот модуль дополнительно к автодополнению, вызываемому нажатием клавиши табуляции, предлагает список выбора при
открытии файла или при переключении на другой буфер, вызываемому при нажатии C-x b. Возможно вы
найдёте этот модуль полезным и станете использовать его так же как я, совместно с tabbar.
Следущее удобное расширение, на которое стоит обратить внимание,
это session.el. Оно позволяет сохранять
историю команд, буфер kill-ring, историю открытия файлов и т.д., а так же, добавляет два полезных пункта меню, где можно
выбрать файлы, которые открывались в последний раз или последние изменённые файлы. Установка:
;; session
(require 'session)
(add-hook 'after-init-hook 'session-initialize)
На этом, пожалуй, завершится обзор доводки Emacs для более удобного использования. Существует масса вещей, которые
можно сделать с этим редактором, от превращения его в просмотрщик картинок, органайзер или средство ведения блогов до
настройки его в качестве мощного nntp и почтового клиента, но, это тема не этой статьи, сейчас же перейдём к созданию из
Emacs среды разработки C++ программ.
C++ IDE.
В этой главе речь пойдёт о вещах специфичных для процесса создания программ, которые облегчат процесс навигации по
исходному коду, по файлам проекта, об интеграции Emacs с окружением для компиляции, дебаггером и навигации по
ошибкам.
Существуют разные способы для того, чтобы включить автодополнение в Emacs. Самый простой из них — использование
etags. Эта утилита устанавливается вместе с Emacs в директорию bin/, если вы захотите её использовать, то необходимо
включить эту директорию в переменную окружения PATH, чтобы Emacs мог найти etags и использовать её для индексации
файлов. Автодополнение привязано к комбинации M-TAB, но т.к. в Windows
сочетание Alt-TAB переключает окна, можно использовать в качестве клавиши "Meta" клавишу "ESC",
либо прописать свою собственную привязку для функции complete-symbol. etags служит не только для автодополнения, но и
для того, чтобы перемещаться на определение функций, для этого надо поместить курсор на нужную функцию и
нажать M-..
Я использую другой способ — пользуюсь функциональностью пакета Semantic, идущего в составе пакета
CEDET. Посколько, последний необходим для дальнейших, описанных ниже шагов, я рекомендую не ставить Semantic отдельно, а
скачать и установить CEDET. Отсюда скачайте последнюю версию (в данный
момент 1.0pre3) CEDET, и разархивируйте содержимое каталога. В файл конфигурации пропишите:
;; Cedet
(setq semantic-load-turn-useful-things-on t)
(load-file "C:/Programme/Emacs/cedet-1.0pre3/common/cedet.el")
(global-set-key [?\C- ] 'semantic-ia-complete-symbol)
Autocompletion в Emacs
откорректировав путь к cedet.el. C-SPC вызовет автодополнение, а
последовательность C-c , SPC всплывающее меню со списком методов для автодополнения.
При программировании бывает довольно удобным скрыть часть / части кода. Например, свернуть тела методов или
комментарии. В Emacs есть режим Outline, который предназначен именно для этого. Кроме того, существуют модули, упрощающие
/ дополняющие использование данной функциональности. Я пользуюсь упрощённым вариантом свёртки, который доступен после
установки модуля hideshow. Следущие строки в
файле конфигурации установят загрузку модуля (после копирования содержимого, доступного по ссылке, в файл hideshow.el) и
установят ловушку для c++-mode, при переходе Emacs в этот режим, автоматически запустится вспомогательный режим
"hideshow":
;; hideshow
(load-library "hideshow")
(add-hook 'c++-mode-hook ; other modes similarly
(lambda () (hs-minor-mode 1)))
Клавиатурные комбинации C-c @ C-h,
C-c @ C-s, C-c @ C-M-h,
C-c @ C-M-s покажут / скроют блок, покажут / скроют все блоки, где блоком является либо
операторный блок кода заключённый в "{ }", либо комментарий. Остальные привязки можно посмотреть открыв исходный код
hideshow.el и прочитав комментарии к коду в начале файла.
Следущая, весьма полезная вещь, которую стоит установить в Emacs, это ECB — Emacs Code Browser. Этот модуль
показывает дерево директорий, список исходных файлов, список классов и методов в текущем файле, историю посещений и
выходное окно компиляции. Для работы модуля требуется наличие установленных дополнительных модулей, но с установкой
CEDET, всё необходимое будет уже установлено. Для установки ECB необходимо скачать
CEDET с этой страницы (на момент написания версия 2.32beta1),
разархивировать модуль и прописать в файл конфигурации:
;; ECB
(add-to-list 'load-path "c:/Programme/Emacs/ecb-2.32/")
(require 'ecb)
(global-set-key (kbd "\e\el") 'ecb-toggle-ecb-windows)
(global-set-key (kbd "\e\eea") 'ecb-activate)
(global-set-key (kbd "\e\eed") 'ecb-deactivate)
скорректировав путь к ECB. Последние три строки создают привязки активизации / деактивизации модуля и переключения
редактирования кода в полноэкранный режим. M M e aвключает ECB, M M e d
выгружает ECB, a M M l переключает режим окна редактирования кода. Надо отметить, что
использование ECB удобно не только при работе с проектом. Дерево директорий настраивается на отображение используемых
директорий, делая открытие файлов весьма неутомительным. Добавьте следущие строки в список custom-set-variables для
подавления стартового "Совета дня" и для задания отображаемых директорий в окне дерева директорий, скорректировав список
необходимых каталогов:
'(ecb-source-path (quote ("~/" "c:/develop")))
'(ecb-tip-of-the-day nil)
Emacs Code Browser
Примерно так выглядит ECB — внешний вид можно изменить удалив или переместив куда угодно любые окна. Для
навигации по окнам используйте комбинации: C-c . g d - дерево директорий,
C-c . g s - окно со списком исходных файлов, C-c . g m - окно со списком
функций и переменных, C-c . g h - история открытия файлов и C-c . g 1 -
окно редактирования кода. Все привязки можно переназначить на более удобные комбинации, если есть в этом
необходимость. Также, можно выбирать файлы с помощью мыши, кнопкой выбора по-умолчанию является средняя кнопка.
После обработки исходных текстов наступает момент компиляции проекта. В Emacs запуск компиляции
вызывается M-x compile. По-умолчанию Emacs вызывает make с ключём -k означающим, что следует
продолжать компиляцию так долго, насколько это возможно, несмотря на ошибки. Это, естественно, можно перенастроить,
внеся в список custom-set-variables значение для переменной compile-command (строковые значения необходимо брать в
кавычки). Выход процесса компиляции отображается в служебном буфере *compilation*, который становится видимым. Если в
процессе компилятор выдал предупреждения или ошибки, то они отображаются в этом буфере, визуально выделяясь цветом. При
клике на сообщении или при нажатии клавиши "Enter", если курсор находится на сообщении, происходит переход на
соответствующую строку в нужном буфере. По-умолчанию комбинации
C-x ` и M-g p осуществляют переход на строки соответствующие следущей /
предыдущей ошибке.
Если программа была собрана с отладочной информацией (make debug), в Emacs можно запустить дебаггер GNU gdb для
пошаговой отладки: M-x gdb. Emacs спросит имя отлаживаемого файла, загрузит из него символьную
таблицу и перейдёт в интерактивный режим ожидания ввода команд пользователя. Если установить точку останова и запустить
дебаггер на выполнение программы, при достижении точки останова Emacs разделит окно на две части и покажет исходный код
программы синхронизируя текущее положение исполнения команд с показом соответствующего места в исходном тексте.