Makefile问题 - 部分执行两次

时间:2014-03-14 16:12:27

标签: c++ c makefile d

我可能不是Makefile-guru,但我过去有过一些经验。但是,我有一个(相当不重要的)问题,这仍然令我感到困惑。

这是我的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

所以,没关系。但是,我仍然不明白为什么。我是否误解了Makefile的结构方式?任何意见都非常欢迎! : - )

3 个答案:

答案 0 :(得分:2)

你对如何使用多个目标解释规则有一个基本的误解:这个makefile实际上不起作用。让我们扩展运行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}

现在你可以看到你的问题了。想要构建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设置,因为源文件不依赖于它,因此它们不会永远被重建。您仍然有对象文件的破坏规则。如果你想要启用并行构建,你的解决方案将无法工作,因为设置可能与其他目标并行运行:你真的想要依赖以确保订购。

一般情况下,在编写makefile时,您应该(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

答案 1 :(得分: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扩展名).PHONY目标(并且我不确定虚假目标是否有帮助,或),所以它不存在。因此,当make尝试确保lex.yy.c是最新的时,它必须执行setup的规则;同上logramm.tab.c;因此双重执行。

您的解决方案看起来很合理。您可以浏览.PHONY并查看在使用GNU make时是否有帮助,并且不介意与GNU make绑定。

答案 2 :(得分:1)

这归结为make处理依赖关系的方式。您可以通过传递make标志来确切地检查-d正在做什么(至少对于GNU Make,ymmv,如果您没有使用任何内置规则,也可以考虑添加-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
...

以下是setupall

的依赖关系的情况
...
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
...