包含它时,Makefile依赖项文件错误

时间:2017-04-13 17:57:22

标签: makefile gnu-make

当我尝试在我的Makefile中包含C源文件时,我发现了问题。此C源文件包含一个由C ++代码(list.cpp)通过外部C链接选项调用的函数。我想知道Makefile中哪个是正确的位置来包含这个C源代码,其源代码在C ++代码中被调用。如果我尝试在Makefile的SOURCES变量中添加此C文件以构建它,那么C ++代码无法正确解析C的函数调用,并且我得到链接器错误:未定义的引用

以下是我的Makefile内容:

CFLAGS =-c -g -Wall -std=c++11
SOURCES = list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXEC = a.out

all: $(SOURCES) $(EXEC)

$(EXEC): $(OBJECTS)
    @$(CXX) $(OBJECTS) -o $@ && $(EXEC)

.cpp.o:
    @$(CXX) $(CFLAGS) $< -o $@

1 个答案:

答案 0 :(得分:1)

我们假设构建中需要的C源文件是bar.c, 并且它有一个关联的头文件bar.h #include list.cpp,并且您已正确编码extern C bar.h中的样板文件。

然后以下makefile将满足您的需求:

<强>生成文件

CXX_SOURCES := list.cpp
C_SOURCES := bar.c
OBJECTS = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)

CXXFLAGS := -g -Wall -std=c++11
CFLAGS := -g -Wall
CPPFLAGS :=
LDFLAGS :=
LDLIBS :=
EXEC := a.out

.PHONY: all clean test

all: $(EXEC)

test: $(EXEC)
    ./$<

$(EXEC): $(OBJECTS)
    $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)

list.o: bar.h

clean:
    rm -f $(EXEC) *.o

这里有很多学习要点:

1。使用立即评估(:=)而不是递归评估(=) 除非你特别想要递归评估,否则创建变量。看到 6.2 The Two Flavors of Variables

2. 如果目标只是任务的名称而不是文件的名称 任务将创建,然后它是phony target 你应该告诉make这是一个虚假的目标,如:

.PHONY: all clean test

3。构建程序运行程序的make-recipe是不正常的 好吧,就像你的:

@$(CXX) $(OBJECTS) -o $@ && $(EXEC)

你并不总是想要只是因为你已经构建了它而运行程序,并且 如果该程序是长期运行或交互式的那么这种方法 将使构建程序变得无法实现。

您可能希望运行程序 test 它已正确构建。 但是建设是一项任务,测试是另一项任务(可能需要更长的时间 涉及额外资源);所以你应该提供一个单独的假目标 用于检测。我在这个makefile中称它为test:通常它被称为check。 要在不测试的情况下构建程序,只需运行make即可。要测试它, 运行make test - 这将 (重新)构建程序,如果需要(重新)构建

4。您无需编写规则即可从name.o创建name.cpp,或者 从name.o制作name.c的规则。 GNU makebuiltin rules 这是正确的,只要你正确设置了make变量即可 make用于这些内置规则:

  • CC:调用C编译或链接的命令,例如gcc
  • CXX:调用C ++编译或链接的命令,例如g++
  • CFLAGS:C编译选项
  • CXXFLAGS:C ++编译选项
  • CPPFLAGS:C / C ++预处理器的选项

5. 具有传统含义的两个更重要的变量是:

  • LDFLAGS:链接选项,不包括库(-l)选项
  • LDLIBS:用于关联的图书馆选项(-l)。

在上面的简单makefile中,CPPFLAGSLDFLAGSLDLIBS不是 需要,可以省略。相反,我已经为它们分配了空值 只是为了说明它们的用途。

6。 makefile应该有一个删除任何文件的假目标clean makefile可能已创建,以便make clean获取 准备从头开始构建任何东西。

<强> 7 即可。如果name.o是从name.cname.cpp汇编的,那么。{ 课程name.o取决于name.c | name.cpp,但也取决于 在 name.c | name.cpp包含的每个头文件中,以及 makefile需要表达所有这些依赖项才能可靠地工作。所以 在这种情况下,您需要(至少)规则:

list.o: bar.h

因此,如果您更改bar.h,则make会看到foo.o已超出 日期并将执行重新制作foo.o的方法。当你 开始构建复杂的程序对你来说是不切实际的 自己弄清楚所有这些头文件依赖:然后你需要 了解自动依赖关系生成

这是the GNU Make manual