【问题标题】:C++ undefined reference in MakefileMakefile 中的 C++ 未定义引用
【发布时间】:2020-12-03 14:05:06
【问题描述】:

我为一个简单的程序创建了我的 Makefile,但它不断返回类函数的未定义引用:

g++ -c src/main.cpp -o lib/main.o
g++ -c src/functions.cpp -o lib/functions.o
g++ -c src/Circular.cpp -o lib/Circular.o
g++ lib/main.o -o bin/app.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: lib/main.o:main.cpp:(.text+0x20): undefined reference to `Circular::Circular()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [app.exe] Error 1

这是我的 Makefile:

app.exe: lib/main.o lib/Circular.o lib/functions.o
g++ lib/main.o -o bin/app.exe

lib/functions.o: src/functions.cpp
g++ -c src/functions.cpp -o lib/functions.o

lib/Circular.o: src/Circular.cpp
g++ -c src/Circular.cpp -o lib/Circular.o

lib/main.o: src/main.cpp
g++ -c src/main.cpp -o lib/main.o

这是 main.cpp 的简短 sn-p:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <string>


#include "../include/Circular.h"
#include "../include/functions.h"

using namespace std;

int main(int argc, const char * argv[]) {

     Circular item;
     return 0;
 }

Circular.h:

#include "node.h"


class Circular
{
    public:
        Circular();
        
        node *start;
        node *last;
        int counter;
}

Circular.cpp:

#include "../include/Circular.h"
#include <iostream>

using namespace std;


Circular::Circular()
{
    start = NULL;
    last = NULL;            
}

和node.h:

struct node
{
    int data;
    struct node *next;
    struct node *prev;
};

我知道问题在于链接器和 Makefile,但即使我尝试了不同的可能解决方案,但不知何故它不起作用。因此,也许有人可以看到我正在犯的错误。谢谢!

【问题讨论】:

  • 提示:在 C++ 中使用 nullptr 而不是 C 的 NULL
  • 为什么main.o 有这么多依赖?它应该只有src/main.cpp。每个文件可以也有头文件依赖,但是如果没有自动化,维护起来会很麻烦。此外,main.exe 应该列出依赖项及其完整路径,例如 lib/main.o 而不仅仅是 main.o
  • 这个Makefile 和正在运行的不匹配。请注意构建命令g++ lib/main.o lib/main.o lib/functions.o -o bin/app.exe,其中包含main.o 两次并省略Circular
  • 您可能还需要指定 .o 文件的路径,例如 lib/main.o: ... 而不仅仅是 main.o: ... 我还要删除所有 .o 文件以确保您没有编译陈旧资产。
  • 我删除了旧的 .o 文件并再次运行 make.exe 并给我错误:make.exe: *** No rule to make target `lib/main.o', needed by `app.exe'. Stop. 你的意思是将 main.o: 也更改为 lib/main.o

标签: c++ gcc makefile


【解决方案1】:

Makefile 应该被构造成构建依赖关系,然后最终组装成一个.exe。每条路径都应完全按原样指定,而不是近似:

app.exe: lib/main.o lib/Circular.o lib/functions.o 
  g++ lib/main.o lib/Circular.o lib/functions.o -o app.exe

lib/main.o: src/main.cpp
  g++ -c src/main.cpp -o lib/main.o

lib/functions.o: src/functions.cpp
  g++ -c src/functions.cpp -o lib/functions.o

lib/Circular.o: src/Circular.cpp
  g++ -c src/Circular.cpp -o lib/Circular.o

这里的关键是保持一致,其中包括此文件中指定的事物顺序之类的内容。无论你选择什么顺序,坚持下去。这使得追踪问题变得更加容易。

如果这个项目变得更复杂,您可能希望转而使用dependency tracking Makefile template 而不是这个自制软件。请注意,您不需要为每个文件指定规则,而是为文件的每种类型指定规则,如.cpp -> .o,其余的会自动发生.

【讨论】:

  • 我使用了完全相同的 Makefile 但错误仍然相同:c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: lib/main.o:main.cpp:(.text+0x20): undefined reference to `Circular::Circular()'
  • 它运行了哪个g++ 命令?我希望您能够阅读该输出并检查其链接是否正确。如果没有,请关注该特定行。
  • 我在这一行得到错误:g++ lib/main.o -o bin/app.exe
  • 这不是这个Makefile 运行的命令,所以你在这里做了一些非常奇怪的事情。这甚至没有引用bin/app.exe,所以你必须有一些不同的东西。
  • 我正在使用 Windows,由于 make 在 Windows 中不起作用,所以下载了这个:gnuwin32.sourceforge.net/packages/make.htm 并将 make.exe 复制到 Makefile 所在的项目文件中,然后我运行它,如果你是这个意思。
【解决方案2】:

我设法从 this source 创建了一个 Makefile。

Makefile 看起来像这样:

CXX = g++
CXXFLAGS = -std=c++17 -Wall
LXXFLAGS = -std=c++17
OBJECTS = main.o Circular.o functions.o
TARGET = main

$(TARGET): $(OBJECTS)
    $(CXX) $(LXXFLAG) $(OBJECTS) -o $(TARGET)
main.o: main.cpp Circular.cpp Circular.h functions.cpp functions.h
    $(CXX) $(CXXFLAGS) -c main.cpp
Circular.o: Circular.cpp 
    $(CXX) $(CXXFLAGS) -c Circular.cpp
functions.o: functions.cpp 
    $(CXX) $(CXXFLAGS) -c functions.cpp
clean:
    rm -f $(TARGET) $(OBJECTS)

并且还为你添加了cout 循环构造函数来检查执行如下:

#include "Circular.h"
#include <iostream>

using namespace std;


Circular::Circular()
{
    start = NULL;
    last = NULL;   
    cout << "Yes!" << endl;     
}

结果如下: Output
不要忘记在 Circular.h 中为 Circular 类添加 分号
注意:如果您无法在 cmd 中使用 make,请使用 choco install make

【讨论】:

  • -c 添加到CXXFLAGS 变量中是一种反模式。这应该出现在规则中。 CXXFLAGS 变量也应该放在链接行上,因为某些标志对链接器也有意义(例如 -g-pthread 等)。此外,您不需要 Circular.cpp 作为先决条件main.o.
  • @MadScientist 你对-c 标志是完全正确的。虽然,链接器的任何重要标志都可以在LXXFLAGS 中添加。此外,我添加了Circular.cpp,所以如果有任何变化Circular.cpp 而不是在 main.cpp 内,那么目标文件将被重新生成。
  • 如果Circular.cpp有变化,那么你不需要重建main.o。你需要重建Circular.o,这是由于它的规则而发生的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
  • 2018-05-25
  • 1970-01-01
相关资源
最近更新 更多