代码之家  ›  专栏  ›  技术社区  ›  Robert S. Barnes Antoni

使用-mm生成include指令和依赖项

  •  4
  • Robert S. Barnes Antoni  · 技术社区  · 15 年前

    如果include的目标已过期或不存在,我希望由include指令触发生成规则。

    当前生成文件如下所示:

    program_NAME := wget++
    program_H_SRCS := $(wildcard *.h)
    program_CXX_SRCS := $(wildcard *.cpp)
    program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
    program_OBJS := $(program_CXX_OBJS)
    
    DEPS = make.deps
    
    .PHONY: all clean distclean
    
    all: $(program_NAME) $(DEPS)
    
    $(program_NAME): $(program_OBJS)
        $(LINK.cc) $(program_OBJS) -o $(program_NAME)
    
    clean:
        @- $(RM) $(program_NAME)
        @- $(RM) $(program_OBJS)
        @- $(RM) make.deps
    
    distclean: clean
    
    make.deps: $(program_CXX_SRCS) $(program_H_SRCS)
        $(CXX) $(CPPFLAGS) -MM $(program_CXX_SRCS) > make.deps
    
    include $(DEPS)
    

    问题是,似乎include指令在生成make.deps的规则之前执行,这实际上意味着make在make.deps不存在时不获取依赖项列表,或者总是从以前的生成中获取make.deps,而不是从当前的生成中获取make.deps。

    例如:

    $ make clean 
    $ make
    makefile:32: make.deps: No such file or directory
    g++  -MM addrCache.cpp connCache.cpp httpClient.cpp wget++.cpp > make.deps
    g++    -c -o addrCache.o addrCache.cpp
    g++    -c -o connCache.o connCache.cpp
    g++    -c -o httpClient.o httpClient.cpp
    g++    -c -o wget++.o wget++.cpp
    g++      addrCache.o connCache.o httpClient.o wget++.o -o wget++
    

    编辑

    我读了 docs for the include directive ,如果include目标不存在,它将继续处理父makefile,尝试构建目标,但我不完全清楚这是如何工作的:

    如果包含的makefile不能 在这些目录中的任何一个中,都可以找到 生成了警告消息,但它 不是立即致命的错误; 处理包含 包含继续。一旦有了 读取完makefiles,make will 尝试重新制作任何过时的 或者不存在。见“如何”一节 重新生成生成文件。只有在它之后 试图找到一种方法来重建 生成文件并失败,将生成 将丢失的生成文件诊断为 致命错误。

    回答

    这是对我接受的答案的修改。缺少的一件事是依赖项文件也依赖于源,除非将它们添加到包含的DEPS文件中,否则将无法重新生成:

    %.d: $(program_CXX_SRCS)
        @ $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@
    

    sed 添加的名称 .d 文件到每个依赖行的开头,如下所示:

    foo.d foo.o: foo.cpp foo.h bar.h baz.h
    

    我从这篇关于递归制造的危险的神奇论文中得到了这个想法:

    Recursive Make Considered Harmful

    我还将以下内容添加到makefile中:

    clean_list += ${program_SRCS:.c=.d}
    
    # At the end of the makefile
    # Include the list of dependancies generated for each object file
    # unless make was called with target clean
    ifneq "$(MAKECMDGOALS)" "clean"
    -include ${program_SRCS:.c=.d}
    endif
    
    3 回复  |  直到 15 年前
        1
  •  2
  •   Didier Trosset    15 年前

    您正依赖隐式规则来编译.cpp文件。您必须重新定义它才能使用将创建依赖文件的-mm和-mf标志。

    %.o: %.cpp
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ -MM -MF $@.d
    

    然后,您必须在makefile中包含这些依赖项文件,使用 -include 当依赖项文件尚不存在时(第一次或清除后),这不会出错。

    program_DEPS := $(program_OBJS:.o=.o.d)
    -include $(program_DEPS)
    

    记住在clean规则中为依赖文件添加rm命令。

        2
  •  2
  •   Beta    15 年前

    我花了一段时间才明白的一个重要点是 以前版本的make.deps已经足够好了 . 考虑一下:对于一个给定的对象文件,依赖文件列表唯一可以改变的方法是…其中一个旧的依赖项文件已被更改。如果是这样,那么旧的make.deps将导致重建该对象文件,如果重建该对象文件也会重建make.deps,那么一切都将是最新的。 在检查必须重新生成哪些对象之前,不必重新生成make.deps。

        3
  •  0
  •   anon    15 年前

    包含指令就像在C和C++中那样工作——它们在任何其他事情发生之前都被处理,以构建然后处理的“真实”Mag文件。具体来说,它们是在任何规则被触发之前被处理的。