Сборочные файлы в Linux: обзор - Сборочный файл, вызывающий другие сборочные файлы

ОГЛАВЛЕНИЕ

Сборочный файл, вызывающий другие сборочные файлы

При работе над крупным проектом с множеством разных частей, таких как библиотеки, динамически подключаемые библиотеки, исполнимые файлы, удобно разбить их в структуру каталогов, храня исходники каждого модуля в его собственном каталоге. Следовательно, каталог каждого исходника может иметь свой собственный сборочный файл, вызывающийся главным сборочным файлом.

Главный сборочный файл хранится в корневом каталоге, меняющемся на каждый подкаталог для вызова сборочного файла модуля. Это просто.

Но есть хитрость, которую надо знать при принуждении команды make переключиться на другой каталог. Например, испытаем простой сборочный файл:

target1:
@pwd
cd dir_test
@pwd

Результат вызова команды make:

Рисунок 11: Неправильный способ изменения текущего каталога

Команда pwd печатает текущий каталог. В данном случае это каталог /root. Заметьте, что вторая команда pwd печатает тот же самый каталог даже после выполнения cd dir_test. Что это значит?

Вы должны знать, что большинство команд командного процессора, таких как cp, mv и так далее, заставляют команду make:

• открыть новый экземпляр командного процессора;
• выполнить команду;
• закрыть экземпляр командного процессора;

По сути, make создает три разных экземпляра командного процессора для обработки каждой из тех команд.

cd dir_test выполнился успешно только во втором экземпляре командного процессора, созданного make.

Решение имеет вид:

target1:
(pwd;cd dir_test;pwd)

Смотрите на результат:

Рисунок 12: Правильный способ изменения текущего каталога

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

Представьте, что произошло бы, если бы не использовались квадратные скобки, и сборочный файл был бы:

target1:
cd dir_test
make

Смотрите на результат:

Рисунок 13: Рекурсивный вызов make

При использовании команды make без квадратных скобок она рекурсивно вызывает один и тот же сборочный файл. Например, make[37] означает 37-й экземпляр команды make.

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

sample5 показывает, как вызвать другие сборочные файлы посредством главного сборочного файла. В каталоге sample5 есть:

• каталог tstlib – содержит исходный код простой библиотеки (tlib.a).
• каталог application(приложение) – содержит исходный код приложения, связанный с tlib.a.
• makefile – главный сборочный файл.
• runmk – командный процессор, вызывающий главный сборочный файл. На самом деле этот командный процессор не требуется, но когда команда make обрабатывает сборочный файл, переключающийся на другой каталог, make показывает раздражающее сообщение, сообщающее, что она входит в или покидает каталог. Используйте --no-print-directory, чтобы избавиться от этих сообщений.

Листинг главного сборочного файла:

COND1=`stat app 2>/dev/null | grep Modify`
COND2=`stat ./application/app 2>/dev/null | grep Modify`

all: buildall getexec

buildall:
@echo "****** Invoking tstlib/makefile"
(cd tstlib; $(MAKE))
@echo "****** Invoking application/makefile"

(cd application; $(MAKE))

getexec:
@if [ "$(COND1)" != "$(COND2)" ];\
then\
echo "Getting new app!";\
cp -p ./application/app . 2>/dev/null;\
chmod 700 app;\
else\
echo "Nothing done!";\
fi

cleanall:
-rm -f app
@echo "****** Invoking tstlib/makefile"
@(cd tstlib; $(MAKE) cleanall)

@echo "****** Invoking appl/makefile"
@(cd application; $(MAKE) cleanall)

Это несложно. 4 ложные цели. Цель all target начинает вызывать цель buildall, и команде make приказывают войти и попытаться скомпоновать два разных проекта. Обратите внимание на макрос $(MAKE), заменяемый словом make. Макрос $(MAKE) стандартный и не требует определения.

Цель cleanall неявно используется для удаления всех объектов и исполнимых файлов. Символ @ перед открывающими квадратными скобками заставляет make не печатать команды.

Опробуем следующую последовательность команд (рисунок 14):

Рисунок 14: Последовательность команд sample5

1. Команда make вызывается через командный процессор runmk для обработки главного сборочного файла.
      - Цель all вызывает цель buildall, и она всегда выполняется, так как является ложной целью. Сначала вызывается сборочный файл в каталоге tstlib, и компонуется tlib.a. Смотрите листинг сборочного файла:

TLIB=tlib.a
OBJS=tstlib_a.o tstlib_b.o
CC=cc
INCPATH=.
CFLAGS=-Wall -I$(INCPATH)

.c.o:
$(CC) $(CFLAGS) -c $<

$(TLIB): $(OBJS)
ar cr $(TLIB) $(OBJS)

$(OBJS): $(INCPATH)/tstlib.h

cleanall:
-rm -f *.o *.a

       - Затем вызывается сборочный файл в каталоге application, и компонуется app. Смотрите листинг сборочного файла:

OBJS=main.o mod_a.o mod_b.o
CC=cc
INCLIB=../tstlib
LIBS=$(INCLIB)/tlib.a
CFLAGS=-Wall -I. -I$(INCLIB)

.c.o:
$(CC) $(CFLAGS) -c $<

app: $(OBJS) $(LIBS)
$(CC) $(CFLAGS) -o app $(OBJS) $(LIBS)

$(OBJS): inc_a.h inc_b.h $(INCLIB)/tstlib.h

cleanall:
-rm -f *.o app

Заметьте, что tlib.a является зависимостью в цели app. Следовательно, всегда, когда tlib.a перекомпоновывается, app приходится снова связывать с ней.

       - Цель getexec была вызвана в главном сборочном файле. Так как исполнимый файл app отсутствует в каталоге sample5, он копируется из каталога application.

2. Команда touch используется для изменения метки времени tstlib/tstlib_b.c, имитируя изменение, сделанное в файле.
3. Команда make вызывается через командный процессор runmk для обработки главного сборочного файла.
       - tlib.a перекомпоновывается.
       - app снова связывается с tlib.a, так как она изменилась.
       - Была вызвана цель getexec в главном сборочном файле. Так как application/app отличается от app, оно обновляется в каталоге sample5.
4. Команда touch используется для изменения метки времени application/inc_a.h, имитируя изменение, сделанное в файле.
5. Команда make вызывается через командный процессор runmk для обработки главного сборочного файла.
       - tlib.a не обрабатывается, потому что она не изменилась.
       - app перекомпоновывается (все модули), потому что inc_a.h является зависимостью всех исходников .c.
       - Была вызвана цель getexec в главном сборочном файле. Так как application/app отличается от app, оно обновляется в каталоге sample5.
6. Цель cleanall выполняется в главном сборочном файле.

Заключение

Как видно из данной статьи, команда make является мощным инструментом, очень полезным для проектов. Эта статья не является руководством. Это всего лишь справка по основным особенностям написания сборочных файлов. В интернете есть много информации о команде make и о сборочных файлах. Также есть книги, рассматривающие другие возможности, отсутствующие в данной статье.