После того, как наш проект сгенерирован, первое, что необходимо сделать, - просмотреть структуру кода, чтобы получить общее понимание того, как работает приложение. Это не только поможет нам начать разработку, а и в дальнейшем мы будем ориентироваться, где необходимо вносить изменения.
Когда мы откроем страничку LFV (Logical File Viewer) в левой части окна KDevelop, мы увидим несколько папок, в которых уже размещены файлы проекта в соответствии с их назначением. Первые две папки - "Headers" и "Sources". Папка заголовков логически содержит все файлы заголовков проекта, папка "Sources" - все исходники. Остальные папки сейчас для нас не интересны, их назначение мы рассмотрим позднее.
Две папки содержат следующие файлы:
Headers:
kscribble.h : содержит объявление класса KScribbleApp.
kscribbledoc.h : содержит объявление класса KScribbleDoc.
kscribbleview.h : содержит объявление класса KScribbleView.
resource.h : содержит коллекцию макросов идентификаторов пунктов меню.
Sources:
kscribble.cpp : содержит реализацию класса KScribbleApp.
kscribbledoc.cpp : содержит реализацию класса KScribbleDoc.
kscribbleview.cpp : содержит реализацию класса KScribbleView.
main.cpp : содержит реализацию функции main().
Перед тем, как углубиться в исходный код, позволим KDevelop откомпилировать и запустить наше новое приложение. Чтобы сделать это, выберем "Make" из меню "Build". или нажмем соответствующую кнопку на панели инструментов. В нижней части KDevelop откроется окно вывода, и мы увидим сообщения, выдаваемые make при работе. Они могут несколько отличаться от приводимых ниже, в зависимости от используемых настроек.
1 Making all in docs 2 make[1]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs' 3 Making all in en 4 make[2]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs/en' 5 make[2]: Nothing to be done for `all'. 6 make[2]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs/en' 7 make[2]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs' 8 make[2]: Nothing to be done for `all-am'. 9 make[2]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs' 10 make[1]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble/docs' 11 make[1]: Entering directory `/home/rnolden/Tutorial/kscribble1/kscribble' 12 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribbleview.cpp 13 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribbledoc.cpp 14 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribble.cpp 15 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c main.cpp 16 /usr/bin/moc ./kscribble.h -o kscribble.moc.cpp 17 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribble.moc.cpp 18 /usr/bin/moc ./kscribbledoc.h -o kscribbledoc.moc.cpp 19 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribbledoc.moc.cpp 20 /usr/bin/moc ./kscribbleview.h -o kscribbleview.moc.cpp 21 g++ -DHAVE_CONFIG_H -I. -I. -I.. -I/opt/kde/include -I/usr/lib/qt/include -I/usr/X11R6/include -O0 -g -Wall -c kscribbleview.moc.cpp 22 /bin/sh ../libtool --silent --mode=link g++ -O0 -g -Wall -o kscribble -L/opt/kde/lib -L/usr/X11R6/lib -rpath /opt/kde/lib -rpath /usr/X11R6/lib kscribbleview.o kscribbledoc.o kscribble.o main.o kscribble.moc.o kscribbledoc.moc.o kscribbleview.moc.o -lkfile -lkfm -lkdeui -lkdecore -lqt -lXext -lX11 23 make[1]: Leaving directory `/home/rnolden/Tutorial/kscribble1/kscribble' |
Мы проставили номера строк напротив каждой строки, которых нет в выводе KDevelop. Это сделано для облегчения дальнейшего обсуждения того, что происходит при компиляции. Во-первых, make работает рекурсивно. Это значит, что она начинает с каталога, откуда была вызвана, и затем в первую очередь заходит в подкаталог, возвращается и заходит в следующий подкаталог. Наконец, обрабатывается стартовый каталог и make завершается. make вызывается из главного каталога проекта, содержащего исходники. В строках 1 и 2 мы видим, как make входит в каталог docs, затем в подкаталог en. Так как там нечего делать, она выходит из этих каталогов, пока не вернется в каталог исходников kscribble в строке 11. Теперь начинается настоящая работа: make вызывает компилятор, g++, для компиляции файла-исходника kscribbleview.cpp. Макрос -DHAVE&_;CONFIG&_;H говорит о том, что должен быть использован файл config.h. Этот файл содержит макросы для определения платформы и приложения, и расположен в корневом каталоге проекта. Следующие -I команды добавляют пути для поиска файлов, указанных в команде "&#;include". Это текущий каталог, корневой каталог проекта (-I..), и пути к файлам KDE, Qt и заголовкам библиотек X11. Эти пути определяются при выполнении скрипта configure и устанавливаются в файлах Makefile; таким образом, компилятор знает, где файлы расположены. Наконец, -O0 устанавливает оптимизацию в ноль (без оптимизации), -g разрешает отладку, -Wall устанавливает предупреждения компилятора в значение all, и -c говорит компилятору, что необходимо генерировать только файлы obj, то есть надо только откомпилировать файлы.
Это делается и для других файлов-исходников нашего проекта в строках 13-15. Очевидно, наш исходный код откомпилирован, но вместо того, чтобы линковать объектные файлы исходников в конечный бинарный файл, мы видим несколько иные команды. В строке 16 программа "moc" вызывается для обработки файла-заголовка kscribble.h, выводя результат в kscribble.moc.cpp. Затем, в строке 17, этот исходный файл компилируется. Аналогичные операции проделываются с другими файлами заголовков проекта до строки 21. Это необходимо, поскольку Qt поддерживает механизм сигнал/слот, но базируется на C++ реализации, и мы используем определенные ключевые слова, не поддерживаемые языком C++, такие как signals: и slots:, в наших классах. Это дает нам возможность легко организовать межобъектное взаимодействие для всех экземпляров классов, порожденных от QObject, и избежать использования традиционного механизма callback указателей на функции. Таким образом, приложению необходим исходный код, который обеспечивает данную функциональность, и вот для чего вызывается moc. Moc - Meta Object Compiler набора инструментов Qt . Он реализует механизм сигнал/слот, обрабатывая файл заголовка и генерируя код, который должен быть откомпилирован для получения бинарного файла. Поскольку проекты KDevelop используют automoc для определения того, какие файлы заголовков должны быть обработаны, мы не должны следить за вызовами moc и C++ компилятора для обработки сгенерированных moc файлов. Только запомните правило, что для использования механизма сигнал/слот класс должен быть порожден от QObject, или от любого другого класса, порожденного от QObject; кроме того, этот класс должен содержать макрос Q&_;OBJECT (без ";"!) в начале своего объявления, и объявления сигналов и слотов.
Наконец, генерируется бинарный файл. Выходной бинарный файл называется kscribble, линкер использует пути к библиотекам KDE и X11, и линкует исходники с библиотеками kfile, kfm, kdeui, kdecore, qt, Xext и X11. На этом make завершает свою работу.