- Lektsia - бесплатные рефераты, доклады, курсовые работы, контрольные и дипломы для студентов - https://lektsia.info -

Лабораторная работа № 7. Разработка программ в среде Linux



1. Цель работы

Целью работы является изучение основных этапов разработки и отладки приложений в ОС Linux, а также приобретение практических навыков по использованию инструментальных средств фонда свободного программного обеспечения при компиляции исходного кода, сборке, отладке и тестировании программ, написанных на языке Си.

2. Методические указания

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

ОС Linux имеет полный набор инструментов для разработки приложений, поддерживающий все основные этапы разработки:

· создание исходного кода (текста) программы;

· сохранение различных вариантов исходного текста;

· компиляция исходного кода;

· компоновка программы (сборка);

· отладка программы;

· сохранение всех изменений, выполняемых при тестировании и отладке.

В лабораторной работе будут использованы компилятор gcc и отладчик gdb.

2.1 Компиляция исходного модуля

Компиляция – процесс перевода программы с алгоритмического языка на язык машинных команд, при этом исходный модуль программы преобразуется в объектный модуль. В общем случае обработка исходной программы компилятором выполняется в три этапа: препроцессорная обработка, преобразование результата работы препроцессора в ассемблерный код и преобразование ассемблерного кода в набор машинных команд.

На этапе препроцессорной обработки в исходную программу включается содержимое всех заголовочных файлов, указанных в директивах #include. В заголовочных файлах обычно находятся объявления функций, используемых в исходной программе, но не определённых в ее тексте. Их определения находятся в других файлах с исходным кодом или в бинарных библиотеках. Результатом препроцессорной обработки является объединенный исходный код программы.

На этапе формирования ассемблерного кода проводятся лексический и синтаксический анализ объединенного исходного кода, а также операторов языка программирования высокого уровня в набор ассемблерных команд.

Компилятор также включает в состав объектного модуля служебную информацию, необходимую для компоновки – словарь внешних символов ESD и словарь перемещений RLD.

Компилятор gcc способен по суффиксам файлов определять их типы и действие, которое необходимо с ними выполнить (см. табл. 24).

Таблица 24

Имя файла Содержимое и действие
file.c исходный код на С, который нуждается в препроцессорной обработке
file.cpp исходный код на С++, который нуждается в препроцессорной обработке
file.i исходный код на С, который не нуждается в препроцессорной обработке
file.ii исходный код на С++, который не нуждается в препроцессорной обработке
file.h заголовочный файл С
file.S ассемблерный код, который нуждается в препроцессорной обработке
file.s ассемблерный код
file.o объектный код

Компилятор имеет множество различных опций, используемых для управления процессом компиляции. Для выполнения лабораторной работы потребуются следующие опции:

-g – включить в исполняемый файл дополнительную отладочную информацию, используемую отладчиком gdb;

-c – отключить автоматический вызов компоновщика, при этом на выходе компилятора формируется объектный файл для каждого исходного входного файла;

-S – отключить ассемблирование, на выходе формируется файл с ассемблерным кодом для каждого не ассемблерного входного файла;

-E – остановиться после этапа препроцессорной обработки, на выходе формируется исходный файл с подключенными заголовочными файлами;

-o file – поместить результат в файл с указанным именем (по умолчанию результат записывается в файл a.out);

-Iкаталог – добавить указанный каталог в список каталогов для поиска заголовочных файлов;

-Lкаталог – добавить указанный каталог в список каталогов для поиска библиотек;

При обработке исходной программы компилятор может выводить два типа диагностических сообщений – предупреждение (warning) и ошибка (error). Предупреждение выводится в случае обнаружения ситуации, которая не влияет на корректность работы программы (например, в программе описана переменная, но она нигде не используется). Ошибка является следствием нарушения синтаксиса языка программирования и делает невозможным формирование объектного модуля.

В сообщениях компилятор указывает место обнаружения ошибки в исходном коде. Часто возникает ситуация, когда число сообщений об ошибках превышает число реальных ошибок в программе. Это объясняется тем, что компилятор просматривает всю программу целиком и реальная ошибка в одном операторе может приводить к неправильным синтаксическим конструкциям в нескольких последующих операторах программы, что приводит к генерации «наведенных» сообщений об ошибках.

После успешного формирования объектного модуля компилятор gcc без дополнительных команд со стороны пользователя вызывает компоновщик, который формирует исполняемый (загрузочный) модуль. Если при вызове компилятора была указана опция –c, то компоновщик не вызывается.

Отладочная информация значительно увеличивает размер исполняемого файла, поэтому после отладки рекомендуется её удалить с помощью программы strip. Для того, чтобы полностью очистить файл от отладочной информации, необходимо указать опцию -s: strip -s a.out

Примеры:

gcc -o abcd –g abcd.c – компиляция программы abcd.cи формирование исполняемого модуля abcdс включением в него отладочной информации;

gcc -c abcd.c – компиляция программы abcd.cи формирование объектного модуля abcd.o;

gcc -E abcd.c – препроцессорная обработка программы abcd.cи формирование результата на стандартный вывод.

2.3 Утилита make

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

В общем случае makefile является списком правил. Каждое правило начинается с указателя, называемого целью, после которого стоит двоеточие, а далее через пробел указываются зависимости – имена файлов, от которых зависит достижение цели. После зависимостей идут команды Linux, каждая из которых должна находиться на отдельной строке и начинаться с символа табуляции. Структура правила может быть сложной и включать ветвления, циклы и другие конструкции языка shell. Строки, которые начинаются с символа «#», являются комментариями.

Например, make-файл для программы, хранящейся в файле abcd.c, может иметь вид:

# Makefile for abcd.c

# Compile abcd.c normaly

abcd: abcd.c

gcc -o abcd abcd.c

# Compile abcd.c with debugging

testabcd: abcd.c

gcc -o testabcd -g abcd.c

# End Makefile

Этот файл включает два правила компиляции и построения исполняемого модуля: первое предусматривает обычную компиляцию с построением исполняемого модуля с именем abcd, второе позволяет включить в исполняемый модуль testabcd информацию для отладки на уровне исходного текста.

В качестве имени правила может быть указана любая символьная строка, но рекомендуется использовать имена файлов или действие. Например, для сборки программы, состоящей из трех модулей, фрагмент make-файла может выглядеть следующим образом:

iResult: main.o func1.o func2.o gcc -o iResult main.o func1.o func2.o Здесь целью является файл iResult (исполняемый файл программы), а правило описывает, как можно получить новую версию файла этого файла (скомпоновать из перечисленных объектных файлов).

Make-файл должен находиться в одном каталоге со всеми файлами программы, запуск утилиты make проводится следующим образом: make имя_правила, например, make abcd.Если не указывать какой-либо цели в командной строке, то make выбирает по умолчанию первое правило make-файла.

2.4 Отладка и тестирование

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

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

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

Запуск отладчика gdb проводится командой gdb testabcd, при этом на экран будет выведена информация об отладчике и появится приглашение для ввода команд отладчика, основными из которых являются:

backtrace – выводит весь путь к текущей точке останова, то есть названия всех функций, начиная с main();

break параметр– устанавливает точку останова, параметром может быть номер строки или название функции;

continue – продолжает выполнение программы от текущей точки до конца;

display– добавляет выражение в список выражений, значения которых отображаются каждый раз при остановке программы;

finish – выполняет программу до выхода из текущей функции; отображает возвращаемое значение, если такое имеется;

help[команда]информация о команде или общая информация об использовании отладчика gdb;

list – пролистывает 10 строк вниз, начиная с текущей;

next – пошаговое выполнение программы, но, в отличие от команды step, не выполняет пошагово вызываемые функции;

print выражение– выводит значение какого-либо выражения;

run – запускает программу на выполнение;

step – пошаговое выполнение программы;

quit – выход из отладчика.

2.6 Тестовый пример для лабораторной работы

При выполнении лабораторной работы будет использоваться программа abcd.c, исходный текст которой приведен ниже. Эта программа представляет собой простейший лексический анализатор, который читает входной текст из стандартного ввода (клавиатуры) и результаты выводит на стандартный вывод (монитор).

Для каждой строки, принятой со стандартного ввода, программа выводит слова по одному в строку. Словом является последовательность алфавитно-цифровых символов, заключенная между пробелами. Если в качестве аргумента задан некоторый символ (например -t), то на стандартный вывод из вводимой строки выводятся только слова, которые включают данный символ.

Приведенный ниже текст программыabcd.c содержит несколько синтаксических и семантических ошибок. Предполагается, что при выполнении лабораторной работы студенты должны найти и исправить эти ошибки и тем самым приобрести практические навыки по использованию таких инструментальных средств как gcc, make, gdb.

Тестовый входной набор данных будет представлен строкой:

this is a test the abcd program

При запуске отлаженной программы abcd без параметров после ввода этой строки на экране должно быть:

this

is

a

test

the

abcd

program

При запуске отлаженной программы abcd с параметром -t после ввода этой строки на экране должно быть:

this

test

the

Исходный текст программы abcd.c

#include <stdio.h>

#include <ctype.h>

#include <string.h>

/* Manifests for state machine to parse input line. */

#define WORD 0

#define IGNORE 1

/* Globals, used by both subroutines. */

char *Words[BUFSIZ/2]; /* Worst case, single letters. */

int WordCount;

 

/* Walk through the array of works, find those with the matching charaсter, printing them on * stdout. Note that the NULL charaсter will match all words. */

void PrintWords(wc, match)

int wc; /* Number of words in Words[] */

char match; /* Attempt to match this charakter. */

{ register int ix; /* Index in Words[]. */

register char *cp; /* Pointer for searching. */

for (ix=0; ix < wc; ix++) {

cp = Words[ix];

/* Try to match the given character. Scan the word, attempting to match,

* or until the end of the word is found. */

while ((*cp) && (*cp++ != match));

if (*cp == match) /* Found a match? Write the word on stdout. */

(void) printf("%s0, Words[ix]); } return; }

 

/* Find words in the gives buffer. The Words[] array is set

* to point at words in the buffer, and the buffer modifeid

* with NULL characters to delimit the words. */

int GetWords (buf)

char buf[]; /* The input buffer. */

{ register char *cp; /* Pointer for scanning. */

int end = strlen(buf); /* length of the buffer. */

register int wc = 0; /* Number of words found. */

int state = IGNORE; /* Current state. */

/* For each character in the buffer. */

for (cp = &buf[0]; cp < &buf[end]; cp++) {

/* A simple state machine to process

* the current character in the buffer. */

switch(state) {

case IGNORE:

if (!isspace(*cp)) {

Words[wc++] = cp; /* Just started a word? Save it. */

state = WORD; /* Reset the state. */ } break;

case WORD:

if (isspace(*cp)) {

*cp = '\0'; /* Just completed aword? terminate it. */

state = IGNORE; /* Reset the state. */ } break; }}

return wc; /* Return the word count. */ }

 

int main(argc, argv) int argc; char *argv[]; { char buf[BUFSIZ], match;

/* Check command line arguments. */

if (argc < 2) match = ' ';

/* No command line argument, match all words. */

else match = *++argv[1]; /* match the char after the first - */

/* Until no more input on stdin. */

while(gets(buf) != (char *)NULL) {

WordCount = GetWords(buf); /* Paste the input buffer. */

PrintWords(WordCount, match); /* Print the matching words. */ }

return(0); /* Return success to the shell. *

3. Порядок выполнения работы

1. Запустите файловый менеджер mc .

2. В домашнем каталоге создайте подкаталог examples.

3. Выполните поиск во внешней памяти файла testcase.c

4. Скопируйте файл testcase.c в ваш подкаталог examplesпод именем abcd.c.

5. Выполните компиляцию программы abcd.c.Исправьте синтаксические ошибки с помощью редактора vi, всю информацию по ошибкам и их устранению занесите в отчет.

6. С помощью редактора vi создайте в поддиректории examples make-файл согласно п. 2.3. Далее различные варианты построения исполняемого модуля должны быть получены с помощью программы make.

7. Выполните отладку программы abcd.cс помощью отладчика gdb. Занесите в отчет результаты выполнения программы до и после устранения каждой ошибки, а также суть исправлений (например, номер строки программы abcd.c и причина исправления)..

8. После получения корректных результатов выполнения программы abcd с помощью редактора vi в начало отлаженной программы введите комментарий: "Программа abcd отлажена с помощью отладчика gdb дд.мм.гг. бригадой группы ПМ-ХХ в составе: ФИО1, ФИО2..."

4. Контрольные вопросы

1. Как получить более полную информацию о программах gcc, make, gdb ?

2. Назовите и дайте краткую характеристику основным этапам разработки приложений в ОС Linux?

3. Что такое суффиксы и префиксы? Основное их назначение. Приведите примеры их использования.

7. Назначение компилятора, основные этапы компиляции.

8. Назначение программы make, структура make-файла.

10. Назовите основное свойство, присущее всем программам отладки. Что необходимо сделать, чтобы его можно было использовать?

11. Основные команды отладчика gdb.

12. Опишите по шагам схему отладки программы abcd.c, которую Вы использовали при выполнении лабораторной работы.

13. Прокомментируйте реакцию компилятора на синтаксические ошибки в программе abcd.c при его первом запуске.

14. Дайте характеристику программе abcd.c и объясните сущность семантических ошибок, которые были выявлены вами при выполнении лабораторной работы.