ТОП 10:

Компиляция одного исходного файла



Компилятором языка С является gcc. Для получения объектного файла в процессе компиляции используют опцию -c. Вот как, например, в режиме командной строки компилируется файл main.c:

%gcc -c main.c.

Полученный объектный файл будет назван main.o.

Компилятором языка C++ является g++. Он работает почти так же, как и gcc. Следующая команда предназначена для компиляции файла reciprocal.cpp:

%g++ -c reciprocal.cpp.

Опция -c говорит компилятору о необходимости получить на выходе объектный файл (он будет называться reciprocal.o). Без нее компилятор g++ попытается скомпоновать программу и создать исполняемый файл a.out.

В процессе написания любой более-менее крупной программы обычно задействуется ряд дополнительных опций. К примеру, опция -I сообщает компилятору о том, где искать файлы заголовков. По умолчанию компиляторы GCC просматривают текущий каталог, а также каталоги, где установлены файлы стандартных библиотек. Предположим, наш проект состоит из двух каталогов: src и include. Следующая команда дает компилятору g++ указание дополнительно искать файл reciprocal.hpp в каталоге ../include:

%g++ -c -I ../include reciprocal.cpp

Компоновка объектных файлов

После того как файлы main.c и reciprocal.cpp скомпилированы, необходимо их скомпоновать. Программы написанные на С/С++ обычно содержат ссылки на функции, определенные где-либо вне самой программы, например, в стандартных библиотеках или в личных библиотеках групп программистов, работающих над данным проектом. Объектный код, созданный компилятором, обычно содержит «дыры» из-за этих отсутствующих частей. Компоновщик связывает объектный код с кодами отсутствующих функций, чтобы создать исполняемый загрузочный модуль (без пропущенных частей).

Если в проект входит хотя бы один файл C++, компоновка всегда осуществляется с помощью компилятора g++. Если же все файлы написаны на языке C, нужно использовать компилятор gcc. В нашем случае имеются файлы обоих типов, поэтому требуемая команда выглядит так:

%g++ -o reciprocal main.o reciprocal.o

Опция -o задает имя файла, создаваемого в процессе компоновки.

Следующий этап называется загрузкой. Перед выполнением программа должна быть размещена в памяти. Это осуществляется с помощью загрузчика, который копирует исполняемый загрузочный модуль с диска в оперативную память машины.

Запуск программы reciprocal осуществляют следующим образом:

%./reciprocal 7

The reciprocal of 7 is 0.142857

Как видите, компилятор g++ автоматически подключил к проекту стандартную библиотеку языка C, содержащую реализацию функции printf().

Автоматизация процесса с помощью GNU-утилиты make

Те, кто программируют в Windows, привыкли работать в той или иной интегрированной среде разработки. Программист добавляет в нее исходные файлы, а среда автоматически создает проект. Аналогичные среды доступны и в Unix системах, но с ними мы будем работать позже. GNU-утилита make позволяет автоматически перекомпилировать программу.

Основная идея утилиты make проста. Ей указываются целевые модули, участвующие в процессе построения исполняемого файла, и правила, по которым протекает этот процесс. Также задаются зависимости, определяющие, когда конкретный целевой модуль должен быть перестроен.

В нашем тестовом проекте reciprocal три очевидных целевых модуля: reciprocal.o, main.o и сама программа reciprocal. Правила нам уже известны: это рассмотренные выше командные строки. А вот над зависимостями нужно немного подумать. Ясно, что файл reciprocal зависит от файлов reciprocal.o и main.o, поскольку нельзя скомпоновать программу, не создав оба объектных файла. Последние должны перестраиваться при изменении соответствующих исходных файлов. Нельзя также забывать о файле reciprocal.hpp: он включается в оба исходных файла, поэтому его изменение тоже затрагивает объектные файлы.

Помимо очевидных целевых модулей должен также существовать модуль clean. Он предназначен для удаления всех сгенерированных объектных файлов и программ, чтобы можно было начать все сначала. Правило для данного модуля включает команду rm, удаляющую перечисленные файлы.

Чтобы передать всю эту информацию утилите make, необходимо создать файл Makefile (touch Makefile). Его содержимое будет таким:

reciprocal: main.o reciprocal.o

g++ $(CFLAGS) -o reciprocal main.o reciprocal.o

main.o: main.с reciprocal.hpp

gcc $(CFLAGS) -c main.c

reciprocal.o: reciprocal.cpp reciprocal.hpp

g++ $(CFLAGS) -c reciprocal.cpp

clean:

rm -f *.o reciprocal

Целевые модули перечислены слева. За именем модуля следует двоеточие и существующие зависимости. В следующей строке указано правило, по которому создается модуль (назначение записи $(CFLAGS) мы пока проигнорируем). Строка правила должна начинаться с символа табуляции, иначе утилита make проинтерпретирует ее неправильно.

Если удалить созданные нами выше объектные файлы и ввести

%make

будет получен следующий результат:

%make

gcc -c main.c

g++ -c reciprocal.cpp

g++ -o reciprocal main.o reciprocal.o

Утилита make автоматически создала объектные файлы и скомпоновала их. Попробуйте теперь внести какое-нибудь простейшее изменение в файл main.с и снова запустить утилиту. Вот что произойдет:

%make

gcc -c main.c

g++ -o reciprocal main.o reciprocal.o

Как видите, утилита make повторно создала файл main.o и перекомпоновала программу, но не стала перекомпилировать файл reciprocal. cpp, так как в этом не было необходимости.

Запись $(CFLAGS) обозначает переменную утилиты make. Ее можно определить либо в файле Makefile, либо в командной строке. Утилита подставит на место переменной реальное значение во время выполнения правила. Вот как, например, можно осуществить перекомпиляцию с включенной оптимизацией:

%make clean

rm -f *.o reciprocal

%make CFLAGS=-02

gcc -02 -c main.c

g++ -02 -c reciprocal.cpp

g++ -02 -o reciprocal main.o reciprocal.o

Обратите внимание на то, что вместо записи $(CFLAGS) в правилах появился флаг -02.

В этом разделе мы рассмотрели лишь самые основные возможности утилиты make. Чтобы получить о ней более подробную информацию, обратитесь к интерактивной документации, введя такую команду:

%info make

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

GNU-отладчик gdb

Отладчик – это программа, с помощью которой можно узнать, почему написанная вами программа ведет себя не так, как было задумано. Работать с отладчиком приходится очень часто. Большинство Unix-программистов имеет дело с GNU-отладчиком (GNU Debugger, GDB), который позволяет пошагово выполнять программу, создавать точки останова и проверять значения локальных переменных.

Компиляция с включением отладочной информации

Чтобы можно было воспользоваться GNU-отладчиком, необходимо скомпилировать программу с включением в нее отладочной информации. Этой цели служит опция -g компилятора. Если имеется описанный выше файл Makefile, достаточно задать переменную CFLAGS равной -g при запуске утилиты make:

%make CFLAGS=-g

gсс -g -c main.c

g++ -g -c reciprocal.cpp

g++ -g -o reciprocal main.o reciprocal.o

Встречая в командной строке флаг -g, компилятор включает дополнительную информацию в объектные и исполняемые файлы. Благодаря этой информации отладчик узнает, какие адреса соответствуют тем или иным строкам в том или ином исходном файле, как отобразить значение локальной переменной, и т.д.

Запуск отладчика

Отладчик gdb запускается следующим образом:

%gdb reciprocal

После запуска появится строка приглашения такого вида:

(gdb)

В первую очередь необходимо запустить программу под отладчиком. Для этого введите команду run и требуемые аргументы. Попробуем вызвать программу без аргументов:

(gdb) run

Starting program: reciprocal

Program received signal SIGSEGV, Segmentation fault.

__strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0)

at strtol.c:287

287 strtol.c: No such file or directory.

(gdb)

Проблема заключается в том, что в функции main() не предусмотрены средства контроля ошибок. Программа ожидает наличия аргумента, а в данном случае его нет. Получение сигнала SIGSEGV означает крах программы. Отладчик определяет, что причина краха находится в функции __strtol_internal(). Эта функция является частью стандартной библиотеки, но ее исходный файл отсутствует. Вот почему появляется сообщение "No such file or directory". С помощью команды where можно просмотреть содержимое стека:

(gdb) where

#0 __strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0)

at strtol.c:287

#1 0x40096fb6 in atoi (nptr=0x0) at ../stdlib/stdlib.h:251

#2 0x804863e in main (argc=l, argv=0xbffff5e4) at main.c:8

Как нетрудно заметить, функция main() вызвала функцию atoi(), передав ей нулевой указатель, что и стало причиной ошибки.

С помощью команды up можно подняться по стеку на два уровня, дойдя до функции main():

(gdb) up 2

#2 0х804863е in main (argc=l, argv=0xbffff5e4) at main.c:8

8 i = atoi (argv[l]);

Заметьте, что отладчик нашел исходный файл main.с и отобразил строку, где располагается ошибочный вызов функции. Узнать значение нужной локальной переменной позволяет команда print:

(gdb) print argv[l]

$2 = 0x0

Это подтверждает нашу догадку о том, что причина ошибки - передача функции atoi() указателя NULL.

Установка контрольной точки осуществляется посредством команды break:

(gdb) break main

Breakpoint 1 at 0x804862e: file main.c, line 8.

В данном случае контрольная точка размещена в первой строке функции main(). Давайте теперь заново запустим программу, передав ей один аргумент:

(gdb) run 7

Starting program: reciprocal 7

Breakpoint 1, main (argc=2, argv=0xbffff5e4) at main.c:8

8 i = atoi (argv[l]);

Как видите, отладчик остановился на контрольной точке. Перейти на следующую строку можно с помощью команды next:

(gdb) next

9 printf ("The reciprocal of %d is %g\n", i,

reciprocal(i));

Если требуется узнать, что происходит внутри функции reciprocal(), воспользуйтесь командой step:

(gdb) step

reciprocal (i=7) at reciprocal.cpp:6

6 assert (i != 0);

Иногда удобнее запускать отладчик gdb непосредственно из редактора Emacs, а не из командной строки. Для этого следует ввести в редакторе команду M-x gdb. Когда отладчик останавливается в контрольной точке, редактор Emacs автоматически открывает соответствующий исходный файл. Не правда ли, проще разобраться в происходящем, глядя на весь файл, а не на одну его строку?

Работа с qmake

Ни один программист в настоящее время уже не желает каждый раз задавать для компиляции своей программы параметры для компоновки и передавать пути к библиотекам "вручную". Гораздо удобнее создать make-файл (Makefile), который возьмет на себя всю работу по настройке компилятора и компоновщика.

Создание make-файлов вручную требует от их создателя опыта и понимания протекающих процессов компоновки приложения. Раньше техника создания подобных файлов являлась неотъемлемой частью программирования, но теперь многое изменилось. И дело совсем не в том, что структура make-файлов стала проще, скорее наоборот - она стала сложнее. Просто появились специальные утилиты - генераторы, которые выполнят эту работу за вас.

Полноценный инструментарий для программирования (контейнеры, протоколы ввода-вывода, протоколы сети, XML, 2D и 3D графика, связка с OpenGL) в среде Unix/Linux предоставляет Qt designer.

Предыдущие версии Qt содержали утилиту tmake, которая позволяла довольно просто создавать make-файлы. Она изначально была реализована на языке Perl, и это накладывало на нее дополнительные ограничения - для использования необходимо было наличие интерпретатора языка Perl на компьютере, что, в свою очередь, снижало способность переносимости данной утилиты. По этой причине и была создана новая утилита qmake, которая вошла в поставку Qt начиная с версии 3.0. Примечательно, что новая утилита так же хорошо переносима, как и сам Qt. Утилита qmake полностью освобождает программиста от использования tmake, перенимая все ее возможности. Благодаря этому старые конфигурационные файлы для tmake могут интерпретироваться ей без проблем. Таким образом, тем, кто уже успел привыкнуть к tmake, вовсе не обязательно изучать новый синтаксис.

Программа qmake интерпретирует файлы проектов, которые имеют расширение .pro и содержат различные параметры. Этот файл создается командой

%qmake -project

Создать из .pro файла make-файл совсем не трудно, для этого нужно просто дать команду

%qmake -o Makefile file.pro

В qmake существует возможность создания файлов с расширением dsp (Developer Studio Project), которые могут быть загружены в Visual Studio. Это можно сделать при помощи команды:

%qmake -o file.dsp -t vcapp file.pro

Опция -t является так называемой шаблонной опцией и заставляет qmake использовать параметр vcapp, невзирая на то, что написано в самом файле проекта. Шаблоны нужны для определения типа проекта. Например, при создании make-файла для приложения нужно задать в файле проекта опцию template = app, а при создании библиотеки template должен быть равен lib. Значения vcapp и vclib имеют смысл только для работы в OC Windows.

Допускается передавать опции в командной строке qmake:

%qmake -o Makefile "TEMPLATE=vcapp" file.pro

Табл. 2 содержит некоторые опции файла проекта. Полный список опций можно получить в официальной документации Qt, поставляемой вместе с самой библиотекой.

Опция Назначение
HEADERS Передается список созданных заголовочных файлов
SOURCES Передается список созданных файлов реализации (с расширением срр)
FORMS Передается список файлов с расширением .ui. Эти файлы создаются программой QtDesigner и содержат описание интерфейса пользователя в формате XML.
LEXISOURCES Lex - это программа для синтаксического анализа. Используется для написания компиляторов.
YACCSOURCES Yacc (Yet another Compiler Compiler) - утилита создания компиляторов
TARGET Передается имя приложения. Если данное поле не заполнено, то название программы будет соответствовать имени проектного файла
CONFIG Задает опции, которые должен использовать компилятор
DESTDIR Задает путь, куда будет помещен готовый исполняемый модуль
DEFINES Здесь можно передать опции для компилятора. Например, это может быть опция помещения отладочной информации для debuger в исполняемый модуль
INCLUDEPATH Путь к каталогу,где содержатся заголовочные файлы. Этой опцией можно воспользоваться в случае, если уже есть готовые заголовочные файлы и вы хотите использовать их в текущем проекте
DEPENDPATH В данном разделе указываются зависимости, необходимые для компиляции
DEF_FILE Файл определения модуля, указывает, является ли файл DLL библиотекой или EXE файлом. Используется только для OC Windows.
RCFILE Файл ресурсов в OC Windows. Содержит растровые изображения, меню, диалоговые окна и др. Используется только для OC Windows.
RESFILE Откомпилированный файл ресурсов (присоединяется к исполняемому коду программы). Используется только для OC Windows.

Проектный файл Qt может выглядеть следующим образом:

TEMPLATE = арр

HEADERS += filel.h \

file2.h

SOURCES += main.cpp \

filel.cpp \

file2.cpp

TARGET = file

CONFIG += qt warn_on release

В первой строке задается тип программы, в данном случае это приложение (template = app). Во второй строке, в опции headers, перечисляются все заголовочные файлы, принадлежащие проекту. В опции sources перечисляются все файлы реализации проекта. Опция target определяет имя программы. config определяет опции, которые должен использовать компилятор в соответствии с подсоединяемыми библиотеками. Например, в нашем случае Qt указывает, что это Qt-приложение и используется библиотека Qt, warn_on означает, что компилятор должен выдавать как можно больше предупреждающих сообщений, release указывает, что приложение должно быть откомпилировано в окончательном варианте, без отладочной информации.

Как видно из вышеприведенного примера, программе qmake не требуется много информации, т. к. она опирается на файл локальной конфигурации, который определен системной. Такой конфигурационный файл очень важен еще потому, что один и тот же вызов qmake приведет к созданию разных make-файлов, в зависимости от того, на какой платформе он был вызван. Это один из очень важных шагов в сторону платформо независимости самих проектных файлов.

Далее создаем исполняемый файл

%make







Последнее изменение этой страницы: 2016-08-14; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.235.29.190 (0.013 с.)