С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. Инструментальные средства разработки ПО в ОС UNIX, страница 6
Описание файла
PDF-файл из архива "С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. Инструментальные средства разработки ПО в ОС UNIX", который расположен в категории "". Всё это находится в предмете "операционные системы" из 3 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 6 страницы из PDF
Правило для компиляциифайла 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), так и нерациональная реализацияалгоритмов.
Однако более эффективным способом поиска «узких»мест является применение профилировщиков (англ. profiler) –программных средств, собирающих значения статистическиххарактеристик работы программы.ВданномметодическомпособиирассматриваютсяпопулярныймногоцелевойпрофилировщикValgrind(http://valgrind.org) и следующее подмножество инструментов,входящие в его состав:••••отладчик памяти memcheck;профилировщик кучи massif;профилировщик кэш-памяти и точек ветвления cachegrind;профилировщик вызовов функций callgrind.Принцип работы Valgrind заключается в преобразованиискомпилированной программы в промежуточное представление,динамически транслируемое во время работы инструмента вмашинные команды с одновременным подсчетом необходимойстатистики.
Архитектура Valgrind допускает написание новыхинструментов сторонними разработчиками.Формат командной строки:valgrind [опции] программа-и-ее-аргументыОпция Valgrind--tool=<memcheck|massif|cachegrind|callgrind|…>memcheck][поумолчанию:позволяет выбрать инструментMemcheck Memcheck – исторически первый инструмент Valgrind отладчик памяти, позволяет отслеживать следующие дефектыпрограммы:36• утечка памяти – не освобождение памяти, выделенной в куче(ситуация, при которой для блока памяти, выделенногофункцией malloc/new, отсутствует вызов free/delete);• обращение к памяти после ее освобождения;• выход за границы выделенной памяти;• использование неинициализированной памяти.В программе:#include <stdlib.h>int main(){char * p = malloc(10);p[10] = 1; // Ошибка – обращение к памяти «за»// выделенным блокомreturn 0;}memcheck, запущенный с помощью командной строкиvalgrind --leak-check=full ./a.outобнаружит выход за границы памяти и утечку (выделено жирным):==1671== Memcheck, a memory error detector==1671== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward etal.==1671== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyrightinfo==1671== Command: ./a.out==1671====1671== Invalid write of size 1==1671==at 0x8048446: main (memcheck1.c:6)==1671== Address 0x17803a is 0 bytes after a block of size 10alloc'd==1671==at 0x59278: malloc (in/usr/local/lib/valgrind/vgpreload_memcheck-x86-freebsd.so)==1671==by 0x804843C: main (memcheck1.c:5)==1671====1671====1671== HEAP SUMMARY:==1671==in use at exit: 10 bytes in 1 blocks==1671==total heap usage: 1 allocs, 0 frees, 10 bytes allocated==1671====1671== 10 bytes in 1 blocks are definitely lost in loss record 1 of133==1671==at 0x59278: malloc (in/usr/local/lib/valgrind/vgpreload_memcheck-x86-freebsd.so)==1671==by 0x804843C: main (memcheck1.c:5)37==1671====1671== LEAK SUMMARY:==1671==definitely lost: 10 bytes in 1 blocks==1671==indirectly lost: 0 bytes in 0 blocks==1671==possibly lost: 0 bytes in 0 blocks==1671==still reachable: 0 bytes in 0 blocks==1671==suppressed: 0 bytes in 0 blocks==1671====1671== For counts of detected and suppressed errors, rerun with: -v==1671== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from0)Для получения информации о строке, содержащей проблему,программа должна быть скомпилирована с отладочной информацией(опция gcc -g ).В начале каждой строки выводится номер процесса.Одной из опций memcheck является leak-check:--leak-check=<no|summary|yes|full> [по умолчанию: summary]Опция задает степень детализации отображения информации поутечкам памяти.
No – отсутствие контроля утечек. Full - полнаяинформация по утечкам с указанием конкретных проблемных мест вкоде. Summary и yes – промежуточные режимы.Massif Massif - профилировщик кучи (англ., heap) и стека (англ.,stack). Собирает статистику по использованию памяти в куче и стекечерез фиксированные промежутки времени.Для следующего примера программы:#include <stdlib.h>void f(){malloc(4000);malloc(4000);}int main(){int i;char * p[10];for(i = 0; i < 10; i++)38{p[i] = malloc(1000);}f();for(i = 0; i < 10; i++){free(p[i]);}return 0;}профилировщик, запущенный командной строкойvalgrind --tool=massif --time-unit=B ./a.outсформирует файл с именем massif.out.<PID процесса>, содержащийстатистику использования памяти.Для визуализации отчета можно использовать утилиту ms_print.Командаms_print massif.out.<PID процесса>приведет к выводу на экран графика использования памяти в куче:KB17.75^##|#|# :::|# : ::|# : : :::|::::::::::# : : : :::|:# : : : : ::|:# : : : : : :::|:# : : : : : : ::|::::::::::::# : : : : : : : :::|@@::# : : : : : : : :|@ ::# : : : : : : : : ::|:::@ ::# : : : : : : : : : @|::: @ ::# : : : : : : : : : @|:::: : @ ::# : : : : : : : : : @|:::: : : @ ::# : : : : : : : : : @|::: : : : @ ::# : : : : : : : : : @|:::: : : : : @ ::# : : : : : : : : : @|::: : : : : : @ ::# : : : : : : : : : @| :::: : : : : : : @ ::# : : : : : : : : : @0 +----------------------------------------------------------------------->KB027.67В режиме –time-unit=B сбор статистики производится черезфиксированное число выделенных / освобожденных байт (в режимепо умолчанию, предполагающем замеры расходования памяти через39фиксированные интервалы времени, график может получиться нечитаемым из-за продолжительных временных интервалов, в которыевыделение / освобождение памяти не производилось).