18. Среда программирования в Unix (типично), ее компоненты.

В “обычных”IDE есть бинарник-интегратор, который вызывает в лучшем случае внешние утилиты, а в худшем случае свою реализацию каждой функцию из DLL или прямо зашитую в бинарник. В UNIX таким бинарником-интегратором является shell (Emacs считается shell’ом в данном случае). Для выполнения каждой функции вызываются специально написанные динамически выполняемые модули, такие как make, cc, ld, и т. д. Преимущество в этом такое же, как преимущество математических функций высшего порядка перед “обычными”функциями. Hапример, функция “отслеживать зависимости”чаще всего реализуется с помощью make, но можно также легко использовать, 57 58 ГЛАВА 8. СРЕДА ПРОГРАММИРОВАНИЯ UNIX скажем, cook, или же переключаться между GNU Make и BSD Make по вкусу. Точно такая ситуация с используемыми редактором, компилятором, etc. Более того, сам по себе shell является “функцией высшего порядка и легко может быть заменен. Кроме того, так как пространство функций практически неограниченно, то IDE “Unix”обеспечивает также заранее не предусмотренные функции высшего порядка, например, различную автогенерацию кода, поддержку тестирования и т. п. Другими словами, командная строка Unix (shell) и является IDE для Unix. Подобный подход позволяет не зацикливаться на програмных решениях одного производителя (разработчика). Любой компонент, воспринимаемый как часть IDE (компилятор, отладчик, компоновщик, редактор, ассемблер, утилиты сборки и тестирования проекта, система контроля версий) может быть заменен на другой. Эти компоненты мы условно можем назвать Инструментальные средства Unix. 8.3 Низкоуровневый доступ к системе Базой UNIX-системы является компилятор Си (сс), библиотека libc и ядро. Все версии UNIX предоставляют строго определенный, ограниченный набор входов в ядро ОС, через которые прикладные задачи получают доступ к базовым услугам UNIX. Эти точки входа называются системными вызовами (system calls). Системный вызов определяет функцию, выполняемую ядром ОС от имени процесса, выполнившего вызов. Syscall является интерфейсом самого низкого уровня взаимодействия прикладных процессов с ядром. Язык системного программирования - Си. Характерная особенность Unix

<цель 1> <цель 2> ?<цель n="">:<зависимость 1> <завис-ть 2>?<завис-ть n=""> <команда 1> <команда 2> ?

<команда n=""> Цель (target) - некий желаемый результат, способ достижения которого описан в правиле. Цель может быть именем файла. Примечание. Перед командами вставляется табуляция, чтобы make отличал их от целей. Пример1: цель как имя файла iEdit: main.o Editor.o gcc main.o Editor.o -o iEdit Пример описывает, как можно получить исполняемый файл из объектных модулей. Цель может быть именем некоторого действия, тогда правило описывает, как совершается указанное действие. Пример2: цель как имя действия clean: rm *.o iEdit 9.2. MAKE 63 Такие цели называют абстрактными (phony targets) или псевдоцелями (pseudo targets). Зависимость (dependency) - это 'исходные данные', необходимые для достижения указанной в правиле цели. Это предварительные условия достижения цели. Зависимостью может быть имя файла или имя действия. В примере1 main.o и Editor.o - зависимости. Файлы должны существовать, чтобы можно было собрать iEdit. Пример3: clean_all: clean_obj rm iEdit clean_obj: rm *.o Для достижения сlean_all необходимо выполнить действие clean_obj. Команда - действия, которые надо выполнить для обновления или достижения цели. Перед командой должен быть символ табуляции (код 9). Так make определяет команды. Типичный makele, который содержит несколько правил, у каждого правила есть некоторая цель и зависимости. Пример4: 1. iEdit: main.o Editor.o 2. gcc main.o Editor.o -o iEdit 3. main.o: main.cpp 4. gcc -c main.cpp 5. Editor.o: Editor.cpp 6. gcc - Editor.cpp 7. clean: 8. rm *.c Смысл работы - достижение главной цели (default goal). Если цель - имя действия (абстрактная), то выполняется действие. Если главная цель - имя файла, то make строит самую свежую версию. Главная цель обычно задается как параметр make: make iEdit, make clean. Если make вызывается без параметров, то в качестве главной берется первая встреченная цель. (В примере это iEdit). Обычно задают цель all как цель по умолчанию. Алгоритм работы: 1. выбор главной цели 2. достижение цели 3. обработка правил 4. обработка зависимостей Достижение цели - проверяет зависимости и потом определяет, надо ли запускать команды. При вызове make iEdit определяет, что главная цель 64 ГЛАВА 9. ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА РАЗРАБОТЧИКА - iEdit. Правило ее достижения - строки 1,2. Обрабатывая правило iEdit, определяем, что зависит от main.o и Editor.o. Для этих зависимостей существуют правила (3,4) и (5,6). main.o зависит от main.cpp. Если нет еще объектного файла, но существует файл .срр, то запускается компиляция. Аналогично и для Editor.o. Для clean зависимостей нет и make сразу переходит к выполнению. Инкрементная сборка - перекомпилируется только то, что было изменено. Для файлов .с и .срр обычно указываются как зависимости .h файлы. 9.2.3 Переменные make. Присвоение: имя = строка (можно с пробелами). Получение значения переменной: $(имя). Значение - текстовая строка, может содержать ссылки на другие переменные. Пример: obj_list = main.o Editor.o # присвоение; $(obj_list) # получение значения 1)dir_list = . .. src/include all: echo $(dir_list) 2)optimize_flags = -03 compile_flags = $(optimize_flags) -pipe all: echo $(compile_flags) Результат: -03 -pipe 3)program_name = iEdit obj_list = main.o Editor.o TextLine.o $(program_name) : $(obj_list) gcc $(obj_list) -o $(program_name) Примечание. Значение переменной вычисляется в момент использования. Часто используемые переменные: 1. CC - указать компилятор по умолчанию. 2. CFLAGS - параметры компиляции 3. LDFLAGS - параметры линковки объектных файлов Автоматические переменные • $^ - список зависимостей, разделјнных пробелами 9.3. СИСТЕМЫ УПРАВЛЕНИЯ ВЕРСИЯМИ. CVS 65 • $@ - имя цели (файла). Если у нас несколько целей (см 9.2.4), эта переменная принимает значение той цели, для которой выполняется шаблон в конкетный запуск • $< - имя первой зависимости Пример: $(program_name):$(obj_name) gcc $^ -o $@ 9.2.4 Шаблонные правила Шаблонные правила (implicit или pattern rules) применяются к группе файлов. Синтаксис: .<расширение_файлов_завис.> .<расширение_файлов_целей>: <команда 1> <команда 2> ? <команда n=""> Пример: .cpp .o: gcc -c $^ 9.3 Системы управления версиями. CVS Очень часто над программой работает больше одного человека. Выходят различные версии программ. И существует потребность как то упорядочивать внесение изменений и дополнений. Для этого служат системы управления версиями. Из используемых сейчас можно назвать CVS, RCS, Monotone, Arch, BitKeeper и SourceSafe. CVS - Conhurent Versions Systems (система управления конкурирующими версиями). 9.3.1 Репозиторий Репозиторий CVS (или хранилище) хранит полную копию всех файлов и каталогов под управлением CVS, включая все сделанные Обычно Вы никогда не получаете доступ к файлам в CVS напрямую. Используются команды CVS для получения копии в "рабочий каталог"и далее работа идјт над копией. После внесения изменений - юзер вносит изменения в репозиторий. После этого, в хранилище сохраняется информация о сделанных изменениях, времени внесения изменений и другая подобная информация. 66 ГЛАВА 9. ИНСТРУМЕНТАЛЬНЫЕ СРЕДСТВА РАЗРАБОТЧИКА Для указания, какой из репозиторев используется - применяется переменная окружения CVSROOT, либо явно указывается с помощью ключа -d. Примеры: $ CVSROOT=/var/cvs; export CVSROOT $ cvs checkout module/project или $ cvs -d /var/cvs module/project Кроме локальных репозиториев - очень часто используются удалјнные (сетевые). Для них необходимо указать адрес и (иногда) - способ доступа. $ cvs -d server1:/root checkout sdir1 Подробнее об этом - в ?? или в еј русском переводе на http://opennet.ru 9.3.2 Получение рабочей копии исходников 9.3.3 Сохранение результатов и версионирование 9.3.4 Коллективная работа над проектом 9.4 Библиотека Си (libc) libc содержит 2 части: системные вызовы и библиотечные функции. Системные вызовы определены, как функции языка Си (независимы от фактической реализации в ядре). В UNIX каждый системный вызов имеет соответствующую функцию (или функции) с тем же именем, хранящуюся в стандартной библиотеке Си. Функции из библиотеки выполняют преобразования аргументов и вызов соответствующего кода ядра. Таким образом, библиотечный код - только оболочка, фактические инструкции находятся в ядре. Функции общего значения - также часть библиотеки, но не являются системными вызовами. Функции общего назначения и системные вызовы - основа среды программирования UNIX. В отличие от других библиотек, libc линкуется с каждым приложением, написанном на Си. Информация о системных вызовах и функциях содержится в 2 и 3 разделах man соотвественно. В различных системах различный набор системных вызовов, поэтому некоторые функции могут быть реализованы как библиотечные в одной системе и как системные вызовы в другой. libc полностью включает в себя библиотеки, определенные в ANSI C (stdio, math, assert). Как следствие: один из основных методов сделать программу переносимой - это написать ее на ANSI C. Такая программа будет компилироваться и работать на всех unix-системах. Подробнее интерфейсы libc будут рассмотрены в главах, посвященных архитектуре и межпроцессному взаимодействию.