如何用main()构造支持多个目标的makefile

时间:2014-03-05 07:04:20

标签: c++ ubuntu makefile g++

我有一个makefile,过去几周一直很好用。但是,现在我已经用“main”向我的项目中添加了另一个目标,它开始有点翻转。

CC=g++
CCOPTS=-g -w

OBJS = $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
TARGETS = $(BINDIR)/manager $(BINDIR)/rtngnode
BINDIR = build

all: $(TARGETS) $(OBJS)

clean:
    rm -f $(TARGETS) $(OBJS)

.PHONY: all clean

$(TARGETS): $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

$(BINDIR)/%.o: %.cpp
    $(CC) -c $(CCOPTS) -o $@ $<

我还不太了解makefile ...所以我不确定发生了什么。我得到了这两个错误:

build/rtngnode.o: In function `__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, Node> > >::new_allocator()':
/home/caleb/Documents/dev/tote2/mp2/rtngnode.cpp:5: multiple definition of `main'
build/manager.o:/home/caleb/Documents/dev/tote2/mp2/manager.cpp:161: first defined here
build/manager.o: In function `main':

manager.cpp:(.text+0xefb): undefined reference to `NetworkConnection::NetworkConnection(char const*, char const*)'

在我的rtngnode目标中,我对tcpcon班级有依赖关系......我的manager目标也有main()个参考号。我很困惑......所以我甚至不确定我是否提出了正确的问题。

我想我的问题是:

  • 对于OBJS和TARGETS,那里有什么?我所有的.cpp文件?我的所有可执行文件?
  • 我如何将两者结合在一起?

4 个答案:

答案 0 :(得分:1)

您应该将您的可执行文件与一个包含“main”函数的源文件绑定在一起。

正如链接器告诉你的那样,manager.cpp和rtngnode.cpp都有main函数的定义。您可能不希望将它们组合在一起。我建议你从使用gcc命令手动构建代码开始(使用gcc -c生成目标文件,使用gcc -o生成可执行文件)。一旦你理解了那里的逻辑 - 继续编写makefile。

顺便说一下,如果你可以选择你的构建环境 - 从cmake开始,它比makefile更不含神秘。

答案 1 :(得分:1)

其他答案都是准确的,但我认为要理解的关键是这条规则:

$(TARGETS): $(OBJS)
        $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

不会做你认为它做的事情。这扩展到:

$(BINDIR)/manager $(BINDIR)/rtngnode : $(BINDIR)/manager.o $(BINDIR)/rtngnode.o
        $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

Make并不试图在这里推断出一些神奇的目标匹配与先决条件;而是为每个目标再次重复整个规则,但具有所有先决条件。上面的规则与写这个规则相同:

$(BINDIR)/manager : $(OBJS)
        $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

$(BINDIR)/rtngnode : $(OBJS)
        $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

鉴于此,您可以看到问题所在:您正在尝试将所有对象链接到EACH可执行文件中。

由于您的程序是使用与程序名称具有相同前缀的单个目标文件构建的,因此您实际上根本不需要为它们编写规则;你可以依靠make的内置规则来构建程序。完全按照上述规则进行操作即可。

答案 2 :(得分:0)

这里最重要的是与你的Makefile无关(除了有点缺乏编译器警告之外,它看起来相当不错):

您的项目中,所有源文件中只有一个 main()

答案 3 :(得分:0)

所以基本上,TARGETS应该包含你的源文件(.cpp),然后编译它们来创建目标文件,这些文件应该在OBJS变量中,然后将它们传递给链接器以创建可执行文件。

现在你的Makefile看起来是正确的,错误告诉你你有2个main()函数声明,一个在rtngnode.cpp文件中,另一个在manager.cpp中,这不会发生,否则机器不会知道程序执行时要调用哪一个。

由于链接器错误,大多数情况下也会出现未定义的引用错误,大多数情况下,当您使用#include将库包含到编译器中时,通常会使用makefile中的LIBS变量将链接器包含在链接器中。

HERE是一个关于Makefiles的小教程,也可以是一个很好的阅读。