QT Creator Linker Error: Link2019 File Not Found

QT Creator Linker Error: Link2019 File Not Found

我不太确定我的问题出在哪里。

我正在为 OpenGL 项目使用 Qt Creator,这是我第一次尝试向我的项目中添加另外几个 classes。我添加了头文件和实现文件:terrain.h、terrain.cpp、imageloader.h 和 imageloader.cpp.

我认为我的问题出在我的 .pro 文件中:

HEADERS += glwidget.h \ 
imageloader.h \
terrain.h
SOURCES += glwidget.cpp main.cpp \
imageloader.cpp \
terrain.cpp

QT += opengl
CONFIG -= app_bundle
CONFIG += console c++11
INCLUDEPATH += "../include"
INCLUDEPATH += $$PWD

RESOURCES += shaders.qrc

当我运行 qmake时,没有错误。

然后,当我构建项目时(清理后,运行ning qmake),我得到以下错误:

glwidget.obj:-1: error: LNK2019: unresolved external symbol "private: static class Terrain * __cdecl GLWidget::loadTerrain(char const *,float)" (?loadTerrain@GLWidget@@CAPEAVTerrain@@PEBDM@Z) referenced in function "protected: virtual void __cdecl GLWidget::initializeGL(void)" (?initializeGL@GLWidget@@MEAAXXZ)

Qt Creator 还说:找不到文件 glwidget.obj

然而,问题似乎确实出在地形 class 上,或者它如何与 glwidget 交互。

当我删除所有对地形的引用时,构建工作正常。

然而,当我在 initializeGL() 方法中将以下行添加到 glwidget.cpp 时,出现 LINK2019 错误:

terrain = loadTerrain("test.bmp", 20);

terrain 在 glwidget.h 中定义为来自 terrain.cpp:

的 Terrain class 的一个实例
Terrain* terrain;

并且loadTerrain在glwidget.h中被定义为:

static Terrain* loadTerrain(const char* filename, float height);

有趣的是,即使注释掉 loadTeerain 的实现也会出现此错误。

以下是我尝试过的其他一些方法:

当我运行清理qmake之前或之后,或删除build文件夹中的.obj文件时,没有任何变化。我注意到重建项目时 glwidget.obj 和 terrain.obj 确实出现了。

感谢任何帮助。如果您想查看我的任何文件,请告诉我。

编辑:即使在使 loadTerrain() 方法成为非静态方法后问题仍然存在。

编辑 2 我似乎也忘记了它抛出的第二个错误,尽管我不确定这是否会有更多帮助:

debug\program2.exe:-1: error: LNK1120: 1 unresolved externals

debug 是 .obj 出现的文件夹,program2 是项目的名称。


已修复! 事实证明,使方法静态化是问题所在。你不能在头文件中声明一个静态方法,而这些方法将以我正在做的方式被多个源使用。我替换了:

static Terrain* loadTerrain(const char* filename, float height);

Terrain* GLWidget::loadTerrain(const char* filename, float height);

以及更改对该方法的后续调用。

感谢您的帮助!

您似乎缺少 glwidget.cpp 中函数 loadTerrain() 的实现:

Terrain* loadTerrain(const char* fileName, float height)
{
   // your implementation here
}

您可以查看 here 示例。

通过创建函数 static,您为其提供了内部链接。这意味着您的函数的定义只能在定义它的翻译单元中找到(即 terrain.cpp),而不是 main.cpp。删除静态关键字。

这很容易用 objdump 确认。假设你有 test.h:

#ifndef _TEST_H
#define _TEST_H

static void a_func();

#endif

test.cpp:

#include "test.h"

void a_func()
{
}

main.cpp:

#include "test.h"

void a_func()
{
}

int main()
{
}

您会注意到您不会收到函数重定义错误。我们可以分别编译每个文件来检查对象:

g++ -c test.cpp -o test.o 
g++ -c main.cpp -o main.o

两者都会显示 a_func:

Disassembly of section .text:

0000000000000000 <_ZL6a_funcv>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   90                      nop
   5:   5d                      pop    %rbp
   6:   c3                      retq

那么最终的二进制文件呢?

g++ main.o test.o

objdump -d ./a.out

00000000004005b6 <_ZL6a_funcv>:
  4005b6:   55                      push   %rbp
  4005b7:   48 89 e5                mov    %rsp,%rbp
  4005ba:   90                      nop
  4005bb:   5d                      pop    %rbp
  4005bc:   c3                      retq   

00000000004005bd <main>:
  4005bd:   55                      push   %rbp
  4005be:   48 89 e5                mov    %rsp,%rbp
  4005c1:   b8 00 00 00 00          mov    [=15=]x0,%eax
  4005c6:   5d                      pop    %rbp
  4005c7:   c3                      retq   

00000000004005c8 <_ZL6a_funcv>:
  4005c8:   55                      push   %rbp
  4005c9:   48 89 e5                mov    %rsp,%rbp
  4005cc:   90                      nop
  4005cd:   5d                      pop    %rbp
  4005ce:   c3                      retq   
  4005cf:   90                      nop

出现了两次!这就是为什么您不在要在多个翻译单元之间共享的头文件中将函数设为静态。