Почему gnumake переделывает промежуточный файл? - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть очень простой make-файл, как показано ниже:

.PHONY: clean all

CC              = /home/utils/gcc-5.2.0/bin/g++
CFLAGS          = -Wall -Werror -fPIC 

SRC             = $(wildcard *.c)
OBJ             = $(subst .c,.o,$(SRC))

.INTERMEDIATE: $(OBJ)

all: test.so

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

test.so: $(OBJ)
    $(CC) -shared $^ -o $@

clean:
    @rm -f *.o *~ *.so

У меня есть только два файла в одном каталоге: ac и bc. Когда я выполняю «make all», я получаю следующее, что идеально.

/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC  -o a.o -c a.c
/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC  -o b.o -c b.c
/home/utils/gcc-5.2.0/bin/g++ -shared a.o b.o -o test.so
rm a.o b.o

Однако, если я это сделаю: коснитесь ac;make all

Я получил ту же последовательность выполнения make, что и выше, что я не ожидал.Между ac и bc нет никакой зависимости. Я ожидаю, что:

/home/utils/gcc-5.2.0/bin/g++ -Wall -Werror -fPIC  -o a.o -c a.c
/home/utils/gcc-5.2.0/bin/g++ -shared a.o b.o -o test.so
rm a.o

Я не понимаю, почему bc снова компилируется.Согласно руководству gnumake:

Первое различие заключается в том, что происходит, если промежуточный файл не существует.Если обычный файл b не существует и make рассматривает цель, которая зависит от b, он неизменно создает b, а затем обновляет цель из b.Но если b - промежуточный файл, то make может оставить достаточно одного.Обновление b или конечной цели не будет беспокоить, если какое-либо предварительное условие для b не новее этой цели, или нет другой причины для обновления этой цели.

bo - промежуточный файл, он не долженскомпилирован снова, так как bc не изменился.Что я пропустил?

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Ваша трудность связана с тем, что вы подразумеваете под промежуточный файл не то, что означает GNU Make;но специальная цель .INTERMEDIATE позволяет вам настаивать на том, что a.o и b.o, которые в вашем make-файле не являются промежуточными файлами в смысле GNU Make, должны обрабатываться так, как если бы они были промежуточными в смысле GNU понимайте, и тогда вы будете ошарашены последствиями.

Что вы имеете в виду под F - это промежуточный файл : F является предварительным условием для цели T, а само F имеет предпосылки .Таким образом, a.o и b.o являются промежуточными по отношению к test.so, потому что они являются предпосылками для этой цели, и сами имеют соответствующие предпосылки a.c и bc`.

В вашем смысле промежуточные, поэтому цель test.so не требует переделывания (a.o | b.o), если она не старше (a.c|b.c).Таким образом, вы озадачены тем фактом, что когда a.o и b.o сделаны .INTERMEDIATE, GNU Make всегда удаляет их , когда делает test.so:

bo является промежуточным файлом, его не нужно снова компилировать, поскольку bc не изменился.Что я пропустил?

В основном вы пропустили 10.4 Цепи неявных правил

Обычно файл не может быть промежуточным, если он указан вMakefile в качестве цели или предпосылки.Однако вы можете явно пометить файл как промежуточный, указав его как обязательное условие специальной цели .INTERMEDIATE.Это вступает в силу, даже если файл упоминается явно как-то иначе.

Так, a.o и b.o обычно не будут промежуточными в смысле GNU Make, потому чтоони упоминаются в вашем make-файле как обязательные для test.so.Но вы можете сделать их промежуточными, в смысле GNU Make, перечислив их в качестве предварительных условий .INTERMEDIATE - как вы это сделали.

Что означает GNU Make под промежуточным , более техническичем то, что вы имеете в виду и объясняется в том же разделе руководства:

Иногда файл может быть создан с помощью последовательности неявных правил.Например, файл no можно создать из ny, запустив сначала Yacc, а затем cc.Такая последовательность называется цепочкой.

Если файл nc существует или упоминается в make-файле, специальный поиск не требуется: make находит, что объектный файл может быть создан компиляцией C из nc;позже, при рассмотрении вопроса о том, как сделать nc, используется правило для запуска Yacc.В конечном итоге и nc, и no обновляются.

Однако, даже если nc не существует и не упоминается, make знает, как представить его как недостающее звено между no и ny! В этом случае nc называется промежуточным файлом .Как только make решит использовать промежуточный файл, он будет введен в базу данных, как если бы он был упомянут в make-файле, вместе с неявным правилом, в котором указано, как его создать.

(Myакцент).Короче говоря, если Make требуется сделать цель output и обнаружить файл input такой, что:

  • У него нет явного правила для создания вывод из ввод , но -
  • Он знает последовательность неявных (он же встроенный ) правил, по которым файл stage , который не является целью или обязательным условием в make-файле, может быть сделан из input , и из которого output может быть выполнен, тогда он примет эту последовательность правил вывод из ввод через stage , а stage будет промежуточным файлом.

Важно, поскольку этап не является одной из ваших целей или обязательным условием для любой из них, Make знает, что это всего лишь одноразовый побочный продукт изготовления вывод из ввода и, следовательно, может быть удален, когда он служит этой цели.

Вот простой пример проекта с участием файлов, которые действительно являются промежуточными в смысле GNU Make.У нас есть yacc source yacc.y и lex source lex.l в каталоге проекта, и мы хотим построить из них парсер, parse,со следующим make-файлом:

Makefile

YFLAGS := -d
OBJS := yacc.o lex.o

.PHONY: all clean

all: parse

parse: $(OBJS)
    $(CC) $^ -o $@

clean:
    $(RM) parse $(OBJS)

Он работает так:

$ make
yacc -d yacc.y
mv -f y.tab.c yacc.c
cc    -c -o yacc.o yacc.c
lex  -t lex.l > lex.c
cc    -c -o lex.o lex.c
cc yacc.o lex.o -o parse
rm lex.c yacc.c

Теперь вы видите, что Make, используя его каталогнеявные правила, выяснили, что yacc.o может быть сделано путем компиляции несуществующего исходного файла C yacc.c, и что yacc.c может быть получено из существующего исходного файла yacc.y с помощью yacc -d yacc.y; mv -f y.tab.c yacc.c.Аналогично, выяснилось, что lex.o можно сделать, скомпилировав несуществующий источник C lex.c, и что lex.c можно сделать из lex.l, запустив lex -t lex.l > lex.c.Затем parse создается из yacc.o и lex.o обычной связью, которую указывает make-файл.

Но ваш make-файл ничего не говорит о yacc.c и lex.c.Насколько вы сказали Make, для вас не имеет значения, существуют ли такие файлы когда-либо.Это промежуточные файлы , просто этапы производства .y -> .o и .l -> .o.Поэтому, когда Make завершает работу с ними:

rm lex.c yacc.c

Затем, если вы:

$ touch yacc.y

и снова:

$ make
yacc -d yacc.y
mv -f y.tab.c yacc.c
cc    -c -o yacc.o yacc.c
cc yacc.o lex.o -o parse
rm yacc.c

only yacc.o переделывается длясвязь parse и промежуточный файл one yacc.c, созданный на этот раз, удаляются.

Нижняя строка

Ваш объектфайлы не являются промежуточными в GNU Make, и вы не хотите, чтобы с ними обращались так, как если бы они были.Это нормально для объектных файлов.Так что удалите .INTERMEDIATE: $(OBJ).

0 голосов
/ 27 ноября 2018

Если b.o не перекомпилировано, то test.so не может быть создано, поскольку оно зависит от b.o.Вы не можете создать общую библиотеку из a.o и b.o, если b.o был удален.

Если вы пытались создать статическую библиотеку, вы могли бы использовать специальный синтаксис архива make для замены a.o без необходимости перекомпиляции b.o, но это невозможно, если вы не используете специальный синтаксис архива, и это невозможно сделать для разделяемых библиотек, например, когда вы пытаетесь создать здесь.

Есть причинаэти .o файлы не считаются промежуточными по умолчанию, и их принудительное добавление к цели .INTERMEDIATE не означает, что вы можете избежать их восстановления.

...