首页 > 解决方案 > Makefile忽略包含的规则

问题描述

我正在尝试为一个非常基本的 c++ 程序创建一个生成文件。我试图通过使用 -M 标志运行 g++ 来实现依赖项的自动生成,将此输出存储在一个.d文件中,然后将这些.d文件包含在我的主 makefile 中。makefile 内容如下

CC=g++
CPPFLAGS=-Wall -Wextra -g -std=c++11

SOURCEDIR=src
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)

BUILDDIR=build
OBJDIR=$(BUILDDIR)/objs
OBJS=$(SOURCES:$(SOURCEDIR)/%.cpp=$(OBJDIR)/%.o)
DEP_FILES = $(OBJS:.o=.d)

OUTFILE=hello.out


$(OUTFILE) : $(OBJS)
    $(CC) -o $@ $^ $(CPPFLAGS)

include $(DEP_FILES)
$(OBJDIR)/%.d : $(SOURCEDIR)/%.cpp
    $(CC) $(CPPFLAGS) $< -MM -MT $(@:.d=.o) > $@

$(DEP_FILES) : | $(OBJDIR)
$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)


.PHONY: clean
clean:
    rm -f $(BUILDDIR) -r
    rm -f *~ 
    rm -f $(OUTFILE)

当我运行make时,会生成目录build/objs/并生成一个.d包含规则的文件。这是main.d文件:

build/objs/main.o: src/main.cpp src/main.h

这是myfunc.d文件:

build/objs/myfunc.o: src/myfunc.cpp src/main.h

这是问题 由于我在这些 .d 文件上调用 include ,我希望随后创建它们指定的 .o 文件,然后将主输出文件创建为主要规则。但是,make 创建.d文件,然后直接跳到主编译步骤而不创建任何 .o 文件:

g++ -o hello.out build/objs/myfunc.o build/objs/main.o -Wall -Wextra -g -std=c++11

这将失败并出现以下错误,因为.o从未创建文件:

g++: error: build/objs/myfunc.o: No such file or directory
g++: error: build/objs/main.o: No such file or directory
g++: fatal error: no input files

如何使用此 makefile 生成.og++ 所需的文件?感谢您提前提供任何帮助!

标签: makefile

解决方案


我看到你的 makefile 可以正常工作,但我只是想添加一些你可能想要为未来项目考虑的东西。我建议使用 vpath 变量,而不是$(OBJDIR)/%.o在您的 makefile 配方中指定。我实际上在某处读到,在单独的目录中构建目标文件不是“大炮”,但是在发布之前进行的粗略搜索中,我找不到该文档。

话虽这么说,我写了一个makefile来做你想做的事;它构建输出文件夹、生成依赖项并编译程序。我特别包含了$(COMPILE.cpp)定义,所以你可以看到它是由什么组成的。$(CC)特别是 C 编译器,特别是 C 编译器$(CFLAGS)的标志。很明显,它们只是变量,因此您可以像以前那样更改它们并且它会正常工作,但要记住的主要想法是,使用您的程序的人都希望能够按照他们认为合适的方式配置编译。这意味着他们将设置$(CXX)$(CXXFLAGS)期望设置 C++ 编译器和标志。$(CPPFLAGS)代表 C/C++ 预处理器标志。

它不是最干净的 makefile,如果我要更改某些内容,我只需将目标文件编译到位,就可以省去头疼的问题。这减少了不必要的黑客攻击,但为了回答您的问题,这里是。无论如何,我希望这对您有所帮助,如果您有任何问题,请告诉我。


哦,是的,我差点忘了;请注意我更改了您的make clean脚本。我用$(RM)的不是简单的rm -f. 当您在 makefile 中使用实用程序时,您希望将它们用作变量。同样,这是为了让您的用户在编译您的程序时尽可能多地自由和灵活。


vpath %.cpp src
vpath %.hpp include
vpath %.o build/objs
vpath %.d build/objs

.SUFFIXES:
.SUFFIXES: .cpp .hpp .o .d

SRCDIR          = src
INCLUDESDIR     = include
BUILDDIR        = build
OBJDIR          = $(BUILDDIR)/objs

SRCS            = $(wildcard $(SRCDIR)/*.cpp)
OBJS            = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
DEP_FILES       = $(patsubst %.o, %.d, $(OBJS))

INCLUDE_DIRS    = -I $(INCLUDESDIR)

CXX             = g++
CPPFLAGS        = 
CXXFLAGS        = -Wall -Wextra -g -std=c++11

PROGRAM         = hello.out

COMPILE.cpp     = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(TARGET_ARCH)

all: $(PROGRAM)

$(PROGRAM): %: $(OBJS)
    $(LINK.cpp) $(INCLUDE_DIRS) $(addprefix $(OBJDIR)/, $^) $(LOADLIBES) $(LDLIBS) -o $@

%.o: %.cpp
    $(COMPILE.cpp) -c -o $(OBJDIR)/$@ $<

%.d: %.cpp
    mkdir -p $(OBJDIR)
    $(COMPILE.cpp) $^ -MM -MT $(addprefix $(OBJDIR)/, $(@:.d=.o)) > $(OBJDIR)/$@

include $(DEP_FILES)

.PHONY: clean
clean:
    @echo $(RM)
    $(RM) $(BUILDDIR) -r
    $(RM) *~ 
    $(RM) $(PROGRAM)

推荐阅读