【问题标题】:Makefile adds itself as targetMakefile 将自身添加为目标
【发布时间】:2010-11-24 11:33:07
【问题描述】:

我有一个使用自动依赖生成的 C++ 程序的 Makefile。 %.d 配方取自 GNU Make 手册。

问题是不知何故“Makefile”被添加为目标,然后一个隐式规则导致它假定它是一个可执行文件并使用我的 src/%.cpp 规则来尝试编译 src/Makefile.cpp。查看调试信息时,这总是发生在包含执行之后。

    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'.

我知道 include 会在必要时重建给定的 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)


【问题讨论】:

    标签: include makefile


    【解决方案1】:

    Make 总是会在执行 Makefile 之前尝试重新制作 Makefile。为此,make 将寻找可用于重新创建 Makefile 的规则。 Make 会寻找相当多的隐含规则和其他晦涩难懂的方法来(重新)创建 Makefile。

    在您的情况下,make 以某种方式决定应该使用模式规则 %.o: $(BUILD_DIR)/stamp 重新创建失败的 Makefile。

    为防止 make 重新制作 Makefile,您可以使用空配方编写规则:

    Makefile: ;
    

    阅读make手册中的Remaking Makefiles章节以获得更多解释。

    关于包含的 Makefile:无论目标如何,都将始终包含包含的 Makefile。如果包含的 makefile 丢失(或比它们的先决条件旧),那么它们将首先被(重新)创建。这意味着make clean 将首先生成.d Makefiles,然后再次删除它们。

    您可以通过将include 指令包装在条件中来防止包含特定目标:

    ifneq ($(MAKECMDGOALS),clean)
    include $(DEPENDENCIES)
    endif
    

    这是您的整个 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)
    

    【讨论】:

    • 附加建议:可以通过将include 包裹在ifneq (,$(filter-out clean,$(MAKECMDGOALS)) gnu.org/software/make/manual/make.html#Goals 中来防止在“make clean”中重制.d 文件
    • 太棒了!更改这些目标修复了它。将斜线留在目录变量的末尾是否被认为是更好的做法?我确信我已经看到了这两种方式。
    • @Jol。当斜杠在变量之外时,我发现它更容易阅读。把斜线想象成一个运算符。比较:FOO=a$(FOO)+b 而不是 FOO=a+$(FOO)b
    猜你喜欢
    • 2017-01-27
    • 2010-09-25
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 2020-10-06
    相关资源
    最近更新 更多