Makefile的依赖项未正确考虑

Dependencies in Makefile not properly taken into account

本文关键字:依赖 Makefile      更新时间:2023-10-16

我对GNU Makefile的了解有限,目前使我失败了。

我有一个类声明文件:mdftree.h,class mdftree.cpp的实现和一个mdftree_x.cpp文件,其中我可以创建一个class 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?

no您需要调整您的文件以编译并链接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)

您需要明确添加所有依赖项,在这种情况下,您的可执行文件取决于构建的mdftree.o,并且mdftree.o and mdftree_x.o_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)能够自动以"制造格式"列出标题依赖项。例如,当更改mdfTree_x.cppmdfTree.cppmdfTree.h的任何一个时,此MakeFile将重新生成可执行文件:

# Compiler flags...
CPPFLAGS+=-MMD -MP
mdfTree_x:mdfTree_x.o mdfTree.o
-include mdfTree_x.d mdfTree.d

cppflags将在编译时创建一个带有标题依赖项的.D文件,如果存在,则包括 - include Line(如果不存在)依赖关系无关紧要)。.d文件的内容将是

mdfTree.o:mdfTree.h

另外,您无需在大多数情况下明确编写制定规则 - 例如,如果您将 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)

使用默认规则使makefiles更简单,还可以使用环境变量来设置默认编译器。

我有一个类声明文件:mdftree.h,class mdftree.cpp的实现和一个mdftree_x.cpp文件,其中我可以创建一个class 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)为您弄清楚这些依赖项。