【问题标题】:Linker error giving me a headache链接器错误让我头疼
【发布时间】:2011-12-10 05:54:58
【问题描述】:

我遇到了一个似乎无法解决的链接器错误…… 我在 Mac OS X 10.6.8 上使用 Qt 4.7 版和 i686-apple-darwin10-g++-4.2.1 编译器

我似乎找不到问题所在,尽管我确信这只是我自己天真造成的愚蠢错误……

我发布了编译器输出和涉及的 2 个文件(其中大部分)只是为了确保我不会遗漏一些重要的东西。

编译器给出以下输出:

Linking CXX executable GLBall
Undefined symbols:
  "BallGLWidget::resizeGL(int, int)", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "_main", referenced from:
      start in crt1.10.6.o
  "BallGLWidget::paintGL()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "BallGLWidget::~BallGLWidget()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "BallGLWidget::~BallGLWidget()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "non-virtual thunk to BallWindow::~BallWindow()", referenced from:
      vtable for BallWindowin moc_DesktopMain.cxx.o
  "non-virtual thunk to BallGLWidget::~BallGLWidget()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "non-virtual thunk to BallWindow::~BallWindow()", referenced from:
      vtable for BallWindowin moc_DesktopMain.cxx.o
  "BallWindow::~BallWindow()", referenced from:
      vtable for BallWindowin moc_DesktopMain.cxx.o
  "non-virtual thunk to BallGLWidget::~BallGLWidget()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "BallGLWidget::initializeGL()", referenced from:
      vtable for BallGLWidgetin moc_DesktopMain.cxx.o
  "BallWindow::~BallWindow()", referenced from:
      vtable for BallWindowin moc_DesktopMain.cxx.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make[2]: *** [GLBall] Error 1
make[1]: *** [CMakeFiles/GLBall.dir/all] Error 2
make: *** [all] Error 2

这里是 DesktopMain.cpp:(注意:为简洁起见省略了标题)

//-----------------------------------------
//FILE-SCOPE POINTERS
//-----------------------------------------

static BallWindow* mainwindow;
//-----------------------------------------

//-----------------------------------------
//class BallGLWidget IMPLEMENTATIONS
//-----------------------------------------

void BallGLWidget::initializeShaders()
{
    char* vs, fs;

    vertexShaderHandle   = glCreateShader(GL_VERTEX_SHADER);
    fragmentShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);

    vs = readFile(VERTEX_SHADER_FILE_NAME);
    fs = readFile(FRAGMENT_SHADER_FILE_NAME);

    const char* vv = vs, *ff = fs;

    glShaderSource(vertexShaderHandle  , 1, &vv, NULL);
    glShaderSource(fragmentShaderHandle, 1, &ff, NULL);

    delete[] vs; delete[] fs;

    glCompileShader(vertexShaderHandle);
    glCompileShader(fragmentShaderHandle);

    programHandle = createProgram();

    glAttachShader(programHandle, vertexShaderHandle);
    glAttachShader(programHandle, fragmentShaderHandle);

    glLinkProgram(programHandle);
    glUseProgram(programHandle);
}

void BallGLWidget::deleteShaders()
{
    glDetachShader(programHandle, vertexShaderHandle);
    glDetachShader(programHandle, fragmentShaderHandle);

    glDeleteShader(vertexShaderHandle);
    glDeleteShader(fragmentShaderHandle);

    glDeleteProgram(programHandle);
}

GLuint BallGLWidget::loadTexture(const char* fptr)
{
    QImage* img = new QImage();
    if(!img->load(fptr))
    {
        //error loading image, handle error
    }

    //bind the texture to the current context
    GLuint texHandle = bindTexture(&img);

    delete img;

    return texHandle;
}

void BallGLWidget::initializeGL()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    initializeShaders();

    glBindAttribLocation(VERTEX_POS_NUM, VERTEX_POS_ATTRIB_NAME);
    glBindAttribLocation(TEX_POS_NUM, TEX_COORD_ATTRIB_NAME);
    glBindAttribLocation(COLOR_POS_NUM, COLOR_ATTRIB_NAME);

    glEnableVertexArray(VERTEX_POS_NAME);
    glEnableVertexArray(TEX_POS_NUM);
    glEnableVertexArray(COLOR_POS_NUM);

    ball_texture_handle = loadTexture(BALL_IMAGE_PATH);

    samplerUniformLocation = 
            glGetUniformLocation(programHandle, BALL_SAMPLER_NAME);

    glActiveTexture(GL_TEXTURE0 + samplerUniformLocation);

    //bind it in initialization because we're only using
    //1 texture in the program
    glBindTexture(GL_TEXTURE_2D, ball_texture_handle);

    //construct C++ objects
    ball = new Ball(BALL_DIAMETER);
    colorTrail = new ColorTrail(programHandle);
}

void BallGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);

    ball      ->draw();
    colorTrail->add_segment(ball->getTopLeftCornerCoord(),
                            ball->getLeftCornerCoord());

    ball->updatePhysics();
}

void BallGLWidget::resizeGL(int width, int height)
{
    //should this be the constants or the parameters?
    //where are the camera functions in OpenGL ES 2...
    glViewport(0, 0, BOX_WIDTH, BOX_HEIGHT);
}

void BallGLWidget::cleanupGL()
{
    deleteShaders();
}

BallGLWidget::BallGLWidget(QWidget *parent = 0)
{

}

BallGLWidget::~BallGLWidget()
{
    cleanupGL();
    delete ball;
    delete colorTrail;
}

//-----------------------------------------
//class BallWindow IMPLEMENTATIONS
//-----------------------------------------

void BallWindow::createWindow()
{
    //minimum size is defined in GlobalConstants.h
    setMinimumSize(QSize(BOX_WIDTH, BOX_HEIGHT));

    BallGLWidget* glWidget = new BallGLWidget;

    setAttribute(Qt::WA_DeleteOnClose);

    setCentralWidget(glWidget);
}

BallWindow::BallWindow(QWidget * parent = 0)
{
    createWindow();
}

BallWindow::~BallWindow()
{

}


//-----------------------------------------
//main FUNCTION
//-----------------------------------------
int main(int argc, const char* argv[])
{
    QApplication application(argc, argv);
    mainwindow = new BallWindow();
    BallWindow->show();

    return application.exec();
}

DesktopMain.h:

class BallGLWidget : public QGLWidget
{
    Q_OBJECT

private:
    //----------------------------
    //HANDLES
    //----------------------------
    GLuint ball_texture_handle;
    GLuint vertexShaderHandle, fragmentShaderHandle;
    GLuint programHandle;
    GLuint samplerUniformLocation;

    //----------------------------
    //PRIVATE VARIABLES
    //----------------------------
    Ball*       ball;
    ColorTrail* colorTrail;

//----------------------------
//PRIVATE METHODS
//----------------------------
void initializeShaders();
void deleteShaders();

GLuint loadTexture(const char* fptr);


protected:
     void initializeGL();
     void paintGL();
     void resizeGL(int width, int height);
     void cleanupGL();

public:
     BallGLWidget(QWidget *parent = 0);
     virtual ~BallGLWidget();
};


class BallWindow : public QMainWindow
{
    Q_OBJECT
private:
    void createWindow();
public:
    BallWindow(QWidget *parent = 0);
    ~BallWindow();
};

//void onProgramExit();

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

编辑:我正在为这个项目使用 CMake。很抱歉忘记在原始问题中发布此内容!

这是 CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)

project(GLBall)

SET(ENV{SOURCES} src/Ball.cpp src/Ball.h src/ColorTrail.cpp src/ColorTrail.h  src/DesktopMain.h src/DesktopMain.cpp src/GlobalConstants.h src/ShaderOps.h)

FIND_PACKAGE(Qt4 REQUIRED)
FIND_PACKAGE(OpenGL REQUIRED)

SET(QT_USE_QTOPENGL TRUE)

QT4_WRAP_CPP(HEADERS_MOC src/DesktopMain.h)

INCLUDE(${QT_USE_FILE})

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})

ADD_DEFINITIONS(${QT_DEFINITIONS})

SET(CMAKE_EXE_COMPILER_FLAGS -g -v)

ADD_EXECUTABLE(GLBall ${SOURCES} ${HEADERS_MOC})

TARGET_LINK_LIBRARIES(GLBall ${QT_LIBRARIES})

【问题讨论】:

  • 我开始赏金是因为我忘记在原始问题中包含我正在使用 CMake 构建这个项目,所以我对 qmake 没有太多直接控制(据我所知)

标签: c++ qt linker g++ cmake


【解决方案1】:

我相信

SET(ENV{SOURCES} src/Ball.cpp src/Ball.h src/ColorTrail.cpp src/ColorTrail.h  src/DesktopMain.h src/DesktopMain.cpp src/GlobalConstants.h src/ShaderOps.h)

应该是

SET(SOURCES src/Ball.cpp src/Ball.h src/ColorTrail.cpp src/ColorTrail.h  src/DesktopMain.h src/DesktopMain.cpp src/GlobalConstants.h src/ShaderOps.h)

因为您稍后引用${SOURCES},而不是环境变量。那当然可以。实际上,“来源”不应该包含标题(将带有 Q_OBJECT 宏的头文件传递给qt4_wrap_cpp,就像你正在做的那样)。这是修改后的文件:

cmake_minimum_required(VERSION 2.6)

project(GLBall)

set(SOURCES src/Ball.cpp src/ColorTrail.cpp src/DesktopMain.cpp)

find_package(Qt4 REQUIRED)
find_package(OpenGL REQUIRED)
set(QT_USE_QTOPENGL TRUE)
include(${QT_USE_FILE})

include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_definitions(${QT_DEFINITIONS})

set(CMAKE_EXE_COMPILER_FLAGS -g -v)

qt4_wrap_cpp(HEADERS_MOC src/DesktopMain.h)

add_executable(GLBall ${SOURCES} ${HEADERS_MOC})
target_link_libraries(GLBall ${QT_LIBRARIES})

此外,您可以在运行ccmakecmake-gui 时将CMAKE_BUILD_TYPE 更改为“Debug”(或“Release”),而不是手动设置编译器标志。


可能与它无关,但以防万一,我通常将qt4_wrap_cpp 调用放在include(${QT_USE_FILE}) 之后。

【讨论】:

    【解决方案2】:

    就像 Luca 说的,确保你正确地运行 qmake,这里是通常的步骤-

    $ qmake -project
    $ qmake
    $ make
    

    ($是shell提示符)

    如果这不能解决问题,也许您应该让我们知道您的目录结构。

    【讨论】:

    • 哦哦,我忘记了一个重要的细节!我正在运行 CMake 我真的很抱歉
    • 我应该发布 CMakeLists.txt 吗?
    • 后来看到你得到了答案;)顺便说一句,当我需要检查我的 CMake+Qt developer.qt.nokia.com/quarterly/view/… 时,我发现此页面很有帮助
    【解决方案3】:

    尝试清理项目运行 qmake。然后重建。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-28
      • 2013-04-22
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      相关资源
      最近更新 更多