【问题标题】:QT Creator Linker Error: Link2019 File Not FoundQT Creator 链接器错误:找不到 Link2019 文件
【发布时间】:2016-04-27 05:39:15
【问题描述】:

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

我正在将 Qt Creator 用于 OpenGL 项目,并且第一次尝试在我的项目中添加另外几个类。我添加了头文件和实现文件: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 时,没有错误。

然后,当我构建项目时(清理后,运行 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 还说:File Not Found glwidget.obj

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

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

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

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

terrain 在 glwidget.h 中定义为 terrain.cpp 中的 Terrain 类的一个实例:

Terrain* terrain;

而loadTerrain在glwidget.h中定义为:

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

有趣的是,即使注释掉了 loadTeerin 的实现,也会出现这个错误。

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

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

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

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

EDIT 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);

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

感谢您的帮助!

【问题讨论】:

  • 您似乎错过了 cpp 文件中 loadTerrain 的实现?
  • 我确实注释掉了一个实现,但是取消注释似乎没有帮助。
  • 注释掉实现意味着你没有实现。您能否发布更新的头文件和源文件的相关部分?
  • 你现在收到同样的错误吗?
  • 我正要回复请求的代码行,但这让我意识到了问题所在。当我将方法设为非静态并取消注释实现时,我将其作为对 loadTerrain 的调用和声明,而不是 GLWidget::loadTerrain。现在看来问题已经解决了!谢谢你的帮助!我在这个问题上花了很长时间。

标签: c++ qt linker qt-creator header-files


【解决方案1】:

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

这很容易通过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    $0x0,%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

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

【讨论】:

  • 将方法设为静态会导致问题是有道理的。但是,我将其设为非静态,清理项目,运行 qmake,然后重新构建,问题仍然存在......
  • 忽略我最后的评论。一旦我使它成为非静态的,我必须记住在方法调用、声明和实现中添加 GLWidget:: 前缀。一旦我这样做并重新运行 qmake,它就起作用了!我在这个问题上花了很多时间。感谢您的帮助。
  • 我会赞成你的回答,但我缺乏必要的声誉!
【解决方案2】:

看来您在 glwidget.cpp 中缺少函数 loadTerrain() 的实现:

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

您可以查看here 以获取示例。

【讨论】:

  • 我确实有一个实现,但它被注释掉了。我取消了它的注释(并使其成为非静态以遵循上面给出的建议)没有运气。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多