gpt4 book ai didi

c++ - 我的 makefile 不断 self 编译;我究竟做错了什么?

转载 作者:行者123 更新时间:2023-11-30 02:16:42 28 4
gpt4 key购买 nike

我不确定是否有一些我不知道的内置变量或规则,或者 make 是否有问题,或者我只是疯了。

对于我的一个项目,我有一个如下的 makefile:

CC=g++
CFLAGS=-O3 `libpng-config --cflags`
LFLAGS=-lm `libpng-config --ldflags`

OBJS=basic_render.o render.o mandel.o
BINS=basic_render

.PHONY: all clean

all: $(BINS)

clean:
rm -f $(BINS) $(OBJS)

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

%: $(OBJS)
$(CC) $(LFLAGS) -o $@ $(OBJS)

构建时,我只想能够运行

make clean
make

构建 BINS 列表中的所有内容。

起初这一切正常,但由于某种原因,在我编辑源文件后行为发生了变化。

在编辑源文件之前:

$ make clean
rm -f basic_render basic_render.o render.o mandel.o
$ make
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o basic_render basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o

我可以一遍又一遍地这样做,而且效果很好。在我对 basic_render.cpp 进行更改之后(实际上只是改变了几个常量),它突然变成了这样:

$ make clean
g++ -O3 `libpng-config --cflags` -c -o basic_render.o basic_render.cpp
g++ -O3 `libpng-config --cflags` -c -o render.o render.cpp
g++ -O3 `libpng-config --cflags` -c -o mandel.o mandel.cpp
g++ -lm `libpng-config --ldflags` -o makefile basic_render.o render.o mandel.o
rm mandel.o basic_render.o render.o
makefile:1: warning: NUL character seen; rest of line ignored
makefile:1: *** missing separator. Stop.

不仅make clean试着编译程序,它编译了basic_render输出设置在 Makefile 中, 覆盖 Makefile本身。

编辑后basic_render.cpp ,我看了Makefile ,而且它没有改变,所以我的编辑器并没有改变 makefile 之类的东西。

那么,我做错了什么?

最佳答案

这是您的问题的 MCVE:

$ ls -R
.:
bar.c main.c Makefile

$ cat main.c
extern int bar(void);

int main(void)
{
bar();
return 0;
}

$ cat bar.c
int bar(void)
{
return 42;
}

$ cat Makefile
OBJS := main.o bar.o
BINS := prog

.PHONY: all clean

all: $(BINS)

%: $(OBJS)
$(CC) -o $@ $(OBJS)

clean:
$(RM) $(OBJS) $(BINS)

第一次制作:

$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog main.o bar.o
rm bar.o main.o

停下来注意 10.4 Chains of Implicit Rules 的不良后果:

rm bar.o main.o

程序链接后所有目标文件都被自动删除,破坏了目的制作。应归咎于我们自己的隐含规则:

%: $(OBJS)
$(CC) -o $@ $(OBJS)

加上内置的隐式规则1:

%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<

它们一起构成了一个隐含的规则链,产生了所有的目标文件成为 intermediate files .

继续,让我们更新源文件:

$ touch main.c

再做一次:

$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o Makefile main.o bar.o
rm bar.o main.o
Makefile:1: warning: NUL character seen; rest of line ignored
Makefile:1: *** missing separator. Stop.

我们的 Makefile 被链接破坏了:

cc -o Makefile main.o bar.o

手册中解释了这种困惑 3.5 How Makefiles Are Remade :

Sometimes makefiles can be remade from other files, such as RCS or SCCS files. If a makefile can be remade from other files, you probably want make to get an up-to-date version of the makefile to read in.

To this end, after reading in all makefiles, make will consider each as a goal target and attempt to update it. If a makefile has a rule which says how to update it (found either in that very makefile or in another one) or if an implicit rule applies to it (see Using Implicit Rules), it will be updated if necessary. After all makefiles have been checked, if any have actually been changed, make starts with a clean slate and reads all the makefiles over again. (It will also attempt to update each of them over again, but normally this will not change them again, since they are already up to date.)

(强调我的)。是否存在适用于 Makefile 的隐含规则?作为目标?是的,它是:

%: $(OBJS)
$(CC) -o $@ $(OBJS)

因为目标模式 % 匹配任何文件。如果我们恢复我们的破坏Makefile 并再次尝试相同的实验,这次是调试:

make -d >debug.log 2>&1

输出将向我们展示:

...
Reading makefiles...
Reading makefile 'Makefile'...
Updating makefiles....
Considering target file 'Makefile'.
Looking for an implicit rule for 'Makefile'.
...
...
Found an implicit rule for 'Makefile'.
...
...
Finished prerequisites of target file 'Makefile'.
Prerequisite 'main.o' is newer than target 'Makefile'.
Prerequisite 'bar.o' is newer than target 'Makefile'.
Must remake target 'Makefile'.
cc -o Makefile main.o bar.o
...

我们可以避免这个结果,也可以避免 self 挫败的自动删除我们的目标文件,通过不使用匹配任何隐式规则来执行我们的链式。通常的做法是通过以下方式从其目标文件制作程序明确的规则,例如

生成文件(二)

OBJS := main.o bar.o
BIN := prog

.PHONY: all clean

all: $(BIN)

$(BIN): $(OBJS)
$(CC) -o $@ $(OBJS)

clean:
$(RM) $(OBJS) $(BIN)

看来您很喜欢让 BINS 成为多个列表的选项程序:

I want to simply be able to run

make clean

make

to build everything in the BINS list.

但是考虑一下:

BINS := prog1 prog2

和食谱:

%: $(OBJS)
$(CC) $(LFLAGS) -o $@ $(OBJS)

作为在 BINS 列表中创建所有内容的方式,您将只创建相同的程序两次,有两个不同的名字。即使你想要这样做,做的方式它将是:

生成文件(三)

OBJS := main.o bar.o
BINS := prog1 prog2

.PHONY: all clean

all: $(BINS)

$(BINS): $(OBJS)
$(CC) -o $@ $(OBJS)

clean:
$(RM) $(OBJS) $(BIN)

运行方式如下:

$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog1 main.o bar.o
cc -o prog2 main.o bar.o

[1] 你可以让 GNU Make 向你展示它所有的内置规则,以及所有其他的它针对特定构建的规则,使用 make --print-data-base ...

关于c++ - 我的 makefile 不断 self 编译;我究竟做错了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54546486/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com