Текст книги "Основы программирования в Linux"
Автор книги: Нейл Мэтью
Соавторы: Ричард Стоунс
Жанры:
Программирование
,сообщить о нарушении
Текущая страница: 3 (всего у книги 67 страниц)
Linux-приложения представлены файлами двух типов: исполняемыми (executable) и сценариями или пакетными файлами (script). Исполняемые файлы – это программы, которые могут непосредственно выполняться на компьютере; они соответствуют файлам ОС Windows с расширением exe. Сценарии или пакетные файлы – это наборы команд для выполнения другой программой, интерпретатором. Они соответствуют в ОС Windows файлам с расширением bat или cmd или интерпретируемым программам на языке Basic.
ОС Linux не требует, чтобы исполняемые или пакетные файлы имели определенные имена или какие-либо расширения. Для обозначения файла как способной выполняться программы применяются атрибуты файловой системы, которые будут обсуждаться в главе 2. В ОС Linux вы можете заменять пакетные файлы откомпилированными программами (и наоборот), не оказывая влияния на другие программы или пользователей, которые обращаются к ним. На уровне пользователя, по сути, между ними нет разницы.
В процессе регистрации в системе Linux вы взаимодействуете с программой командной оболочки (часто bash), которая запускает программы так же, как это делает оболочка командной строки в ОС Windows. Она находит запрашиваемые вами программы по имени, выполняя поиск файла с тем же именем в заданном наборе каталогов. Каталоги, предназначенные для поиска, хранятся в переменной оболочки PATH
, так же как в ОС Windows. Путь поиска (который вы можете пополнять) настраивается вашим системным администратором и обычно содержит стандартные каталоги, в которых сохраняются системные программы. К ним относятся:
□ /bin – бинарные файлы (binaries), программы, применяемые для загрузки системы;
□ /usr/bin – пользовательские библиотеки, стандартные программы, доступные пользователям;
□ /usr/local/bin – локальные библиотеки, программы, относящиеся к этапу инициализации.
Если войти в систему как администратор, например с именем root
, можно использовать переменную PATH
, которая включает каталоги с хранящимися системными программами, такие как /sbin и /usr/sbin.
Необязательные компоненты операционной системы и приложения сторонних производителей могут устанавливаться в подкаталоги /opt, а добавить инсталляционные программы в вашу переменную PATH
можно через пользовательские инсталляционные сценарии.
Примечание
Не стоит удалять каталоги из переменной
PATH
, пока нет полной уверенности в результате, который будет получен.
Обратите внимание на то, что в ОС Linux, как и UNIX, для разделения отдельных элементов в переменной PATH
применяется символ двоеточия (:) в отличие от символа точки с запятой, используемого в ОС MS-DOS и Windows. (ОС UNIX сделала выбор первой, поэтому спрашивайте, почему отличается Windows, а не почему в UNIX все не так!) Далее приведен пример переменной PATH
:
/usr/local/bin:/bin:/usr/bin:.:/home/neil/bin:/usr/X11R6/bin
В этой переменной PATH
содержатся каталоги для хранения стандартных программ, текущий каталог (.), исходный каталог пользователя и каталог графической оболочки X Window System.
Запомните, в ОС Linux используется прямой слэш (/) для отделения имен каталогов в полном имени файла в отличие от обратного слэша (), применяемого в ОС Windows. И снова ОС UNIX выбирала первой.
Текстовые редакторыДля ввода и набора примеров программного кода, приведенных в книге, вам понадобится текстовый редактор. В типовых системах Linux есть большой выбор таких программ. У многих пользователей популярен редактор vi.
Оба автора предпочитают Emacs, поэтому мы предлагаем потратить немного времени на знакомство с основными функциями этого мощного редактора. Почти во все дистрибутивы ОС Linux Emacs включен как необязательный пакет, который можно установить. Кроме того, вы можете получить его на Web-сайте GNU по адресу http://www.gnu.org или же взять версию для графических сред разработки на Web-сайте XEmacs по адресу http://www.xemacs.org.
Для того чтобы узнать больше о редакторе Emacs, можно воспользоваться его интерактивным средством обучения. Начните с выполнения команды emacs
, затем нажмите комбинацию клавиш t
для доступа к этому средству. У редактора Emacs есть также полное руководство. Для получения дополнительной информации о нем в редакторе Emacs нажмите комбинацию клавиш i
. В некоторых версиях Emacs может быть меню, предоставляющее доступ к средству обучения и полному руководству.
В системах, соответствующих стандарту POSIX, компилятор языка С называется с89. Раньше компилятор языка С назывался просто сс. Шли годы, разные поставщики продавали UNIX-подобные системы с компиляторами С, обладающими разными функциями и параметрами, но очень часто все также названными сс.
Когда создавался стандарт POSIX, выяснилось, что невозможно определить стандартную команду cc
, которая была бы совместима со всеми этими разработками.
Вместо этого комитет решил создать новую стандартную команду для компилятора языка С – с89
. Если эта команда представлена, она всегда использует одни и те же опции независимо от машины.
В системах Linux, которые на деле пытаются следовать стандартам, можно обнаружить, что все или некоторые из команд с89
, cc
и gcc
ссылаются на системный компилятор языка С, обычно компилятор GNU С или gcc. В системах UNIX компилятор языка С почти всегда называется cc.
В этой книге мы используем gcc, поскольку он поставляется в дистрибутивах Linux и потому что он поддерживает для языка С синтаксис стандарта ANSI. Если когда-нибудь вы обнаружите, что в вашей системе нет gcc, мы советуем получить его и установить. Найти его вы можете по адресу http://www.gnu.org. Всюду, где мы используем в книге команду gcc
, просто заменяйте ее подходящей командой вашей системы.
Упражнение 1.1. Ваша первая Linux-программа на языке C
В этом примере вы начнете разработку в ОС Linux с помощью языка С, написав, откомпилировав и выполнив свою первую Linux-программу. Ею, кстати, может стать самая известная из всех программ для начинающих – программа, выводящая сообщение «Hello World» («Привет, мир»).
1. Далее приводится текст файла hello.c:
#include
#include
int main() {
printf(«Hello Worldn»);
exit(0);
}
2. Теперь откомпилируйте, скомпонуйте и выполните вашу программу.
$ gcc -о hello.c $ ./hello
Hello World
Как это работает
Вы запустили компилятор GNU С (в Linux, вероятнее всего, он будет доступен и как cc
), который оттранслировал исходный код на языке С в исполняемый файл, названный hello. Вы выполнили программу, и она вывела на экран приветствие. Это наипростейший из существующих примеров, но если вы смогли с помощью вашей системы добраться до этого места, то сможете откомпилировать и выполнить и остальные примеры из книги. Если же программа не сработала, убедитесь в том, что в вашей системе установлен компилятор языка С. Например, во многих дистрибутивах Linux есть установочная опция, названная Software Development (Разработка ПО) (или что-то похожее), которую следует выбрать для установки необходимых пакетов.
Поскольку это первая выполненная вами программа, самое время обратить внимание на некоторые основные положения. Программа hello, вероятно, должна быть в вашем исходном каталоге. Если в переменную PATH
не включена ссылка на ваш исходный каталог, оболочка не сможет найти программу hello. Более того, если один из каталогов в переменной PATH
содержит другую программу, названную hello, вместо вашей будет выполнена эта программа. То же самое произойдет, если такой каталог упомянут в переменной path раньше вашего исходного каталога. Для решения этой потенциальной проблемы можно снабдить имена программ префиксом ./
(например, ./hello
). Данный префикс сообщает оболочке о необходимости выполнить программу с заданным именем, находящуюся в текущем каталоге. (Точка – это условное название текущего каталога.)
Если вы забыли опцию -o name
, которая указывает компилятору, куда поместить исполняемый файл, компилятор поместит его в файл с именем a.out (что означает ассемблерный вывод). Не забудьте поискать файл с именем a.out, если вы уверены, что скомпилировали программу, а найти ее не можете! Когда ОС UNIX только появилась, пользователи, хотевшие играть в ней в игры, часто запускали их как файл с именем a.out, чтобы не быть пойманными системным администратором, и некоторые установки ОС UNIX традиционно удаляют каждый вечер все файлы с именем a.out.
Разработчику ОС Linux важно знать кое-что о том, где размещаются средства и ресурсы разработки. В следующих разделах дан краткий обзор некоторых важных каталогов и файлов.
Приложения
Приложения обычно хранятся в отведенных для них каталогах. Приложения, предоставляемые системой для общего использования, включая средства разработки программ, находятся в каталоге /usr/bin. Приложения, добавленные системными администраторами для конкретного хост-компьютера или локальной сети, часто хранятся в каталоге /usr/local/bin или /opt.
Администраторы предпочитают /opt и /usr/local, потому что они хранят предоставляемые конкретными поставщиками файлы и свежие дополнения отдельно от приложений, предоставляемых системой. Подобная организация хранения файлов может помочь, когда придет время обновлять операционную систему, т.к. в этом случае потребуется сберечь только каталоги /opt и /usr/local. Мы рекомендуем компилировать в ветви иерархии /usr/local только системные приложения общего назначения, предназначенные для запуска и доступа к требуемым файлам. Для разрабатываемых программ и личных приложений лучше всего применять папку в вашем исходном каталоге.
Дополнительные средства и системы программирования могут иметь собственные структуры каталогов и каталоги программ. Важнейшая среди них – графическая оболочка X Window System, которая обычно устанавливается в каталог /usr/X11 или каталог /usr/bin/X11. В дистрибутивах Linux, как правило, применяется версия X.Org Foundation графической оболочки X Window System, базирующаяся на модификации Revision 7 (X11R7). В других UNIX-подобных системах могут быть выбраны иные версии X Window System, устанавливаемые в другие каталоги, например, каталог /usr/openwin для оболочки Open Windows компании Sun в системе Solaris.
Программа системного драйвера компилятора GNU, gcc (которую вы использовали в предыдущем упражнении) обычно помещается в каталог usr/bin или usr/local/bin, но она будет запускать различные поддерживающие компиляцию приложения из других каталогов. Эти каталоги задаются во время компиляции самого компилятора и зависят от типа хост-компьютера. В системах Linux это может быть зависящий от конкретной версии подкаталог /usr/lib/gcc/. На одной из машин одного из авторов во время написания книги это был подкаталог /usr/lib/gcc/i586-suse-linux/4.1.3. В нем хранятся отдельные проходы компилятора GNU C/C++ и специфические заголовочные файлы GNU.
Заголовочные файлы
В процессе программирования на языке С и других языках вам потребуются заголовочные файлы или файлы заголовков для включения определений констант и объявлений вызовов системных и библиотечных функций. В случае языка С эти файлы почти всегда находятся в каталоге /usr/include и его подкаталогах. Заголовочные файлы, зависящие от конкретного воплощения запущенной вами ОС Linux, вы, как правило, найдете в каталогах /usr/include/sys и /usr/include/linux.
У других систем программирования тоже есть заголовочные файлы, хранящиеся в каталогах, которые автоматически находятся соответствующим компилятором. Примерами могут служить каталоги /usr/include/X11 для графической оболочки X Window System и /usr/include/c++ для языка GNU С++.
Вы можете использовать заголовочные файлы из подкаталогов или нестандартных мест хранения, указав флаг -I (для include) в строке вызова компилятора языка С. Например, команда
$ gcc -I/usr/openwin/include fred.c
заставит искать заголовочные файлы, использованные в программе fred.c, в стандартных каталогах и в каталоге /usr/openwin/include. Для получения дополнительных сведений обратитесь к руководству компилятора С (man gcc
).
Искать заголовочные файлы с конкретными определениями и прототипами конкретных функций часто удобно с помощью команды grep. Предположим, вам нужно знать имя из директив #define
, используемое для возврата из программы статуса завершения. Просто замените каталог на /usr/include и примените grep для поиска предполагаемой части имени следующим образом:
$ grep EXIT_ *.h
...
stdlib.h#define EXIT_FAILURE 1 /*Failing exit status. */
stdlib.h#define EXIT_SUCCESS 0 /*Successful exit status. */
...
$
В этом случае команда grep ищет в каталоге все файлы с именами, заканчивающимися на .h, со строкой EXIT_. В данном примере она нашла (среди прочих) нужное вам определение в файле stdlib.h.
Библиотечные файлы
Библиотеки – это наборы заранее откомпилированных функций, написанных в расчете на многократное использование. Обычно они состоят из наборов связанных функций, предназначенных для решения общей задачи. Примерами могут служить библиотеки функций работы с экраном (библиотеки curses и ncurses) и процедуры доступа к базе данных (библиотека dbm). В последующих главах мы познакомим вас с некоторыми библиотеками.
Стандартные системные библиотеки обычно хранятся в каталогах /lib и /usr/lib. Компилятору языка С (или, точнее, компоновщику) необходимо сообщить, в каких библиотеках искать, поскольку по умолчанию он ищет только в стандартной библиотеке С. Это пережиток, пришедший к нам из того времени, когда компьютеры были медленными и циклы ЦПУ были дороги. Недостаточно поместить библиотеку в стандартный каталог и ждать, что компилятор найдет ее; библиотеки должны следовать очень специфическим правилам именования и быть упомянуты в командной строке.
Имя файла библиотеки всегда начинается с символов lib. Далее следует часть, указывающая на назначение библиотеки (например, с для библиотеки С или m для математической библиотеки). Последняя часть имени начинается с точки (.) и задает тип библиотеки:
□ а – для традиционных статических библиотек;
□ .so – для совместно используемых библиотек (см. далее).
Обычно библиотеки существуют в статическом и совместно используемом форматах, как покажет быстрый просмотр каталога командой ls /usr/lib. Вы можете заставить компилятор искать библиотеку, задав полное имя ее файла или применив флаг -l. Например, команда
$ gcc -о fred fred.c /usr/lib/libm.a
сообщает компилятору о необходимости компилировать файл fred.c и искать разрешения ссылок на функции в библиотеке математических функций в дополнение к стандартной библиотеке С. Аналогичного результата можно добиться с помощью следующей команды:
$ gcc -о fred fred.c -lm
-lm
(без пробела между символами l
и m
) – это сокращенное обозначение (сокращенные формы очень ценятся в UNIX-кругах) библиотеки с именем libm.a, хранящейся в одном из стандартных библиотечных каталогов (в данном случае /usr/lib). Дополнительное преимущество обозначения -lm в том, что компилятор автоматически выберет совместно используемую библиотеку, если она существует.
Несмотря на то что библиотеки, как и заголовочные файлы, обычно хранятся в стандартных каталогах, вы можете добавить каталоги для поиска, указав флаг -L (заглавная буква) в команде вызова компилятора. Например, команда
$ gcc -о x11fred -L/usr/openwin/lib x11fred.c -lX11
будет компилировать и компоновать программу x11fred, используя версию библиотеки libX11, найденную в каталоге /usr/openwin/lib.
Статические библиотеки
Простейшая форма библиотеки – это коллекция объектных файлов, хранящихся вместе в виде, готовом к использованию. Когда программе нужна функция, содержащаяся в библиотеке, в нее включают заголовочный файл, объявляющий эту функцию. За соединение программного кода и библиотеки в единый исполняемый файл отвечают компилятор и компоновщик. Вы только должны применить опцию -l
для указания нужных библиотек, отличных от стандартной библиотеки С исполняющей системы.
Статические библиотеки, также называемые архивами, в соответствии с принятыми соглашениями имеют окончание .а. Например, lib/libc.а и /usr/lib/libX11 для библиотек С и X11 соответственно.
Вы можете очень легко создавать и поддерживать собственные статические библиотеки с помощью программы ar (для создания архивов) и отдельно компилировать функции с помощью команды gcc -с
. Старайтесь, насколько это возможно, хранить функции в отдельных исходных файлах. Если функциям нужен доступ к общим данным, вы можете поместить данные в один исходный файл и использовать статические переменные, объявленные в этом файле.
Упражнение 1.2. Статические библиотеки
В этом упражнении вы создадите свою маленькую библиотеку, содержащую две функции, и затем используете одну из функций в примере программы. Функции называются fred и bill и просто выводят приветствия.
1. Сначала создайте отдельные исходные файлы (как не удивительно, названные fred.c и bill.c) для каждой функции.
Далее приведен первый из них:
#include
void fred(int arg) {
printf(«fred: you passed %dn», arg);
}
А это второй:
#include
void bill(char *arg) {
printf(«bill: you passed %sn», arg);
}
2. Вы можете отдельно откомпилировать эти функции и создать объектные файлы, готовые к включению в библиотеку. Для этого запустите компилятор С с опцией -с
, которая помешает компилятору создать законченную программу. Попытка создать законченную программу окажется безуспешной, т.к. вы не определили функцию с именем main.
$ gcc -с bill.с fred.c
$ ls *.o
bill.о fred.о
3. Теперь напишите программу, вызывающую функцию bill
. Прежде всего, хорошо бы создать заголовочный файл для вашей библиотеки. В нем будут объявлены функции из вашей библиотеки, и он будет включаться во все приложения, которые захотят применить вашу библиотеку. В файлы fred.c и bill.c тоже хорошо бы включить заголовочный файл, чтобы помочь компилятору обнаружить любые ошибки.
/*
Это файл lib.h. В кем объявлены пользовательские функции fred and bill
*/[1]1
Здесь и далее для удобства читателей комментарии переведены на русский язык. Возможность ввода знаков кириллицы зависит от выбранного дистрибутива Linux и текстового редактора. – Пер.
[Закрыть]
void bill(char *);
void fred(int);
4. Вызывающая программа (program.с) может быть очень простой. Она включает заголовочный файл и вызов из библиотеки одной из функций.
#include
#include «lib.h»
int main() {
bill(«Hello World»);
exit(0);
}
5. Теперь можно откомпилировать и протестировать программу. Для этого задайте компилятору явно объектные файлы и попросите его откомпилировать ваш файл и связать его с ранее откомпилированным объектным модулем bill.o.
$ gcc -с program.с
$ gcc -о program program.о bill.о
$ ./program
bill: we passed Hello World
$
6. Для создания архива и включения в него ваших объектных файлов используйте программу ar. Программа называется ar, поскольку она создает архивы или коллекции отдельных файлов, помещая их все в один большой файл. Имейте в виду, что программу ar можно применять для создания архивов из файлов любого типа. (Как многие утилиты UNIX, ar – универсальное средство.)
$ ar crv libfоо.a bill.о fred.о
а – bill.о а – fred.о
7. Библиотека создана, и в нее добавлены два объектных файла. Для того чтобы успешно применять библиотеку в некоторых системах, в особенности в производных от Berkeley UNIX, требуется создать для библиотеки индекс содержимого архива или список вложенных в библиотеку функций и переменных (table of contents). Сделайте это с помощью команды ranlib
. В ОС Linux при использовании программных средств разработки GNU этот шаг не является необходимым (но и не приносит вреда).
$ ranlib libfoo.a
Теперь ваша библиотека готова к использованию. Вы можете добавить следующий список файлов, которые должен обработать компилятор для создания вашей программы:
$ gcc -о program program.о libfоо.а
$ ./program
bill: we passed Hello world
Можно было бы применить для доступа к библиотеке флаг -l
, но т.к. она хранится не в одном из стандартных каталогов, вы должны сообщить компилятору место поиска с помощью флага -L
следующим образом:
$ gcc -о program .program.о -L. -lfoo
Опция -L
заставляет компилятор искать библиотеки в текущем каталоге (.). Опция -lfoo
сообщает компилятору, что нужно использовать библиотеку с именем libfoo.a (или совместно используемую библиотеку libfoo.so, если она есть). Для того чтобы посмотреть, какие функции включены в объектный файл, библиотеку или исполняемую программу, можно применить команду nm
. Если вы взглянете на файлы program и libfoo.a, то увидите, что библиотека содержит обе функции: fred
и bill
, а файл program – только функцию bill
. Когда создается программа, в нее включаются из библиотеки только те функции, которые ей действительно нужны. Вставка заголовочного файла, содержащего объявления всех функций библиотеки, не вызывает включения в конечную программу целиком всей библиотеки.
Если вы знакомы с разработкой программ в ОС Windows, то поймете, что в ОС UNIX существует ряд прямых аналогий, перечисленных в табл. 1.1.
Таблица 1.1
Объектный модуль | func.o | FUNC.OBJ |
Статическая библиотека | lib.a | LIB.LIB |
Программа | program | PROGRAM.EXE |
Совместно используемые библиотеки
У статических библиотек один недостаток – когда вы запускаете много приложений одновременно и все они используют функции из одной библиотеки, в результате образуется множество копий одних и тех же функций в памяти и множество реальных копий функций в самих файлах программ. Это может привести к потреблению большого объема полезной памяти и дискового пространства.
Устранить этот недостаток могут многие системы UNIX и Linux с поддержкой совместно используемых или разделяемых библиотек. Подробное обсуждение совместно используемых библиотек и их реализации в разных ОС не входило в нашу задачу, поэтому ограничимся только реализацией их в ОС Linux.
Совместно используемые библиотеки хранятся в тех же каталогах, что и статические, но у имен файлов совместно используемых библиотек другой суффикс. В типовой системе Linux имя совместно используемой версии стандартной библиотеки математических функций – /lib/libm.so.
Когда программа применяет совместно используемую библиотеку, она компонуется таким образом, что содержит не код функции как таковой, а ссылки на совместно используемый код, который станет доступен на этапе выполнения. Когда окончательная программа загружается в память для выполнения, ссылки на функции разрешаются, и выполняются вызовы совместно используемой библиотеки, которая будет загружаться в память по мере необходимости.
В этом случае система предоставляет возможность многим приложениям одновременно использовать единственную копию совместно используемой библиотеки и хранить ее на диске в единственном экземпляре. Дополнительным преимуществом служит возможность обновления совместно используемой библиотеки независимо от базирующихся на ней приложений. Применяются символические ссылки из файла /lib/libm.so на текущую версию библиотеки (/lib/libm.so.N, где N – основной номер версии – 6 во время написания книги). Когда ОС Linux запускает приложение, она учитывает номер версии библиотеки, требующийся приложению, чтобы не дать ведущим новым версиям библиотеки испортить более старые приложения.
Примечание
Вывод в следующем примере получен из дистрибутива SUSE 10.3. Если вы применяете другой дистрибутив, ваш вывод может слегка отличаться.
В системах Linux программа (динамический загрузчик), отвечающая за загрузку совместно используемых библиотек и разрешение ссылок на функции в клиентских программах, называется ld.so и может присутствовать в системе как ld-linux.so.2, или li-lsb.so.2, или li-lsb.so.3. Дополнительные каталоги поиска совместно используемых библиотек настраиваются в файле /etc/ld.so.conf, который после внесения изменений (например, если добавляются совместно используемые библиотеки X11 при установке графической оболочки X Window System) следует обработать командой ldconfig
.
Запустив утилиту ldd
, вы можете увидеть, какие совместно используемые библиотеки требуются программе. Например, если вы попытаетесь выполнить утилиту для приложения из нашего примера, то получите следующие строки:
$ ldd program
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/libc.so.6 (0xb7db4000)
/lib/ld-linux.so.2 (0xb7efc000)
В этом случае вы видите стандартную библиотеку С (libc) как совместно используемую (.so). Программе требуется основная версия 6. В других системах UNIX принимаются аналогичные меры для получения доступа к совместно используемым библиотекам. Подробную информацию можно найти в системной документации.
Во многом совместно используемые библиотеки аналогичны динамически подключаемым библиотекам в ОС Windows. Библиотеки с расширением .so соответствуют файлам с расширением dll и требуются во время выполнения, а библиотеки с расширением .а аналогичны файлам с расширением lib, которые включаются в исполняемые программы.