我对GNU makefile的了解有限,但目前还没有让我失望。
我有一个类声明文件:mdfTree.h,类mdfTree.cpp的一个实现,以及一个带有main的mdfTree_x.cpp文件,我创建了一个类mdfTree的对象并调用它的公共函数,然后调用它们mdfTree的一些私有成员变量。
我正在用Makefile编译它:
CXX=g++
CXXFLAGS=-g -Wall -W -Wconversion -Wshadow -Wcast-qual -Wwrite-strings $(shell root-config --cflags --gl\
ibs)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
mdfTree_x: mdfTree_x.o
g++ $(LDFLAGS) -o mdfTree_x mdfTree_x.o $(LDLIBS)
mdfTree_x.o: mdfTree_x.cpp
g++ $(LDFLAGS) $(CXXFLAGS) -c mdfTree_x.cpp
mdfTree.cpp和mdfTree_x.cpp中有#include mdfTree.h
。 mdfTree_x.cpp也需要#include mdfTree.cpp
吗?
我认为我的Makefile是错误的,因为当我尝试编译时,类mdfTree中的公共函数无法看到同一个类的私有变量。此外,当我在mdfTree.h中插入语法错误时,编译器不会提取它。我怎么告诉Makefile mdfTree_x需要使用/编译mdfTree.h / .cpp?
答案 0 :(得分:2)
不需要调整你的make文件来编译和链接mdfTree.cpp。
像这样的东西
mdfTree.o: mdfTree.cpp
g++ $(LDFLAGS) $(CXXFLAGS) -c mdfTree.cpp
并将链接步骤更改为
mdfTree_x: mdfTree_x.o mdfTree.o
g++ $(LDFLAGS) -o mdfTree_x mdfTree_x.o mdfTree.o $(LDLIBS)
答案 1 :(得分:1)
您需要显式添加所有依赖项,在这种情况下,您的可执行文件依赖于已构建的mdfTree.o,mdfTree.o和mdfTree_x.o依赖于mdfTree.h。您的依赖应该是
mdfTree_x:mdfTree_x.o mdfTree.o
mdfTree.o:mdfTree.cpp mdfTree.h
mdfTree_x.o:mdfTree_x.cpp mdfTree.h
某些编译器(例如gnu& intel)能够自动列出make格式的标头依赖项。例如,当mdfTree_x.cpp
,mdfTree.cpp
或mdfTree.h
中的任何一个发生更改时,此makefile将重新生成可执行文件:
# Compiler flags...
CPPFLAGS+=-MMD -MP
mdfTree_x:mdfTree_x.o mdfTree.o
-include mdfTree_x.d mdfTree.d
CPPFLAGS将在编译时创建带有标头依赖性的.d文件,-include行将尝试将这些文件包含到makefile中(如果它们不存在,则无论如何都要重新编译源文件,所以额外的依赖无关紧要)。 .d文件的内容类似于
mdfTree.o:mdfTree.h
此外,在大多数情况下,您不需要显式编写make规则 - 例如,如果您将文件foo.o
列为依赖gnu make的默认规则将运行
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o foo.o foo.cpp
(和其他语言类似)。类似地,如果可执行文件名称与一个目标文件匹配,则链接是自动的。
foo:foo.o
将运行(注意CC不是CXX)
$(CC) $(LDFLAGS) -o foo foo.o $(LDLIBS)
使用默认规则可以使makefile更简单,还可以使用环境变量来设置默认编译器。
答案 2 :(得分:1)
我有一个类声明文件:mdfTree.h,类mdfTree.cpp的一个实现,以及一个带有main的mdfTree_x.cpp文件,我创建了一个类mdfTree的对象并调用它的公共函数,然后调用它们mdfTree的一些私有成员变量。
您的程序需要mdfTree.cpp和mdfTree_x.cpp中定义的功能。所以你需要编译这两个文件,你的链接需要包含mdfTree.o和mdfTree_x.o。
您可以编写两个规则,一个用于编译mdfTree.cpp,另一个用于编译mdfTree_x.cpp。这很快就会失控。是邪恶的。 一个规则来构建它们,一条规则来找到它们,一条规则将它们全部带入并在黑暗中绑定它们。
objects = mdfTree_x.o mdfTree.o
$(objects): %.o: %.cpp
g++ $(CXXFLAGS) -c $<
请注意,上述编译规则中没有$(LDFLAGS)
。编译时不应指定链接选项。
您需要链接对象以形成可执行文件:
mdfTree_x: $(objects)
g++ $(LDFLAGS) -o $@ $^ $(LDLIBS)
请注意,现在您需要指定链接器选项;你正在联系。
下一步之前的最后一点:一般来说,在makefile中指定规则的顺序无关紧要。但是有一个例外。第一个规则是默认规则,如果您未在make
命令中指定任何目标,则将使用该规则。明确地将默认规则放在makefile的最顶层附近是个好主意。例如,将以下内容放在makefile顶部附近,在任何其他规则之前:
default: mdfTree_x
mdfTree.cpp和mdfTree_x.cpp中包含#include mdfTree.h。 mdfTree_x.cpp是否也需要#include mdfTree.cpp?
从不 #include
源文件。决不。让链接器做到这一点。
然而,这里缺少一些东西。假设您更改了mdfTree.h。你需要重建。到目前为止,makefile不会这样做。缺少的是对mdfTree.h的依赖。在这种情况下,可以轻松解决此依赖性问题:只需指定依赖项。
$(objects): mdfTree.h
通常,此标头依赖性问题是一个非常难的问题。最好不要将这些头文件依赖项放在makefile中。让一些自动化工具(例如makedepend
)为您找出那些依赖项。