为什么这个 makefile 在“make clean”上执行目标?

发布于 2024-09-19 12:32:36 字数 1298 浏览 7 评论 0原文

这是我当前的 makefile。

CXX      = g++
CXXFLAGS = -Wall -O3
LDFLAGS  =

TARGET = testcpp
SRCS   = main.cpp object.cpp foo.cpp
OBJS   = $(SRCS:.cpp=.o)
DEPS   = $(SRCS:.cpp=.d)


.PHONY: clean all

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)

.cpp.o:
    $(CXX) $(CXXFLAGS) -c $< -o $@

%.d: %.cpp
    $(CXX) -M $(CXXFLAGS) $< > $@

clean:
    rm -f $(OBJS) $(DEPS) $(TARGET)

-include $(DEPS)

除了一个例外,它工作得很好。如果目录已经干净(没有 *.d,*.o)并且我运行“make clean”,它会重新创建依赖项,然后立即删除它们:

[user@server proj]$ make
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
g++ -Wall -O3 -c main.cpp -o main.o
g++ -Wall -O3 -c object.cpp -o object.o
g++ -Wall -O3 -c foo.cpp -o foo.o
g++ -Wall -O3  main.o object.o foo.o -o testcpp
[user@server proj]$ make clean
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user@server proj]$ make clean
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user@server proj]$

我不明白为什么第二个“make clean”会重新- 生成依赖文件。我怎样才能避免这种情况?对于这个人为的示例来说这并不是什么大问题,但对于大型项目来说,这可能非常耗时。

谢谢。

This is my current makefile.

CXX      = g++
CXXFLAGS = -Wall -O3
LDFLAGS  =

TARGET = testcpp
SRCS   = main.cpp object.cpp foo.cpp
OBJS   = $(SRCS:.cpp=.o)
DEPS   = $(SRCS:.cpp=.d)


.PHONY: clean all

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)

.cpp.o:
    $(CXX) $(CXXFLAGS) -c 
lt; -o $@

%.d: %.cpp
    $(CXX) -M $(CXXFLAGS) 
lt; > $@

clean:
    rm -f $(OBJS) $(DEPS) $(TARGET)

-include $(DEPS)

It works perfectly with one exception. If the directory is already clean (no *.d, *.o) and I run 'make clean', it re-creates the dependencies, then immediately deletes them:

[user@server proj]$ make
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
g++ -Wall -O3 -c main.cpp -o main.o
g++ -Wall -O3 -c object.cpp -o object.o
g++ -Wall -O3 -c foo.cpp -o foo.o
g++ -Wall -O3  main.o object.o foo.o -o testcpp
[user@server proj]$ make clean
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user@server proj]$ make clean
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user@server proj]$

I don't understand why the second 'make clean' would re-generate the dependency files. How can I avoid this? This isn't a big deal for this contrived example, but for a large project, it can be quite time-consuming.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ゃ懵逼小萝莉 2024-09-26 12:32:36

这是因为 .d 文件被无条件 -included。据 make 所知,他们可以向 clean 目标添加依赖项或命令。由于这个原因,所有 included 文件都会首先构建,否则您可能会得到不正确或失败的构建。要禁用此功能,您需要有条件地包含依赖项文件:

ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif

另一种解决方案是使用 touch 生成依赖项文件,并将它们替换为实际数据,作为编译的副作用。这就是 automake 进行依赖项跟踪的方式,因为它使一次性构建速度更快。如果您想走这条路,请查看 gcc-MD-MMD 选项。使用如下模式规则:

%.d:
    @touch $@

最初创建依赖文件。

It's because the .d files are being -included unconditionally. As far as make knows, they could add dependencies or commands to the clean target. All included files are built first for this reason, otherwise you might get an incorrect or failed build. To disable this, you want to conditionally include the dependency files:

ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif

An alternative solution is to generate the dependency files using touch and have them replaced by actual data as a side-effect of compilation. This is how automake does its dependency tracking, as it makes one-time builds faster. Look into the -MD and -MMD options to gcc if you want to go this route. Use a pattern rule like:

%.d:
    @touch $@

To initially create the dependency files.

终止放荡 2024-09-26 12:32:36

如果您想跳过多个目标的包含,可以使用filter函数。

MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc

# Include only if the goal needs it
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
  -include $(DEPS)
endif

If you want to skip the include for multiple targets, you can use the filter function.

MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc

# Include only if the goal needs it
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
  -include $(DEPS)
endif
路还长,别太狂 2024-09-26 12:32:36

它想要重新生成依赖文件,因为它总是在执行其他操作之前尝试重新生成所有 makefile,包括 -include 的 makefile。 (好吧,实际上,对我来说它并没有这样做 - 我有 GNU Make 3.81 - 所以也许这是你的版本中已修复的错误,或者是我的版本有而你的版本没有的优化。但无论如何。

)解决这个问题的方法是编写规则,以便它们生成 .d 文件作为常规编译的副作用,而不是给出明确的规则来生成它们。这样,当它们不存在时,Make 不知道如何生成它们,因此它不会尝试(在干净的树中,.cpp.o 规则就足够了,您不需要需要 头文件依赖项)。查看 Automake 生成的 makefile(一个简单的文件),看看它是如何完成的。

It wants to regenerate the dependency files because it always tries to regenerate all of the makefiles, including -include'd makefiles, before doing anything else. (Well, actually, for me it doesn't do that - I have GNU Make 3.81 - so maybe it's a bug in your version that was fixed, or an optimization that mine has and yours doesn't. But anyway.)

The easiest way around this is to write your rules so they generate the .d files as a side effect of regular compilation, rather than giving explicit rules to generate them. That way, when they're not there, Make doesn't know how to generate them so it doesn't try (in a clean tree, the .cpp.o rules are enough, you don't need the header file dependencies). Look at an Automake-generated makefile -- a simple one -- to see how it's done.

以往的大感动 2024-09-26 12:32:36

-include 中的前导 - 表示如果依赖项缺失且无法执行,make 不会抱怨被重制,但这并不意味着它不会首先尝试制作它们(并且在这种情况下会成功) - 毕竟,任何有趣或重要的都可以 > 在包含的文件中,让我们尝试制作它们。我认为没有办法阻止这种情况。

有关 include-include 的文档,请参阅 此处

The leading - in -include means that make won't complain if the dependencies are missing and can't be remade, but it doesn't mean it won't try to make them first (and, in this case, succeed) -- after all, anything interesting or important could be in the included files, whence the let's-try-making them attempt. I don't think there's a way to stop that.

For docs on include and -include, see here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文