Makefile忽略包含的规则

时间:2019-03-20 01:27:15

标签: makefile

我正在尝试为一个非常基本的c ++程序创建一个makefile。我试图通过运行带有-M标志的g ++来实现依赖关系的自动生成,将此输出存储在.d文件中,然后将这些.d文件包含在我的主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文件,然后再将主要outfile创建为主要规则。但是,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生成g ++所需的.o文件?谢谢您提前提供帮助!

2 个答案:

答案 0 :(得分:1)

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

话虽这么说,我写了一个makefile来完成你想要的;它构建输出文件夹,生成依赖关系,并编译程序。我专门包括了$(COMPILE.cpp)定义,因此您可以看到它的组成。 $(CC)特别是C编译器,$(CFLAGS)特别是C编译器的标志。显然,它们只是变量,因此您可以像以前一样更改它们,并且可以正常工作,但是要记住的主要思想是,使用程序的人都希望能够按照自己的意愿配置编译。这意味着他们将设置$(CXX)$(CXXFLAGS),期望设置C ++编译器和标志。 $(CPPFLAGS)代表C / C ++预处理器标志。

这不是最干净的makefile,如果我要更改某些内容,我只需将目标文件编译到位,就可以避免麻烦。这样可以减少不必要的make hacking,但是为了回答您的问题,这里是。无论如何,我希望这对您有所帮助,如果您有任何疑问,请告诉我。


哦,是的,我差点忘了;请注意,我更改了您的make clean脚本。我使用了$(RM)而不是简单的rm -f。在makefile中使用实用程序时,您想use them as variables。同样,这是为了让您的用户在编译程序时拥有尽可能多的自由和灵活性。


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)

答案 1 :(得分:0)

对于任何有类似问题的人,这里的注释中都是正确的解决方案。为方便起见:包含的.d文件会生成依赖关系,但不会生成制作.o文件的方法,并且由于我将内容放置在各个目录中,因此默认规则在这里无效,因此{未创建{1}}个文件。解决方案是将以下规则添加到我的主makefile中。

.o

感谢马特和雷诺的回答!