0

我对 GNU makefile 的了解有限,目前这让我很失望。

我有一个类声明文件:mdfTree.h,一个类 mdfTree.cpp 的实现,以及一个 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?

4

3 回答 3

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)
于 2012-10-23T12:15:36.213 回答
1

我有一个类声明文件:mdfTree.h,一个类 mdfTree.cpp 的实现,以及一个 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)

请注意,现在您确实需要指定链接器选项;你正在链接。

下一步之前的最后一点:您在生成文件中指定规则的顺序通常无关紧要。然而,有一个例外。第一条规则是默认规则,如果您在命令中根本没有指定任何目标,则将使用该规则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为您找出这些依赖关系。

于 2012-10-23T12:55:37.613 回答
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.cppmdfTree.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 更简单,并且还允许您使用环境变量来设置默认编译器。

于 2012-10-23T12:34:04.600 回答