我正在尝试为一个非常基本的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
文件?谢谢您提前提供帮助!
答案 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
感谢马特和雷诺的回答!