Внутреннее устройство Linux
Шрифт:
UTIL_OBJS=util.o
BORING_OBJS=$(UTIL_OBJS) boring.o
TRITE_OBJS=$(UTIL_OBJS) trite.o
PROGS=boring trite
Остальная часть файла Makefile могла бы выглядеть так:
all: $(PROGS)
boring: $(BORING_OBJS)
$(CC) -o $@ $(BORING_OBJS) $(LDFLAGS)
trite: $(TRITE_OBJS)
$(CC) -o $@ $(TRITE_OBJS) $(LDFLAGS)
Вы могли бы скомбинировать две цели для исполняемых файлов в виде одного правила, но обычно так поступать не следует, поскольку вам было бы непросто перенести правило в другой файл Makefile и удалить исполняемый файл или группу исполняемых файлов в отдельности. Более того, зависимости стали бы некорректными: если
примечание
Если вам необходимо определить специальное правило для объектного файла, поместите такое правило непосредственно над правилом, которое задает сборку исполняемого файла. Если несколько исполняемых файлов используют один и тот же объектный файл, поместите правило для объектного файла над всеми правилами для исполняемых файлов.
15.3. Отладчики
Стандартным отладчиком в системах Linux является gdb; доступны также системы с дружественным к пользователю интерфейсом, например Eclipse IDE и Emacs. Чтобы включить полную отладку ваших программ, запустите компилятор с параметром -g для записи таблицы имен и другой отладочной информации в исполняемый файл. Чтобы запустить отладчик gdb для исполняемого файла program, выполните такую команду:
$ gdb program
Вы должны получить приглашение (gdb). Чтобы запустить программу program с параметром командной строки options, введите следующую команду после приглашения отладчика:
(gdb) run options
Если программа в порядке, она должна запускаться, работать и завершать выполнение нормально. Однако, если возникает проблема, отладчик gdb останавливается, выводит ошибочный исходный код и возвращает вас в строку приглашения (gdb). Поскольку фрагмент исходного кода часто содержит подсказку о причине проблемы, вам может потребоваться вывести значение какой-либо переменной, с которой связана ошибка. Команда print работает также для массивов и структур языка C.
(gdb) print variable
Чтобы отладчик остановил программу в указанном месте исходного кода, используйте контрольные точки. В следующей команде файл file является файлом с исходным кодом, а параметр line_num — это номер строки этого файла, в которой отладчик должен остановиться:
(gdb) break file:line_num
Для продолжения отладки выполните такую команду:
(gdb) continue
Чтобы удалить контрольную точку, введите команду:
(gdb) clear file:line_num
Этот раздел содержит только краткое введение в отладчик gdb в надежде на то, что вы изучите более полное руководство, онлайн или в печатном виде, например 10-е издание книги Ричарда М. Столлмана (Richard M. Stallman) и др. Debugging with GDB («Отладка с помощью GDB», GNU Press, 2011). Еще одним руководством по отладке является книга Нормана Матлофа (Norman Matloff) и Питера Джея Зальцмана (Peter Jay Salzman) The Art of Debugging («Искусство отладки», No Starch Press, 2008).
примечание
Если вам интересно выявление проблем в памяти и запуск профильных тестов, посетите сайт проекта Valgrind .
15.4. Инструменты Lex и Yacc
Инструменты Lex и Yacc могли встретиться вам при компиляции программ, которые читают файлы конфигурации или команды. Эти инструменты являются строительными блоками для языков программирования.
• Lex — это разметчик (tokenizer), который переводит текст в пронумерованные теги с ярлыками. Версия GNU/Linux для этого инструмента называется flex. Для его совместной работы с компоновщиком могут потребоваться флаги -ll или -lfl.
• Yacc — это синтаксический анализатор, который пытается считывать метки в соответствии с грамматикой. Анализатор GNU называется bison; для его совместимости с Yacc запустите команду bison -y. Может потребоваться флаг компоновщика -ly.
15.5. Языки сценариев
В давние времена обычному системному администратору Unix не приходилось особенно беспокоиться насчет других языков сценариев, кроме Bourne shell и awk. Сценарии оболочки (рассмотренные в главе 11) по-прежнему остаются важной частью системы Unix, но язык awk понемногу сходит со сценарной арены. В то же время появились его мощные наследники, и теперь многие системные команды созданы не на языке C, а на языках сценариев (например, практичная версия команды whois). Рассмотрим некоторые основы сценариев.
Для начала вам необходимо знать о любом языке сценариев следующее: первая строка сценария выглядит так же, как и в сценарии оболочки Bourne shell. Например, сценарий на языке Python начинается так:
#!/usr/bin/python
Или так:
#!/usr/bin/env python
В Linux любой исполняемый текстовый файл, начинающийся символами #!, является сценарием. Путь, который следует за этим префиксом, представляет исполняемый файл интерпретатора языка сценариев. Когда Unix пытается запустить исполняемый файл, который начинается с символов #!, она выполняет следующую за ним команду, используя оставшуюся часть файла как стандартный ввод. Следовательно, даже такой код является сценарием:
#!/usr/bin/tail -2
This program won't print this line,
but it will print this line...
and this line, too.
Первая строка сценария оболочки часто содержит одну из самых распространенных проблем со сценариями: неверный путь к интерпретатору языка сценариев. Допустим, вы назвали предыдущий сценарий myscript. Что будет, если команда tail на самом деле находится в вашей системе в каталоге /bin вместо /usr/bin? В этом случае запуск сценария myscript вызвал бы такую ошибку:
bash: ./myscript: /usr/bin/tail: bad interpreter: No such file or directory
Не рассчитывайте на то, что в первой строке сценария будет работать несколько аргументов. То есть аргумент -2 в приведенном примере мог бы сработать, но если вы добавите еще один аргумент, то система могла бы расценивать -2 и этот новый аргумент как один большой аргумент с пробелами, и все. Это может быть различным для разных систем, поэтому не испытывайте свое терпение на таких малозначащих вещах, как эта.