Сборочные файлы в Linux: обзор - Ложные цели, макрос и специальные символы

ОГЛАВЛЕНИЕ

Ложные цели, макрос и специальные символы

Иногда target – это не файл, а действие, подлежащее выполнению. Цель, не относящаяся к файлу, называется ложной целью.

Например:

getobj:
mv obj/*.o . 2>/dev/null

Цель getobj перемещает все файлы с расширением .o из каталога obj в текущий каталог – ничего особенного. Но что если в obj нет файла? В этом случае команда mv вернет ошибку, которая передастся команде make.

Замечание: Стандартное поведение команды make – прервать обработку при обнаружении ошибки при выполнении команд в правилах.

Конечно, бывают случаи, когда каталог obj пустой. Как не допустить прерывания команды make при появлении ошибки?

Можно использовать специальный символ - (минус) перед командой mv. Итак:

getobj:
-mv obj/*.o . 2>/dev/null

- Приказывает make игнорировать ошибки. Есть еще один специальный символ: @ приказывает make не печатать команду в стандартный вывод перед выполнением. Можно объединять оба символа всегда перед командой:

getobj:
-@mv obj/*.o . 2>/dev/null

Есть специальная ложная цель по имени all(все), позволяющая сгруппировать несколько главных целей и ложных целей. Ложная цель all часто используется, чтобы направлять команду make при чтении сборочного файла.

Например:

all: getobj app install putobj

Команда make выполнит цели в последовательности: getobj, app, install и putobj. Также команда make поддерживает макросы в сборочных файлах. Можно определить макрос, написав:

MACRONAME=value

и обратиться к значению MACRONAME(макроимя), написав $(MACRONAME) или ${MACRONAME}.

Например:

EXECPATH=./bin

INCPATH=./include

OBJPATH=./obj

CC=cc

CFLAGS=-g -Wall -I$(INCPATH)

При выполнении make заменяет $(MACRONAME) на выделенное определение. Узнав, что такое ложные цели и макросы, переходим к следующему примеру.

Тестирование sample3

sample3 имеет чуть более сложный сборочный файл, использующий макросы, ложные цели и специальные символы. Также в каталоге sample3 есть 3 подкаталога:

• include – тут хранятся все файлы .h.
• obj – каталог, куда все объектные файлы перемещаются после компоновки, и откуда они перемещаются перед началом новой компоновки.
• bin – сюда копируются конечные исполнимые файлы.

Исходники .c хранятся вместе со сборочным файлом в корне sample3. Если имя сборочного файла - makefile, то не надо использовать параметр –f в команде make.

Файлы разделены по каталогам для повышения реалистичности примера. Листинг сборочного файла идет ниже:

Рисунок 4:Листинг сборочного файла sample3

Конечно, номеров строк нет в сборочном файле. Они используются здесь для облегчения чтения исходника.

Итак, имеется:

• Строки 7 - 13: определение некоторого макроса:
      - INSTPATH, INCPATH и OBJPATH ссылаются на подкаталоги.
      - CC и CFLAGS - компилятор и наиболее распространенные параметры компилятора соответственно. Если хотите, можете изменить CC, чтобы он указывал на компилятор gcc.
      - COND1 и COND2 – выполняемые команды, затем обращается к макросу.

• Строка 17: ложная цель all как самая первая цель в сборочном файле. Цель all определяет порядок выполнения целей слева направо:
      - За getobj первым идет app (main.o, mod_a.o и mod_b.o являются зависимостями app и будут вызваны при необходимости), затем make вызывает цель install, и в конце выполняется putobj.

• Строки 19-29: перечисляют цели, отвечающие за компоновку самого приложения. Обратите внимание на использование макросов CC и CFLAGS. Помните, макросы заменяются значениями. Так что $(CC) читается как cc, а CFLAGS читается как -g -Wall -I./include. Затем строка 20 интерпретируется как:
      - -g -Wall -I./include -o app main.o mod_a.o mod_b.o

• Строки 31-34: перечисляют цели getobj и putobj. Это ложные цели, помогающие или организующие процесс компоновки:
      - getobj указан в цели all как выполняемый первым. Он отвечает за извлечение объектных файлов из каталога obj ($(OBJPATH)) перед началом компоновки. Команда make может сравнить метки времени у объектов с метками времени у файлов исходного кода и заново скомпоновать или нет объектный файл согласно изменениям в исходных файлах.
      - putobj делает противоположное. После успешной компоновки он перемещает все объектные файлы обратно в каталог obj.

• Строка 38: цель install – еще одна ложная цель, показывающая использование оператора командного процессора if(если). Программирование командного процессора не входит в данную статью. Если вам нужно больше информации, гуглите. Далее в статье объяснено, что делает цель install(установить).

• Строка 47: цель cleanall удаляет все файлы, чтобы заставить команду make скомпоновать все заново. Она не вызывается во время процесса компоновки. Ее можно вызвать путем передачи ее в качестве аргумента команде make:

make cleanall

Также обратите внимание на использование специальных символов (- и @) перед командами в getobj, putobj, install и cleanall. Как сказано выше, - приказывает make продолжить обработку даже при появлении ошибки, а @ приказывает make не печатать команду перед ее выполнением.

Замечание: В цели install каждая строка завершается "\", и символ "\" должен быть последним символом в строке (никаких пробелов после него), иначе make может выдать следующую ошибку:

строка xxx: синтаксическая ошибка: неожиданный конец файла

Где xxx – строка, считающаяся началом блока.

Всегда при группировке команд с помощью \ он должен быть последним символом в строке.

Выполняется следующая последовательность команд (рисунок 5):

Рисунок 5: Последовательность команд sample3.

1. Команда make вызывается без аргументов, так как имя сборочного файла - makefile.
      - Если нет файлов в каталоге obj, getobj выдаст ошибку. Однако символ - (минус) перед командой mv (строка 32) не дает make прервать обработку.
      - Это сообщение печатается, только если условие истинно (строка 39). Обратите внимание на символ @ перед оператором if. Оно запрещает печать всего блока. Условие сравнивает две строки, являющиеся результатом двух команд, определенных макросами COND1 и COND2 (строки 12-13). Условие использует сочетание команд командного процессора, чтобы проверить, различаются ли метки времени app и ./bin/myapp. Если истина – app копируется в ./bin с именем myapp, и его полномочия доступа к файлу меняются, чтобы разрешить доступ к нему только владельцу файла. Если никакого условия не было наложено, то цель install выполняется при каждом вызове make.
2. Команда make вызывается снова, но выполняются только getobj и putobj. Не происходит компоновка и, следовательно, не выполняется install.
3. Команда touch меняет метку времени для inc_a.h
4. Команда make вызывается, и перекомпоновываются только цели с зависимостью inc_a.h.
5. Перечисляется содержимое ./bin. Обратите внимание на полномочия myapp.
6. Пример использования цели cleanall.