清除目标文件后 Make 不会重新编译
Make doesn't recompile after cleaning object files
我有以下生成文件:
compiler := g++
flags := -Wall -Wextra -Wpedantic -Werror -O2 -march=native
libs := sqlite3
build_dir := build
debug_dir := debug
source_dir := src
object_dir := obj
include_dir := include
objects := main.o politician.o data_base.o exceptions.o input.o
# Prepend object_dir/ to every object
objects := $(patsubst %, $(object_dir)/%, $(objects))
dependencies := data_base.hpp exceptions.hpp politician.hpp input.hpp CLI11.hpp
# Prepend include_dir/ to every dependency
dependencies := $(patsubst %, $(include_dir)/%, $(dependencies))
executable := politician
# Don't remove object files when finished
.SECONDARY: $(objects)
.PHONY: all
all: $(build_dir)/$(executable) | $(build_dir)
.PHONY: debug
debug: flags += -g
debug: $(debug_dir)/$(executable) | $(debug_dir)/
%/$(executable): $(objects)
$(compiler) $(flags) -l $(libs) $^ -o $@
$(object_dir)/%.o: $(source_dir)/%.cpp $(dependencies) | $(object_dir)/
$(compiler) $(flags) -I $(include_dir) -c $< -o $@
%/:
mkdir -p $@
.PHONY: clean
clean:
rm -f $(objects)
.PHONY: clean-all
clean-all:
rm -f $(objects) $(build_dir)/$(executable) $(debug_dir)/$(executable)
预计,在 运行 make clean
之后,make all
将重新编译所有内容(因为可执行文件依赖于对象并且它们不再存在),但这不是正在发生的事情:相反,我得到 make: Nothing to be done for 'all'.
是什么导致了这种行为?
发生这种情况是因为您正在使用一系列模式规则。
考虑一个简单的例子:
all: build/politician
build/politician: main.o
whatever...
main.o: src/main.cpp
whatever...
如果你 运行 make
,它将构建 main.o
,然后 build/politician
。如果您随后删除 main.o
并再次删除 运行 make
,它将再次构建 main.o
和 build/politician
.
现在将其中两个规则更改为模式规则:
all: build/politician
%/politician: main.o
whatever...
%.o: src/%.cpp
whatever...
现在您第一次 运行 make
,它将再次构建 main.o
然后 build/politician
。但是当你删除 main.o
并再次删除 运行 make
时,它会报告 "Nothing to be done for 'all'" 并且什么都不做。这是因为 main.o
现在是一个 中间文件 ,并且根据 the manual:
If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.
我有以下生成文件:
compiler := g++
flags := -Wall -Wextra -Wpedantic -Werror -O2 -march=native
libs := sqlite3
build_dir := build
debug_dir := debug
source_dir := src
object_dir := obj
include_dir := include
objects := main.o politician.o data_base.o exceptions.o input.o
# Prepend object_dir/ to every object
objects := $(patsubst %, $(object_dir)/%, $(objects))
dependencies := data_base.hpp exceptions.hpp politician.hpp input.hpp CLI11.hpp
# Prepend include_dir/ to every dependency
dependencies := $(patsubst %, $(include_dir)/%, $(dependencies))
executable := politician
# Don't remove object files when finished
.SECONDARY: $(objects)
.PHONY: all
all: $(build_dir)/$(executable) | $(build_dir)
.PHONY: debug
debug: flags += -g
debug: $(debug_dir)/$(executable) | $(debug_dir)/
%/$(executable): $(objects)
$(compiler) $(flags) -l $(libs) $^ -o $@
$(object_dir)/%.o: $(source_dir)/%.cpp $(dependencies) | $(object_dir)/
$(compiler) $(flags) -I $(include_dir) -c $< -o $@
%/:
mkdir -p $@
.PHONY: clean
clean:
rm -f $(objects)
.PHONY: clean-all
clean-all:
rm -f $(objects) $(build_dir)/$(executable) $(debug_dir)/$(executable)
预计,在 运行 make clean
之后,make all
将重新编译所有内容(因为可执行文件依赖于对象并且它们不再存在),但这不是正在发生的事情:相反,我得到 make: Nothing to be done for 'all'.
是什么导致了这种行为?
发生这种情况是因为您正在使用一系列模式规则。
考虑一个简单的例子:
all: build/politician
build/politician: main.o
whatever...
main.o: src/main.cpp
whatever...
如果你 运行 make
,它将构建 main.o
,然后 build/politician
。如果您随后删除 main.o
并再次删除 运行 make
,它将再次构建 main.o
和 build/politician
.
现在将其中两个规则更改为模式规则:
all: build/politician
%/politician: main.o
whatever...
%.o: src/%.cpp
whatever...
现在您第一次 运行 make
,它将再次构建 main.o
然后 build/politician
。但是当你删除 main.o
并再次删除 运行 make
时,它会报告 "Nothing to be done for 'all'" 并且什么都不做。这是因为 main.o
现在是一个 中间文件 ,并且根据 the manual:
If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.