С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. - Инструментальные средства разработки ПО в ОС UNIX (1114658), страница 6
Текст из файла (страница 6)
Если приопределении переменной были использованы другие переменные,подстановка их значений происходит при использованиипеременной (опять так же, как и в препроцессоре языка Си).Зависимости между компонентами определяются следующимобразом:<цель> : <цель1> <цель2> ... <цельn>Где <цель> - имя цели, которое может быть либо именем файла,либо некоторым именем, обозначающим действие, которому несоответствует никакой файл, например clean. Список целей в правойчасти задает цели, от которых зависит <цель>.Если описание проекта содержит циклическую зависимость,то есть, например, файл A зависит от файла B, а файл B зависит отфайла A, такое описание проекта является ошибочным.Команды для перекомпиляции цели записываются послеописания зависимости.
Каждая команда должна начинаться ссимвола табуляции (\t). Если ни одной команды для перекомпиляциицели не задано, будут использоваться стандартные правила, еслитаковые имеются. Для определения, каким стандартным правиломнеобходимо воспользоваться, обычно используются суффиксы именфайлов. Если ни одна команда для перекомпиляции цели не задана истандартное правило не найдено, программа make завершается сошибкой.Для программы earth простейший пример файла Makefile длякомпиляции проекта может иметь вид:earth : arthur.o trillian.o prosser.ogcc arthur.o trillian.o prosser.o -o eartharthur.o : arthur.cgcc -c arthur.ctrillian.o : trillian.cgcc -c trillian.cprosser.o : prosser.cgcc -c prosser.c29Однако, в этом описании зависимостей не учтены .h файлы.Например, если файл arthur.h подключается в файлах arthur.c иtrillian.c, то изменение файла arthur.h должно приводить кперекомпиляции как arthur.c, так и trillian.c.
Получается, что .oфайлы зависят не только от .c файлов, но и от .h файлов, которыевключаются данными .c файлами непосредственно или косвенно. Сучетом этого файл Makefile может приобрести следующий вид:earth : arthur.o trillian.o prosser.ogcc arthur.o trillian.o prosser.o -o eartharthur.o : arthur.c arthur.hgcc -c arthur.ctrillian.o : trillian.c trillian.h arthur.hgcc -c trillian.cprosser.o : prosser.c prosser.h arthur.hgcc -c prosser.cПервой в списке зависимостей обычно записывается «главная»зависимость, а затем записываются все остальные файлызависимости.В командной строке программы make можно задать имя цели,которую требуется (при необходимости) перекомпилировать. Так,при запускеmake prosser.oбудет при необходимости перекомпилирован только файл prosser.o ите файлы, от которых он зависит, все прочие файлы затронуты небудут.
Если в командной строке имя цели не указано, берется перваяцель в файле. В нашем случае это будет цель earth.Если придерживаться хорошего стиля написания Makefile, токаждый Makefile должен содержать как минимум два правила: all –основноеправило,котороесоответствуетосновномупредназначению файла, и правило clean, которое предназначено дляудаления всех рабочих файлов, создаваемых в процессе компиляции.В случае программы earth рабочими файлами можно считать самисполняемый файл программы earth, а также все объектные файлы.С учетом этих дополнений файл Makefile примет вид:all : earthearth : arthur.o trillian.o prosser.ogcc arthur.o trillian.o prosser.o -o earth30arthur.o : arthur.c arthur.hgcc -c arthur.ctrillian.o : trillian.c trillian.h arthur.hgcc -c trillian.cprosser.o : prosser.c prosser.h arthur.hgcc -c prosser.cclean :rm -f earth *.oОбратите внимание, что у правила clean отсутствует списокфайлов, от которых этот файл зависит.
Поскольку существованиефайла с именем clean в рабочем каталоге не предполагается, командаrm -f … будет выполняться каждый раз, когда make запускается навыполнение командойmake cleanДанный файл, безусловно, решает задачу автоматизациисборки программы earth. Теперь можно придать этому файлу болееобщий вид, чтобы в этот файл легче было вносить изменения.Во-первых, можно параметризовать название используемогокомпилятора, а также предоставить возможность управлятьпараметрами командной строки компилятора.
Для заданиякомпилятора можно определить переменную CC, для задания опцийкомандной командной строки компиляции объектных файлов —переменную CFLAGS, а для задания опций командной строкикомпоновки выходной программы — переменную LDFLAGS.Получим следующий файл:CC = gccCFLAGS = -Wall -O2LDFLAGS = -sall : earthearth : arthur.o trillian.o prosser.o$(CC) $(LDFLAGS) arthur.o trillian.o prosser.o -o eartharthur.o : arthur.c arthur.h$(CC) $(CFLAGS) -c arthur.ctrillian.o : trillian.c trillian.h arthur.h$(CC) $(CFLAGS) -c trillian.cprosser.o : prosser.c prosser.h arthur.h$(CC) $(CFLAGS) -c prosser.cclean :rm -f earth *.o31Теперь можно изменить используемый компилятор, не толькоотредактировав Makefile, но и из командной строки.
Например,запуск программы make в видеmake CC=iccпозволит для компиляции программы использовать не gcc, а Intelкомпилятор Си. Аналогично запускmake CFLAGS=”-g” LDFLAGS=”-g”позволит включить отладочную информацию в генерируемыеобъектные файлы и исполняемую программу.Во-вторых, можно избавиться от дублирования имен файловсначала в зависимостях, а потом в выполняемых командах. Дляэтого могут быть использованы специальные переменные $^, $< и$@. Переменная $@ раскрывается в имя цели, стоящей в левойчасти правила. Переменная $< раскрывается в имя первойзависимости в правой части правила.
Переменная $^ раскрывается всписок всех зависимостей в правой части. Правило для компиляциифайла arthur.o приобретет следующий вид:arthur.o : arthur.c arthur.h$(CC) $(CFLAGS) -c $<Именно такое правило для компиляции .o файлов из .c файловуже встроено в make, поэтому строку компиляции можно простоудалить. Останется следующий Makefile:CC = gccCFLAGS = -Wall -O2LDFLAGS = -sall : earthearth : arthur.o trillian.o prosser.o$(CC) $(LDFLAGS) $^ -o $@arthur.o : arthur.c arthur.htrillian.o : trillian.c trillian.h arthur.hprosser.o : prosser.c prosser.h arthur.hclean :rm -f earth *.oПри желании можно создавать новые шаблонные зависимости,то есть зависимости не конкретных файлов друг от друга, а файлов,имена которых удовлетворяют заданному шаблону.
Тогда команды взависимостях конкретных файлов также могут быть опущены.32Например, стандартное шаблонное правило для зависимостей .oфайлов от .c файлов может быть определено следующим образом:%.o : %.c:$(CC) -c $(CFLAGS) $<Тем не менее, в этом файле проекта осталось слабое место.Оно связано с тем, что зависимости объектных файлов включают всебя помимо .c файлов и .h файлы, подключаемые .c файламинепосредственно или транзитивно.
Представим себе, что в файлprosser.c была добавлена директива#include “trillian.h”но Makefile не был соответствующим образом изменен. Теперьможет получиться так, что в файле trillian.h будет измененанекоторая структура данных, но файл prosser.o не будетперекомпилирован и код модуля prosser.o будет продолжатьработать со старой версией структуры данных, в то время какостальная программа — с новой версией структуры данных. Такоерасхождение в описании данных в рамках одной программы можетпривести к «загадочным» ошибкам при ее работе.Хотелось бы каким-либо образом строить спискизависимостей объектных файлов от .c и .h файлов автоматически.Для этого мы воспользуемся специальными опциями компилятораgcc и расширенными возможностями GNU make.Предположим, что автогенерируемые зависимости ненаходятся в самом файле Makefile, а подключаются из внешнегофайла deps.make.
Для подключения содержимого внешнего файла вMakefile необходимо добавить директивуinclude deps.makeДля генерации файла deps.makeвоспользуемся опцией -MM компилятора gcc:сзависимостямиdeps.make:arthur.c trillian.c prosser.c arthur.h trillian.h prosser.hgcc -MM arthur.c trillian.c prosser.c > deps.makeФайл deps.make зависит от всех .c и .h файлов, из которыхсобирается программа. Может показаться, что это правило не будетработать, так как в Makefile необходимо включить файл deps.make,для генерации которого необходимо выполнить Makefile, то есть33возникает циклическая зависимость, однако GNU make умееткорректно обрабатывать такие ситуации.Для того, чтобы не выписывать списки .c и .h файловнесколько раз, в начале Makefile можно определить переменные:CFILES = arthur.c trillian.c prosser.cHFILES = arthur.h trillian.h prosser.hБолее того, список объектных файлов можно получать изсписка .c файлов заменой суффикса .c на .o:OBJECTS = $(CFILES:.c=.o)В итоге получили следующий Makefile:CC = gccCFLAGS = -Wall -O2LDFLAGS = -sCFILES = arthur.c trillian.c prosser.cHFILES = arthur.h trillian.h prosser.hOBJECTS = $(CFILES:.c=.o)TARGET = earthall : $(TARGET)earth : $(OBJECTS)$(CC) $(LDFLAGS) $^ -o $@include deps.makedeps.make : $(CFILES) $(HFILES)gcc -MM $(CFILES) > deps.makeclean :rm -f $(TARGET) *.oЭтот файл можно легко модифицировать для сборки другихпроектов с помощью изменения значений переменных CFILES,HFILES и TARGET.Разработка в Code::BlocksИнтегрированная среда разработки (англ., integrateddevelopment environment, IDE) призвана объединить в общемграфическом пользовательском интерфейсе инструменты разработкипрограммного обеспечения: основные – такие как редакторисходных текстов, компилятор, компоновщик, отладчик и, вомногих случаях, вспомогательные – средство автоматизации сборки,34профилировщик, среду для запуска модульных тестов, генератордокументации и др.Code::Blocks (http://www.codeblocks.org) – свободная кроссплатформенная интегрированная среда разработки, написанная наСи++ и поддерживаемая языки Си, Си++ и др.
В состав Code::Blocksвходит редактор исходных текстов с подсветкой синтаксиса ифункцией автозаполнения (англ., autocomplete) – подсказки именфункций и переменных при наборе первых букв имени.Исходные тексты, относящиеся к одной единице компоновки(исполняемый модуль, библиотека), составляют проект (англ.,project) Code::Blocks. По каждому проекту могут заданы параметрытрансляции и компоновки компилятором gcc для отладочной (англ.,Debug) и рабочей (англ., Release) конфигураций. Несколькологически связанных проектов (например, проект-приложение сграфическим пользовательским интерфейсом, проект-библиотека,содержащая бизнес-логику, и используемая приложением) могутбыть объединены в общее рабочее пространство (workspace). Дляпроектов рабочего пространства может быть задан порядок ихсборки.Однимизпопулярныхсценариевиспользованияинтегрированной среды разработки является отладка.
Code::Blocksпредоставляет графический интерфейс к популярным функциямотладчика GDB: пошаговой отладке (включая подключение кработающему процессу), управлению контрольными точками,просмотру переменных, стека вызовов, значений ячеек памяти.Функциональность Code::Blocks может быть расширена засчет установки дополнительных модулей.Профилирование в ValgrindВо многих случаях перед программистом встает проблемапоиска в программе «узких» мест – фрагментов кода, негативновлияющих на производительность программы, а также ошибок,приводящих к нарушению функционирования программы из-занерационального, а порой безконтрольного использования памяти.Конечно же, путем изучения исходных текстов, внесения в35программу кода сбора статистики по числу обращений к функциям,времени их работы, количеству неосвобожденных блоков памятимогут быть обнаружены как некорректные использования и утечкипамяти (англ., memory leak), так и нерациональная реализацияалгоритмов.