11. СРЕДСТВА РАЗРАБОТКИ ПРОГРАММ

Система UNIX обеспечивает богатый набор средств для раз-

работки программ, включающий компиляторы, линкер, символьный

отладчик, средства ведения программных проектов и разработки

 

 

- 97 -

языковых процессоров, архивные средства и другие.

 

11.1 Вызов компиляторов

В системе UNIX имеются компиляторы с языков C, ФОРТРАН-77

и ПАСКАЛЬ и другие. Команды вызова компилятора имеют вид cc,

f77 или fc, pc и т.п.

Параметрами этих команд являются файлы с текстами прог-

рамм на исходных языках, имена которых должны оканчиваться

на .c, .f, .p и т.п. соответственно.

Примеры:

$ cc program.c

$ fc test.f

$ pc example.p

Результатом работы компилятора является файл исполняемого

кода, имеющий по умолчанию имя a.out. Если вы хотите другое

имя, его можно указать явно ключом -o <имя> при вызове ком-

пилятора.

Пример:

$ fc -o test test.f

$ ls

test

test.f

$

 

 

 

- 98 -

11.2. Линкер

На практике программы создаются из множества раздельно

транслируемых модулей, каждый из которых занимает отдельный

файл. Результатом компиляции каждого модуля является файл

объектного (перемещяемого) кода, имя которого получается за-

меной .c (или .f, .p и т.д.) на .c. Затем все объектные фай-

лы объединяются в единую программу, помещаемую в файл испол-

няемого кода, посредством линкера. Линкер может вызываться

как независимой командой ld, так и автоматически при выпол-

нении команд вызова компилятора cc, fc, pc и т.д. В послед-

нем случае эти команды могут иметь несколько параметров-фай-

лов, имена которых могут оканчиваться не только на .c, .f,

.p, ..., но и на .o. Файлы исходного текста компилируются, а

затем все файлы объектного кода, как полученные в результате

компиляции, так и параметры команды вызова компилятора, пе-

редаются линкеру. Результатом по-прежнему является файл с

именем по умолчанию a.out, если вы не указали явно другое

имя.

При этом, как правило, объектные файлы уничтожаются. Что-

бы сохранить их, можно подавить автоматический вызов линкера

ключом -c (только компиляция) в команде вызова компилятора.

Пример:

$ fc -c test.f check prove.f

$ ld /lib/frt0.o *.o -lF77

 

 

- 99 -

$ ls

a.out

check.f

check.o

prove.f

prove.o

test.f

test.o

$

Здесь добавлены файл /lib/frt0.o стартового модуля для

программы на ФОРТРАНе (для C /lib/crt0.o) и библиотека -

lF77 подпрограмм для ФОРТРАНа (для C - lc); могут быть до-

бавлены и другие библиотеки. Обозначение -lx является сокра-

щением для /lib/libx.a для любого x. Следует заметить, что

библиотеки указываются последними (не являются ключами ко-

манды ld). При автоматическом вызове линкера стартовый мо-

дуль и ряд библиотек вызываются по умолчанию. Чтобы их уви-

деть, следует применить ключ -v в командах вызова компилято-

ра.

 

11.3. Библиотеки

Как мы показали выше, на вход линкера могут подаваться не

только файлы объектного кода, но и библиотечные файлы, кото-

рые оказываются очень удобным средством хранения объектных

модулей, если их становится очень много.

 

 

- 100 -

Имя библиотечного файла обычно оканчивается на .a. Имеет-

ся команда ar (архив) для создания, пополнения и просмотра

библиотечных файлов.

Пример создания библиотеки из трех объектных файлов:

$ ar rcv exam.a test.o check.o prove.o

a - test.o

a - check.o

a - prove.o

$

Здесь ключи команды ar означают:

r - заменить (replace) модули в библиотеке;

c - создать (create) библиотеку;

v - печатать включаемые модули (verbose).

Теперь мы можем распечатать содержимое библиотеки ко-

мандой ar с ключом t (table of content):

$ ar t exam.a

test.o

check.o

prove.o

$

и ссылаться на библиотеку в командах вызова компиляторов

или линкера, например:

$ ld -o test /lib/frt0.o exam.a -lF77

Следует помнить, что порядок размещения модулей в библио-

теке существенен.

Например, если подпрограмма test вызывает подпрограмму

check, то test.o должен предшествовать check.o в библиотеке.

 

 

- 101 -

Для выявления и печати таких зависимостей предназначена ко-

манда lorder.

 

11.4. Символьный отладчик

Как правило, имеется единый символьный отладчик для прог-

рамм на нескольких языках программирования, компиляторы ко-

торых вырабатывают объектный код и таблицы символов в едине-

ом формате. Символьный отладчик обычно имеет альтернативные

имена для разных языков, например, cdb, fdb и pdb для языков

C, ФОРТРАН-77 и PASCAL соответственно. Вызов отладчика про-

изводится одноименной командой, в которой указывается файл

кода отлаживаемой программы, по умолчанию a.out. Для генера-

ции и сохранения отладочной информации (таблиц символов и

т.п.) компиляция программы должна производиться с ключом -g.

Пример:

$ fc -g test.f check.f prove.f

$ fdb

>

Знак > - подсказка отладчика, приглашающая вводить коман-

ды отладчика. Команды отладчика позволяют:

- посмотреть текущие значения переменных выполняемого

оператора, строки исходного текста, процедуры, файла в ука-

занном формате;

- устанавливать и сбрасывать точки прерывания для пошаго-

вого выполнения отлаживаемой программы между точками преры-

вания и/или с постоянным шагом;

 

 

- 102 -

- задавать утверждения, проверяемые перед выполнением

каждого оператора для останова перед теми операторами, для

которых утверждение истинно;

- копировать все сигналы, связанные с отлаживаемой прог-

раммой;

- записывать и повторно использовать команды сеанса от-

ладки (командный файл на входе отладчика).

Более подробную информацию о символьном отладчике можно

найти в руководстве по команде cdb.

 

11.5. Средства оценки эффективности исполнения программы

Имеются средства, позволяющие выяснить, сколько времени и

места требуется для выполнения программы и ее частей. Эти

средства полезны для сравнения качества реализации программы

на разных языках программирования или в разных версиях сис-

темы UNIX.

Команда time позволяет выяснить три значения потраченного

на решение указанной программы времени в секундах: реально-

го, равного времени, замеренному по секундомеру, зависящего

от количества пользователей в данный момент; пользователь-

ского, равного времени счета программы по командам пользова-

теля, и системного, равного времени системы при обслуживании

этой программы. Команда time в Shell и в C-Shell имеет раз-

ные формы выдачи.

 

 

- 103 -

Пример (в Shell):

$ time test

real 30.0

user 27.6

sys 0.5

$

Команда size показывает размер памяти в байтах трех раз-

личных частей программы: выполняемого кода (называемого

текстом), области инициируемых данных и области неинициируе-

мых данных.

Пример:

$ size test

1356 + 260 + 613 = 2226 b = 004265 b

Общий размер программы test равен 4265 байтов.

Если имя оцениваемого файла отсутствует, подразумевается

a.out.

Для программы на языке C есть более тонкое средство, поз-

воляющее получить профиль программы, показывающий для каждой

подпрограммы долю времени ее выполнения в процентах (%

time), суммарное время ее выполнения в секундах (cumsecs),

количество ее вызовов (# call) и время, потраченное на один

вызов в миллисекундах (ms/call). Для получения профиля сле-

дует перетранслировать программу с ключом -p (профиль), а

после запуска программы, во время которого статистическая

информация будет собрана в файле mon.out, выполнить команду

prof для обработки указанного файла.

 

 

- 104 -

Пример:

   $ cc -p program.c
   $ mv a.out program
   $ program
   $ ls
   mon.out
   program
   program.c
   $ prof program
   name   % time   cumsecs   # call   ms/call
   conv   58.6     11.38     2000     5.69
   strcat 30.1      9.50      100     95.0
   main    1.1      2.1         1      2.1
   . . . . . . . . . . . . . . . . . . . . .
   atoi    0.0      0.1         1      0.0

 

11.6. Сопровождение программ: make

Если программный продукт велик, содержит много исходных,

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

модификации может быть облегчена утилитой make, которая поз-

воляет автоматизировать все рутинные операции по перетранс-

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

в них изменений.

Утилита make работает с файлом Makefile, в который запи-

сывается необходимая информация о всех файлах программы и

связях между ними.

 

 

- 105 -

Пример:

   $ cat Makefile
   FILES   = test.f  check.f  prove.f
   OBJECTS = test.o  check.o  prove.o
   test:  $ {OBJECTS}
          ld -o test/lib/frt0.o ${OBJECTS} -lF77
   $

Как видно из примера, в файле Makefile помещаются макро-

определения, имеющие вид:

 

строка1 = строка2

 

и правила, имеющие вид:

 

конечный файл : исходные файлы

команда

 

Первая строка правила называется зависимостью. Зависи-

мость указывает, что конечный файл является результатом ра-

боты команды, указанной во второй строке правила, над исход-

ными файлами. Внутри зависимости можно ссылаться на макрооп-

ределения в форме $(строка1).

Подготовив такой Makefile, можно модифицировать прог-

рамму test одним вызовом команды make, например:

$ make

fc -c test.f

fc -c check.f

fc -c prove.f

ld -o test/lib/frt0.o check.o prove.o -lF77

$

 

 

- 106 -

Команда выполняется только в том случае, если дата созда-

ния или модификации конечного файла меньше, чем соответству-

ющая дата хотя бы одного исходного файла (то есть если ко-

нечный файл устарел).

Возможно изменить только часть программы, например:

$ make prove.o

fc -c prove.f

$

В данном случае утилита make по умолчанию "знает", что

файл prove.o зависит от файла prove.f и реализация этой за-

висимости есть указанный вызов компилятора.

Полезный ключ -n утилиты make позволяет не выполняя пред-

писанных действий предварительно посмотреть, что было бы вы-

полнено, если бы ключ не был подан.

Подробнее о make можно узнать из руководства по команде

make и книг [7,8].

 

11.7. Средства реализации языков программирования

До сих пор речь шла о разработке программ на языках прог-

раммирования, реализованных в системе (т.е. имеющих компиля-

тор и линкер). Если вас, как опытного пользователя, не уст-

раивают эти предопределенные языки и вы хотите реализовать

свой язык, то и в этом вам поможет система UNIX, предостав-

ляя утилиты lex и yacc.

Утилита lex является текстовым процессором, реализующим

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

других языковых процессоров.

Утилита yacc (yet another compiler compiler) конвертирует

безконтекстную грамматику в таблицы, управляющие граммати-

 

 

 

- 107 -

ческим разбором посредством LR(1)-автомата. Формируемые при

этом правила предшествования позволяют избавиться от двус-

мысленностей исходной грамматики.

Совместное использование утилит lex и yacc является мощ-

ным подспорьем для быстрой реализации языковых процессоров в

среде системы UNIX [9,10,11].