Linux make не работает при первом запуске, успешно при втором запуске

Когда я запускаю make, первый запуск всегда терпит неудачу с Error 1, но второй запуск компилируется должным образом.

При первом запуске создается эта команда:

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -ldl -o ../project42 ../project42.c -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

Второй запуск вызывает эту команду (обратите внимание на включение csvparser.c и nxjson.c):

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -ldl -o ../project42 ../csvparser.c ../nxjson.c ../project42.c -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

Makefile выглядит так:

ACEBASEDIR=../../../..
APIDIR=ctree.ctdb/multithreaded/static
GLIBINC=$(shell pkg-config --cflags glib-2.0 | xargs)
INCDIRS=-I$(ACEBASEDIR)/include -I$(ACEBASEDIR)/include/sdk/$(APIDIR) $(GLIBINC)
CFLAGS=-g $(INCDIRS) -ldl -o $@
LIBDIRS=-L$(ACEBASEDIR)/lib/$(APIDIR)
SYSLIBS=-lpthread -ldl -lm -lglib-2.0
SRCDIR=..
OUTDIR=..
$(OUTDIR)/project42: $(SRCDIR)/csvparser.c $(SRCDIR)/nxjson.c $(SRCDIR)/project42.c
    cc $(CFLAGS) $? $(LIBDIRS) -lmtclient $(SYSLIBS)
clean:
    rm -f $(OUTDIR)/project42

Когда я разворачиваю команду, я получаю следующее:

cc -g -I../../../../include -I../../../../include/sdk/ctree.ctdb/multithreaded/static $(shell pkg-config --cflags glib-2.0 | xargs) -ldl -o $@ $? -L../../../../lib/ctree.ctdb/multithreaded/static -lmtclient -lpthread -ldl -lm -lglib-2.0

Запуск pkg-config --cflags glib-2.0 | xargs возвращает -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include.

На мой взгляд, проблема связана с переменной $?, любезно описанной здесь. При первом запуске кажется, что разрешается только ../project42.c, а не ../csvparser.c ../nxjson.c ../project42.c.

Я подозреваю, что у меня что-то вышло из строя, и это кешируется во время первого запуска, но только ПОСЛЕ того, как это необходимо.

Что мне нужно изменить в Makefile, чтобы компиляция заработала в первый раз? Мне нужно переместить часть -L (LIBDIRS) перед чем-то другим?


person Adam Howell    schedule 03.12.2019    source источник


Ответы (1)


Не используйте $?. Это расширяется до списка файлов, которые новее, чем целевой. Вы не можете создать исполняемый файл только из измененных файлов: вы должны собрать его из всех файлов.

Вместо этого вы хотите использовать $^.

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

person MadScientist    schedule 03.12.2019
comment
Хороший ответ. Однако я не вижу веских причин для перехода на сценарий оболочки здесь. У меня есть много изящных make-файлов, которые могут быть простыми сценариями оболочки, но могут усложниться позже. - person remcycles; 03.12.2019
comment
Это устранило проблему, спасибо! Сработал ли второй запуск, потому что первый запуск изменил метку времени на csvparser.c и nxjson.c? - person Adam Howell; 03.12.2019
comment
Я не вижу возможности, чтобы этот make-файл изменил временные метки в исходных файлах. Обычно это очень плохая идея: временные метки исходного файла должны изменяться пользователем только при выполнении обновлений. Скорее всего, первая сборка не была скомпилирована из-за отсутствия файлов (вы не показываете это здесь), и поэтому цель ../project42 была удалена из-за ошибок. Затем вы повторно запустили make, и теперь все файлы новее, чем (несуществующий) целевой объект, поэтому $? расширяется до всех из них. - person MadScientist; 03.12.2019