Проблема с Makefile - раздел выполнен дважды

0

Возможно, я не являюсь Makefile-гуру, но у меня есть опыт с ними в прошлом. Тем не менее, у меня есть (довольно неважная) проблема, которая все еще меня озадачивает.

Вот мой Makefile:

#-------------------------
# Definitions
#-------------------------

APP   = lgm

# Tools & commands

CC    = gcc
LEX   = lex
YACC  = /usr/local/bin/bison
RM    = rm
CP    = cp
MV    = mv
DMD   = dmd

# Paths

SRC     = src
BIN     = bin
TEST    = test
LIB     = lib

# C stuff

CC_HEADERS  = logramm.tab.h
CC_SOURCES  = lex.yy.c logramm.tab.c
CC_OBJECTS  = lex.yy.o logramm.tab.o

CC_LEXER    = logramm.l
CC_PARSER   = logramm.y

# D stuff

D_SOURCES   = main.d
D_OBJECTS   = main.o

D_LFLAGS    = -m64

#-------------------------
# Main Functions
#-------------------------

all: ${APP} clean

${APP}: ${CC_OBJECTS} ${D_OBJECTS}
    ${DMD} ${CC_OBJECTS} ${D_OBJECTS} -of${APP} ${D_FLAGS}
    ${MV} ${APP} ${BIN}

${D_OBJECTS}:
    ${DMD} -c ${D_SOURCES}

${CC_OBJECTS}: ${CC_SOURCES}
    ${CC} -g -c ${CC_SOURCES}

${CC_SOURCES}: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

setup:
    ${CP} ${SRC}/*.d .
    ${CP} ${SRC}/*.l .
    ${CP} ${SRC}/*.y .

clean:
    ${RM} *.d *.y *.l *.o *.hh *.c *.h

Беда в том, что:

Когда я смотрю вывод make all, часть ${CC_SOURCES} выполняется дважды (2 lex, 2 команды bison). Например, он выводит:

cp src/*.d .
cp src/*.l .
cp src/*.y .
lex logramm.l
/usr/local/bin/bison -d logramm.y
lex logramm.l
/usr/local/bin/bison -d logramm.y
gcc -g -c lex.yy.c logramm.tab.c
dmd -c main.d
dmd lex.yy.o logramm.tab.o main.o -oflgm 
mv lgm bin
rm *.d *.y *.l *.o *.hh *.c *.h
rm: *.hh: No such file or directory
make: *** [clean] Error 1

Почему это? Что я делаю не так?


ОБНОВИТЬ :

Мне только удалось это исправить, взяв setup из ${CC_SOURCES} и поместив ее во all разделы, например:

all: setup ${APP} clean

Итак, все в порядке. Однако я до сих пор не понимаю, почему. Я неверно истолковал способ структурирования Makefiles? Любой вход был бы более чем приветствуем! :-)

  • 1
    Setup не файл. Т.е. для каждого из компонентов ${CC_SOURCES} ( lex.yy.c и logramm.tab.c ) не существует актуальных предпосылок. Таким образом, правило выполняется дважды.
Теги:
makefile
d

3 ответа

2
Лучший ответ

У вас есть основное непонимание того, как make интерпретирует правила с несколькими целями: этот make файл действительно не работает. Позвольте развернуть правило, которое запускает lex/yacc:

lex.yy.c logramm.tab.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

Сделать это интерпретируется так, как если бы это было (в явном правиле несколько целей создают отдельное правило для каждой цели):

lex.yy.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

logramm.tab.c: setup
        ${LEX} ${CC_LEXER}
        ${YACC} -d ${CC_PARSER}

Теперь вы можете увидеть свою проблему. Make хочет построить lex.yy.o, и это зависит от lex.yy.c, поэтому make пытается его построить. Он видит, что это зависит от setup, которой не существует (потому что ничего не создает, но если кто-то создал этот файл в вашем каталоге, он сильно сломается). Таким образом, он запускает шаги lex и yacc (оба, начиная с этого рецепта) для сборки lex.yy.c

Затем это происходит точно так же, как для создания logramm.tab.c... поэтому правила запускаются дважды.

У вас одинаковая проблема с вашими объектными файлами; расширяя это правило, мы видим:

lex.yy.o logramm.tab.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

который идентичен:

lex.yy.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

logramm.tab.o: lex.yy.c logramm.tab.c
        ${CC} -g -c lex.yy.c logramm.tab.c

что явно не так.

Кроме того, ваше правило setup (поскольку оно никогда не существует) приведет к тому, что все будет восстанавливаться каждый раз.

Ваше решение лучше WRT, так как исходные файлы не зависят от него, поэтому они не всегда будут перестроены. У вас все еще есть нарушенные правила для объектных файлов. Также ваше решение не будет работать, если вы когда-либо захотите включить параллельные сборки, потому что настройка может выполняться параллельно с другими целями: вы действительно ХОТИТЕ зависимость, чтобы обеспечить упорядочение.

В общем, при написании make файлов вы должны (a) иметь одно правило для создания одной цели и (b) обеспечить правильное построение ТОЧНО, цель, которую вы сказали, сделать ее сборкой.

Попробуйте использовать это вместо этого:

all: ${BIN}/${APP} clean

${BIN}/${APP}: ${APP}
        ${CP} $< $@

${APP}: ${CC_OBJECTS} ${D_OBJECTS}
    ${DMD} $^ -of$@ ${D_FLAGS}

%.o : %.d
        ${DMD} -c $<

%.o: %.c
        ${CC} -g -c $<

%: ${SRC}/%
        ${CP} $< $@

lex.yy.c: ${CC_LEXER}
        ${LEX} $<

%.tab.c %.tab.h: %.y
        ${YACC} -d $<

clean:
        ${RM} *.d *.y *.l *.o *.hh *.c *.h
  • 0
    Большое спасибо. Действительно информативно! Мне действительно трудно решить, какой из этих двух великих ответов принять; но по соображениям справедливости (ответ @ Джонатана был раньше на 1 минуту) я пойду с его ответом. Тем не менее, я все еще ценю это! :-)
  • 0
    Это хорошо ... просто чтобы заметить, что есть и другие проблемы с вашим make-файлом, которые вы должны решить, в дополнение к тем, которые отметил Джонатан.
Показать ещё 9 комментариев
1

Проблема в том, что CC_SOURCES = lex.yy.c logramm.tab.c так что целевая строка (плюс действия):

${CC_SOURCES}: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

эквивалентно:

lex.yy.c: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

logramm.tab.c: setup
    ${LEX} ${CC_LEXER}
    ${YACC} -d ${CC_PARSER}

Правило setup не имеет зависимостей, но не является (GNU make extension) .PHONY target либо (и я не уверен, что это была фальшивая цель, тоже), поэтому его не существует. Поэтому, когда make пытается убедиться, что lex.yy.c обновлен, он должен выполнить правила setup; то же для logramm.tab.c; следовательно, двойное выполнение.

Ваше решение выглядит разумным. Вы можете исследовать .PHONY и посмотреть, поможет ли это, если вы используете GNU make и не против привязываться к GNU make.

  • 0
    Большое спасибо. Очень полезное объяснение!
1

Это сводится к тому, как make зависимости от ручек. Вы всегда можете проверить, что make, передавая флаг -d (по крайней мере, для GNU Make, ymmv, также подумайте о добавлении -r если вы не используете какие-либо встроенные правила, поскольку они существенно -r выходу).

Здесь, что происходит в случае, когда setup является зависимостью ${CC_SOURCES}

...
Does lex.yy.c exist? no, okay check its prerequisites
    Does setup exist? no, okay check its prerequisites
        No prerequisites, run the recipe
    Prerequisites for lex.yy.c done, run the recipe
Does logramm.tab.c exist? yes, but check its prerequisites
    We already built setup, so prune this prerequisite, but treat it as newer than logramm.tab.c
    Prerequisites for logramm.tab.c done, run the recipe
...

Вот что происходит в случае, когда setup является зависимостью от all

...
Does setup exist? no, okay check its prerequisites
    No prerequisites, run the recipe
...
Does lex.yy.c exist? no, okay check its prerequisites
    No prerequisites, run the recipe
Does logramm.tab.c exist? yes, but check its prerequisites
    No prerequisites, so done
...

Ещё вопросы

Сообщество Overcoder
Наверх
Меню