c++ - make 的自动依赖生成 .d 文件但不读取它们

标签 c++ makefile

我正在尝试为我的 C++ 程序编写一个生成自动依赖关系的生成文件。我查看了 this tutorial并且一直在查看 GNU make 手册。似乎 make 正在生成我的 .d 文件但不读取它们,或者它读取它们但由于某种原因不会使用它们。

我的项目包含以下目录:

  • .cpp 文件的 src
  • 包含 .hpp 文件
  • .d 文件的 makedeps
  • .o 文件的对象
  • 最终可执行文件的 bin

  • 这是我的生成文件:

    BIN=bin
    SRC=src
    INC=include
    DEP=makedeps
    OBJ=objects
    # sources are like 'src/main.cpp'
    sources=$(wildcard $(SRC)/*.cpp)
    # objects are like 'objects/main.o'
    objects=$(subst $(SRC),$(OBJ),$(sources:.cpp=.o))
    # dependencies are like 'makedeps/main.d'
    deps=$(subst $(SRC),$(DEP),$(sources:.cpp=.d))
    GPP=g++
    CPPFLAGS=-std=c++11
    LINKARGS=-L/usr/lib/x86_64-linux-gnu
    
    # used by the implicit rules that the dependency files use:
    CXX=$(GPP)
    
    $(BIN)/app.exe : $(objects)
        $(GPP) $(CPPFLAGS) $(LINKARGS) $(objects) -lcurl -o $(BIN)/app.exe
    
    # on the first pass this should fail, but it should discover how 
    # to build these dependencies and then build them and load them in.
    # once they are loaded in, it should know how to build the object files.
    -include $(deps)
    
    # this produces the dependency files, the sed command puts directory prefixes
    # before the files
    $(DEP)/%.d : $(SRC)/%.cpp
        @set -e; rm -f $@; \
        $(GPP) -I$(INC) -MM $(CPPFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,$(OBJ)/\1.o : ,g' < $@.$$$$ > $@; \
        rm -f $@.$$$$
    
    .PHONY:clean
    clean:
        rm -f $(OBJ)/*.o
        rm -f $(DEP)/*.d
        rm -f $(BIN)/*
    

    当我运行 make 时,它​​会在“makedeps”目录下生成所有依赖文件,这是它们的连接输出:

    objects/DownloadBuffer.o : src/DownloadBuffer.cpp include/DownloadBuffer.hpp
    objects/Downloader.o : src/Downloader.cpp include/Downloader.hpp \
     include/DownloadBuffer.hpp
    objects/main.o : src/main.cpp include/Downloader.hpp
    

    我在关于隐式规则的 GNU make 手册文档中发现了这一点:

    Compiling C++ programs: n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form ‘$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c



    这就是我在上面设置 CXX=$(GPP) 的原因。

    但是,没有生成目标文件。这是make输出:

    mike@ubuntu:~/NetBeansProjects/CppApplication_1$ make -f mk.mk clean
    rm -f objects/*.o
    rm -f makedeps/*.d
    rm -f bin/*
    mike@ubuntu:~/NetBeansProjects/CppApplication_1$ make -f mk.mk 
    g++ -std=c++11 -L/usr/lib/x86_64-linux-gnu objects/DownloadBuffer.o objects/Downloader.o objects/main.o -lcurl -o bin/app.exe
    g++: error: objects/DownloadBuffer.o: No such file or directory
    g++: error: objects/Downloader.o: No such file or directory
    g++: error: objects/main.o: No such file or directory
    make: *** [bin/app.exe] Error 1
    

    请注意,.d 文件首先被删除,并且我确认它们是在 make 运行时创建的。仔细阅读后this section on include directives ,我的印象是 make 应该(再次)尝试在创建这些 .d 文件后包含它们。

    有人可以解释为什么没有生成目标文件吗?

    最佳答案

    如果您的目标由于隐式规则查找的工作方式而具有路径分隔符,则不能依赖隐式规则,解决问题的最直接方法是在 $(BIN)/app.exe 之后提供显式配方

    $(objects):
        $(GPP) $(CPPFLAGS) $(CXXFLAGS) -c $^ -o $@
    

    也就是说,GCC 已经有了更好的依赖生成了一段时间,但看起来文档还没有跟上。您可以使用 -MMD 生成依赖项作为编译的副作用。这意味着您可以摆脱所有 sed crud(-MP 为标题添加虚拟目标以避免删除它们时出现问题)。

    你的 Makefile 看起来像这样

    BIN := bin
    SRC := src
    INC := include
    OBJ := objects
    
    app     := $(BIN)/app.exe
    sources := $(wildcard $(SRC)/*.cpp)
    objects := $(subst $(SRC),$(OBJ),$(sources:.cpp=.o))
    deps    := $(objects:.o=.d)
    
    CXX      := g++
    CPPFLAGS := -I $(INC) -MMD -MP
    CXXFLAGS := -std=c++11
    LDFLAGS  := -L /usr/lib/x86_64-linux-gnu
    LDLIBS   := -lcurl
    
    $(app) : $(objects)
        $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
    
    $(OBJ)/%.o: $(SRC)/%.cpp
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $^ -o $@
    
    .PHONY: clean
    clean: ; $(RM) $(objects) $(deps) $(app)
    
    -include $(deps)
    

    您可以从文件中看到的其他一些注释
  • 使用:=而不是 =除非你需要后者
  • 如果您的标题位于单独的文件夹中,则需要添加路径
  • 使用 GCC 的自动依赖生成器时,在与对象相同的目录中输出依赖会更简单。您可以使用 -MF 更改输出文件如有必要。
  • 您无需提供CPPFLAGS链接时,它不执行任何预处理。
  • 您可能应该坚持使用默认的链接器配方和变量(以及 CXX)。
  • 在配方中尽可能使用自动变量($@ 等)。

  • 如果你真的想使用隐式规则,你需要做一些事情,比如从你的目标文件中删除路径并预先更改为目标目录。

    关于c++ - make 的自动依赖生成 .d 文件但不读取它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25966411/

    相关文章:

    c++ - 使用firebreath的浏览器插件

    c++ - 在 vector 中查找对象,有多个要求

    opencv - 编译/链接 OpenCV Matlab 源文件时出错

    makefile - 如何使用makefile激活virtualenv?

    c++ - 如何避免具有更好抽象的typeid?

    C++平台兼容性

    c++ - 将 Makefile 选项添加到 qtcreator 项目中

    compilation - 如何并行化可以在多台机器上分配任务的 "make"命令

    vim - 在没有提示的情况下使用makefile和vim

    c++ - 读取文本文件并创建一个迷宫