• Строки, образующие каждую командную строку, передаются оболочке в виде одной строки. Таким образом, все символы ;, которые нужны оболочке, должны присутствовать, включая даже те, которые обычно в сценариях оболочки опускаются, поскольку их наличие подразумевается благодаря символам новой строки. Более детально о программировании программной оболочки рассказывается в [22].
• Если требуется разыменовывать переменную make, это делается обычным образом (то есть $(переменная)), но если нужно разыменовывать переменную оболочки, необходимо применять двойной символ $: $$i.
4.2.2. Переменные
Часто бывает необходимо определить только один компонент переменной за раз. Можно написать, например, такой код:
OBJS = foo.о
OBJS = $(OBJS) bar.о
OBJS = $(OBJS) baz.о
Ожидается, что здесь OBJS будет определен как foo.о bar.о baz.о, но в действительности он определен как $(OBJS) baz.о, поскольку make не разворачивает переменные до момента их использования[4]. При ссылке в правиле на OBJS make войдет в бесконечный цикл[5]. Во избежание этого во многих make-файлах разделы организуются следующим образом:
OBJS1 = foo.о
OBJS2 = bar.о
OBJS3 = baz.о
OBJS = $(OBJS1) $(OBJS2) $(OBJS3)
Объявления переменных вроде предыдущего встречаются, когда объявление одной переменной оказывается слишком длинным и потому не удобным.
Развертывание переменной вызывает типичный вопрос, который программист в Linux должен решить. Инструменты GNU, распространяемые с Linux, обычно более функциональны, чем версии инструментов, включенных в другие системы, и GNU make — не исключение. Авторы GNU make предусмотрели альтернативный способ присваивания переменных, но не все версии make понимают эти альтернативные формы. К счастью, GNU make можно собрать для любой системы, в которую можно перенести исходный код, написанных под Linux. Существует форма простого присваивания переменных, которая показана ниже.
OBJS := foo.о
OBJS := $(OBJS) bar.о
OBJS := $(OBJS) baz.о
Операция := заставляет GNU make вычислить выражение переменной при присваивании, а не ждать вычисления выражения при его использовании в правиле. В результате выполнения этого кода OBJS действительно получит foo.о bar.о baz.о.
Простое присваивание переменной используется очень часто, но в GNU make есть еще и другой синтаксис присваивания, который позаимствован из языка С:
OBJS := foo.о
OBJS += bar.о
OBJS += baz.о
4.2.3. Суффиксные правила
Суффиксные правила — это другая область, в которой вам нужно решить, писать ли стандартные make-файлы или использовать расширения GNU. Стандартные суффиксные правила намного ограниченнее, нежели шаблонные правила GNU, но во многих ситуациях стандартные суффиксные правила могут оказаться полезными. К тому же шаблонные правила поддерживаются не во всех версиях make. Суффиксные правила выглядят следующим образом:
.c.o:
$(CC) -с $ (CFLAGS) $ (CPPFLAGS) -о $<
.SUFFIXES: .с .о
В этом правиле говорится (если не касаться излишних деталей), что make должна, если не было других явных указаний, превратить файл а.с в а.о путем запуска приложенной командной строки. Каждый файл .с будет рассматриваться так, будто он явно внесен в список в качестве зависимости соответствующего файла .о в вашем make-файле.
Это суффиксное правило демонстрирует другую возможность make — автоматические переменные. Понятно, что нужно найти способ подставить зависимость и целевой объект в командную строку. Автоматическая переменная $@ выступает в качестве целевого объекта, $< выступает в качестве первой зависимости, а $^ представляет все зависимости.
Существуют и другие автоматические переменные, которые рассматриваются в руководстве по make. Все автоматические переменные можно использовать в обыкновенных правилах, а также в суффиксных и шаблонных правилах.
Последняя строка примера представляет еще одну директиву. .SUFFIXES указывает make на то, что .с и .о являются суффиксами, которые должен использовать make для нахождения способа превратить существующие исходные файлы в необходимые целевые объекты.
Шаблонные правила более мощные и, следовательно, немного сложнее, чем суффиксные правила. Ниже приведен пример эквивалентного шаблонного правила для показанного выше суффиксного правила.
% .о: % .с
$(CC) -с $(CFLAGS) $(CPPFLAGS) -о $<
Дополнительные сведения о make можно получить в [26]. GNU make также включает замечательное и удобное в обращении руководство в формате Texinfo, которое можно почитать на сайте FSF, распечатать или заказать у них в форме книги.
Большинство крупных проектов с открытым исходным кодом используют инструменты Automake, Autoconf и Libtool. Эти инструменты представляют собой коллекцию знаний об особенностях различных систем и стандартах сообщества, которая может помочь в построении проектов. Таким образом, потребуется писать лишь немного кода, специфического для проекта. Например, Automake пишет целевые объекты install и uninstall, Autoconf автоматически определяет возможности системы и настраивает программное обеспечение для его соответствия системе, a Libtool отслеживает различия в управлении совместно используемыми библиотеками на разных системах.
По этим трем инструментам написана целая книга — [41]; здесь мы даем лишь основу, которая понадобится для работы с GNU Autoconf, Automake и Libtool.
4.3. Отладчик GNU
gdb — это отладчик, рекомендуемый Free Software Foundation, gdb представляет собой хороший отладчик командной строки, на котором строятся некоторые инструменты, включая режим gdb в Emacs, графический отладчик Data Display Debugger (http://www.gnu.org/software/ddd/) и встроенные отладчики в некоторых графических интерфейсах IDE. В этом разделе рассматривается только gdb.
Запустите gdb с помощью команды gdb имя_программы. gdb не будет просматривать значение PATH в поисках исполняемого файла. Отладчик загрузит символьную информацию для исполняемого файла и запросит дальнейших действий.
Существует три способа проверить процесс с помощью gdb.
• Используя команду run для обычного выполнения программы.
• Используя команду attach для начала проверки уже запущенного процесса. При подключении к процессу, последний останавливается.
• Исследуя существующий файл ядра для определения состояния процесса при его завершении. Для исследования файла ядра gdb потребуется запустить с помощью команды имя_программы файл_ядра.
Перед запуском программы или подключением к уже запущенному процессу можно установить точку прерывания, просмотреть исходный код и выполнить другие операции, которые не обязательно относятся к запущенному процессу.
4
Несмотря на то что такое поведение выглядит неудобным, это важное средство, а не ошибка. Неразворачиваемые переменные критически важны при написании обобщенных суффиксных правил, которые создают подразумеваемые зависимости.
5
Большинство версий make, включая версию GNU, распространяемую с Linux, определят бесконечный цикл и завершатся с выдачей соответствующего сообщения об ошибке.