2016-04-27 1 views
1

Я не совсем уверен, где моя проблема.Ошибка компоновщика QT Creator: Link2019 Файл не найден

Я использую 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)" ([email protected]@@[email protected]@[email protected]) referenced in function "protected: virtual void __cdecl GLWidget::initializeGL(void)" ([email protected]@@MEAAXXZ) 

Qt Creator также говорит: Файл не найден glwidget.obj

Однако, проблема действительно связана с классом ландшафта или с тем, как он взаимодействует с glwidget.

Когда я удаляю все ссылки на местности, сборка отлично работает.

Однако, когда я добавить следующую строку в glwidget.cpp в методе initializeGL(), появляется ошибка LINK2019:

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

местности определяется в glwidget.h как экземпляр класса Terrain от местности .cpp:

Terrain* terrain; 

И loadTerrain определяется в glwidget.h как:

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

Интересно, что эта ошибка возникает даже тогда, когда выполняется реализация loadTeerain.

Вот еще несколько вещей, которые я пробовал:

Когда я запускаю чист перед или после QMAKE или удалить файлы .obj в папке сборки, нет никаких изменений. Я заметил, что glwidget.obj, а также terrain.obj появляются, когда проект перестраивается.

Любая помощь приветствуется. Дайте мне знать, хотите ли вы увидеть какие-либо из моих файлов.

EDIT: Проблема сохраняется даже после того, как метод loadTerrain() нестатический.

EDIT 2 я, казалось, забыли вторую ошибку, что он бросает, хотя я не уверен, что это будет больше помощь:

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

отладки является папка, в которой. obj появляются, а program2 - это название проекта.


FIXED! Оказывается, проблема в статичности метода была проблемой. У вас не может быть объявлен статический метод в файлах заголовков, которые будут использоваться несколькими источниками в том виде, в котором я работал.Я заменил:

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

с

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

, а также изменить последующие вызовы метода.

Благодарим за помощь!

+0

Кажется, вам не хватает реализации loadTerrain в файле cpp? – demonplus

+0

У меня была реализация, прокомментированная, однако раскол ее, похоже, не помогает. –

+0

Внедрение реализации означает, что у вас нет реализации. Не могли бы вы опубликовать связанные части вашего заголовка и исходных файлов? – demonplus

ответ

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 

Оказывается дважды! Вот почему вы не ставите функции в файл заголовка, предназначенный для совместного использования несколькими единицами перевода.

+0

Имеет смысл, что статический метод может вызвать проблему. Тем не менее, я сделал его нестатическим, очистил проект, запустил qmake и перестроил, и проблема осталась ... –

+0

Не обращайте внимания на мой последний комментарий. Как только я сделал это нестатичным, мне пришлось не забыть добавлять префикс GLWidget :: к вызову метода, декларации и реализации. Как только я сделал это и перезапустил qmake, это сработало! Я трачу сумасшедшее количество времени на проблему. Спасибо за помощь. –

+0

Я бы поднял ваш ответ, но мне не хватает необходимой репутации! –

0

кажется вам не хватает реализации функции loadTerrain() в glwidget.cpp:

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

Вы можете посмотреть here для образца.

+0

У меня была реализация, но она была прокомментирована. Я расколол его (и сделал его нестационарным, чтобы следовать приведенному выше совету) не повезло. –