如何使用 main() 构造支持多个目标的生成文件

How to construct a makefile that support multiple targets with main()

本文关键字:目标 文件 支持 main 何使用      更新时间:2023-10-16

我有一个制作文件,在过去的几周里一直运行得很好。但是,现在我已经使用"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 $@ $<

我仍然不太了解制作文件...所以我不确定发生了什么。我得到这两个错误:

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 和目标,那里有什么?我所有的.cpp文件?我所有的可执行文件?
  • 我怎么喜欢两者在一起?

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

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

没有做你似乎认为它做的事情。 这将扩展到:

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

在这里并没有试图推断目标与先决条件的神奇匹配;相反,Make 会为每个目标再次重复整个规则,但要包含所有先决条件。 上面的规则与编写以下内容相同:

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

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

由于您的程序是从与程序名称具有相同前缀的单个对象文件构建的,因此您实际上根本不需要为它们编写规则;您可以依靠make的内置规则来构建程序。 只需完全排除上述规则,它应该可以工作。

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

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

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

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

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

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

截至目前,您的 Makefile 似乎是正确的,错误告诉您您声明了 2 个 main() 函数,一个在 rtngnode.cpp 文件中,另一个在管理器中.cpp,这不会发生,否则机器将不知道在执行程序时调用哪个函数。

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

这里有一个关于Makefiles的小教程,也可能是一个很好的阅读。