Makefile - section执行两次的问题
Issue with Makefile - section executed twice
我可能不是一个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
所以,没关系。然而,我还是不明白为什么。我是否误解了makefile的结构方式?欢迎任何意见!: -)
您对make如何解释具有多个目标的规则有一个基本的误解:这个make文件实际上不起作用。让我们展开运行lex/yacc的规则:
lex.yy.c logramm.tab.c: setup
${LEX} ${CC_LEXER}
${YACC} -d ${CC_PARSER}
Make将其解释为(在显式规则中,多个目标为每个目标创建单独的规则):
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设置,因为源文件不依赖于它,所以它们不会总是被重建。对于目标文件,您仍然有不符合的规则。此外,如果你想启用并行构建,你的解决方案将不起作用,因为安装可能与其他目标并行运行:你真的希望依赖关系确保顺序。
一般来说,当你写makefile时,你应该(a)有一个规则来构建一个目标,(b)确保规则构建的目标完全符合你告诉make它要构建的目标。
试着用这个代替:
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
问题是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
同上;因此要执行两次。
你的解决方案看起来很合理。如果你正在使用GNU make
,并且不介意被绑定到GNU make
,你可以探索.PHONY
,看看它是否有帮助。
这归结为make
处理依赖关系的方式。您总是可以通过传递-d
标志来检查make
正在做什么(至少对于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
...
以下是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
...
- g++的分段错误(在NaN上使用to_string两次时)
- 蛇在C++不会连续转两次
- 检查一个数组是否包含在另一个数组中,以相反的顺序,至少两次
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 我应该如何去缓解两次出现的cin?
- Realloc 两次无法在 Visual Studio 上运行
- 使用 getline(cin, var) 两次在进行字符串比较时会产生错误 (==)
- 为什么映射插入和 map.find() 的单次迭代比插入和 map.find() 的两次单独迭代慢得多
- C++析构函数调用两次,堆栈分配的复合对象
- 为什么参数在构造 std::thread 时移动两次
- 在钻石问题的求解中,为什么要虚拟地继承两次grand-parent类
- C OOP,读取文件的问题,EOF使用了两次,排行榜
- 矩阵移位两次时出现问题
- 不知道出了什么问题 - 两次程序隔离错误
- 复制构造函数——用相同的变量按值调用函数两次会导致问题
- 布尔值返回两次有问题(Arduino)
- C++两次传递函数指针导致问题
- Printf由于某种原因打印两次,cout似乎没问题
- 使用字符,我发现的唯一解决方案是static_cast两次。有没有办法解决这个问题?
- Makefile - section执行两次的问题