我有一个使用自动依赖项生成的C++程序的Makefile.%.d配方取自GNU Make手册.
问题是以某种方式将"Makefile"添加为目标,然后隐式规则使其假定它是可执行文件并使用我的src /%.cpp规则来尝试编译src/Makefile.cpp.查看调试信息时,这总是在执行include之后发生.
No need to remake target `build/Sprite.d'.
Considering target file `Makefile'.
Looking for an implicit rule for `Makefile'.
...
Trying pattern rule with stem `Makefile'.
Trying implicit prerequisite `Makefile.o'.
Looking for a rule with intermediate file `Makefile.o'.
Run Code Online (Sandbox Code Playgroud)
我知道包含原因如果需要,可以重建给定的Makefile.它是否也尝试重建当前的Makefile?如果是这样,我如何阻止它,如果没有,那么为什么"Makefile"被添加为目标呢?
此外,执行include,即使我在命令行上指定目标,也会重新生成.d文件,例如make clean.有没有办法阻止这种情况发生?
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src/
INCLUDE_DIR = include/
BUILD_DIR = build/
SOURCES = $(wildcard $(SOURCE_DIR)*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
include $(DEPENDENCIES)
%.o: $(BUILD_DIR)stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$@) -o $@
$(BUILD_DIR)%.d: $(SOURCE_DIR)%.cpp $(BUILD_DIR)stamp
@ echo Generate dependencies for $ $@.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $@ : ,g' $@; \
rm -f $@.$$$$
$(BUILD_DIR)stamp:
mkdir -p $(BUILD_DIR)
touch $@
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
@ echo $(SOURCES)
@ echo $(OBJECTS)
@ echo $(DEPENDENCIES)
Run Code Online (Sandbox Code Playgroud)
les*_*ana 12
Make将始终尝试在执行Makefile之前重新生成Makefile.为此,make将查找可用于重新创建Makefile的规则.Make将寻找相当多的隐式规则和其他模糊方法来(重新)创建Makefile.
在您的情况下,以某种方式决定%.o: $(BUILD_DIR)/stamp应该使用模式规则来重新创建失败的Makefile.
要防止make重新生成Makefile,您可以使用空配方编写规则:
Makefile: ;
Run Code Online (Sandbox Code Playgroud)
有关详细说明,请参阅制作手册中的Remaking Makefiles一章.
关于包含的Makefile:包含的Makefile将始终包含在内,无论目标如何.如果包含的makefile缺失(或者早于其先决条件),则首先(重新)创建它们.这意味着一个人make clean将首先生成.dMakefile,只是再次删除它们.
您可以通过将include指令包装在条件中来阻止包含特定目标:
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
Run Code Online (Sandbox Code Playgroud)
这是你的整个Makefile,有一些修复.我标记了我改变某些地方的地方.
# Makefile
# $(call setsuffix,newsuffix,files)
# Replaces all the suffixes of the given list of files.
setsuffix = $(foreach file,$2,$(subst $(suffix $(file)),$1,$(file)))
# $(call twinfile,newdir,newsuffix,oldfile)
# Turns a path to one file into a path to a corresponding file in a different
# directory with a different suffix.
twinfile = $(addprefix $1/,$(call setsuffix,$2,$(notdir $3)))
MAIN = main
SOURCE_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(call twinfile,$(BUILD_DIR),.o,$(SOURCES))
DEPENDENCIES = $(call twinfile,$(BUILD_DIR),.d,$(SOURCES))
CXX = g++
LIBS = -lpng
CXXFLAGS = -I $(INCLUDE_DIR)
.PHONY: all
all: $(MAIN)
$(MAIN): $(OBJECTS)
$(CXX) $(LIBS) $^ -o $(MAIN)
# -------> only include if goal is not clean <---------
ifneq ($(MAKECMDGOALS),clean)
include $(DEPENDENCIES)
endif
# ---------> fixed this target <--------------
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
$(CXX) $(CXXFLAGS) -c $(call twinfile,$(SOURCE_DIR),.cpp,$@) -o $@
# ---------> and this target <---------------
$(BUILD_DIR)/%.d: $(SOURCE_DIR)/%.cpp $(BUILD_DIR)/stamp
@ echo Generate dependencies for $@;
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,$(BUILD_DIR)\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
$(BUILD_DIR)/stamp:
mkdir -p $(BUILD_DIR)
touch $@
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
.PHONY: printvars
printvars:
@ echo $(SOURCES)
@ echo $(OBJECTS)
@ echo $(DEPENDENCIES)
Run Code Online (Sandbox Code Playgroud)