0

在名为 gl_ext.h 的文件中,我有以下内容:

#ifndef GLEXT_H_INCLUDED
#define GLEXT_H_INCLUDED

#include <stdexcept>

#ifdef WIN32
#include <Windows.h>
#include <GL/GL.h>
#include <GL/glext.h>
# define glGetProcAddress(arg) wglGetProcAddress(arg)
#elif __linux__
#include <GL/gl.h>
#include <GL/glext.h>
# include <GL/glx.h>
# define glGetProcAddress(arg) glXGetProcAddress((const GLubyte*)arg)
#endif

PFNGLCREATESHADERPROC glCreateShader = 0;

namespace glext
{
  bool load_gl_extensions()
  {
    static bool loaded = false;
    if (loaded) {
      return true;
    }
    if (!glCreateShader) {
      glCreateShader = 
        (PFNGLCREATESHADERPROC)(glGetProcAddress("glCreateShader"));
      if (!glCreateShader) {
        throw "Failed to load glCreateShader";
      }
    }
  }
}
#endif

使用以下 .pro 文件从 qt creator 内部构建时

QT += core gui opengl

TEMPLATE = app
TARGET = GLExtensions
INCLUDEPATH += .

LIBS += -lGL
HEADERS += gl_ext.h \
           qtrenderer.h        

SOURCES += main.cpp \
           qtrenderer.cpp

这个“头库”的用法如下: main.cpp

#include <QtGui/QApplication>
#include "qtrenderer.h"

int main(int argc, char * argv[]) {
  QApplication app(argc, argv);

  QtRenderer *renderer = new QtRenderer();
  renderer->show();

  app.exec();
}

qtrenderer.h

#ifndef QTRENDERER_H_INCLUDED
#define QTRENDERER_H_INCLUDED

#include <QtCore/QObject>
#include <QtOpenGL/QGLWidget>

#include <gl_ext.h>

class QtRenderer : public QGLWidget
{

  Q_OBJECT

private:
  QtRenderer(const QtRenderer &other);
  QtRenderer &operator = (const QtRenderer &other);

protected:
  virtual void paintGL();
  virtual void initializeGL();

public:
  QtRenderer();
  ~QtRenderer();

public slots:
  virtual void updateGL();
};

#endif

qtrenderer.cpp

#include "qtrenderer.h"
QtRenderer::QtRenderer() :
  QGLWidget() {
}

QtRenderer::~QtRenderer() {
}

void QtRenderer::initializeGL() {
  try {
    glext::load_gl_extensions();
  } catch (...) {
    throw std::runtime_error("Failed to load needed extensions.");
  }
}

void QtRenderer::paintGL() {
  swapBuffers();
}

void QtRenderer::updateGL() {
  paintGL();
}

使用构建此源代码时

gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)

我收到以下构建错误:

qtrenderer.o: In function `glext::load_gl_extensions()':
/home/mehoggan/Devel/test_gl/./gl_ext.h:28: multiple definition of `glCreateShader'
main.o:/home/mehoggan/Devel/test_gl/./gl_ext.h:28: first defined here

为什么会这样?

4

2 回答 2

3

好吧,头文件 gl_ext.h 被包含多次。请记住,#include 就像以复制和粘贴的方式将 #include 语句替换为文件的内容。

您应该将 load_gl_extensions() 的实现放入 .cpp 文件中,并且仅将声明放入头文件中。

gl_ext.h:

//...

extern PFNGLCREATESHADERPROC glCreateShader;

namespace glext
{
  bool load_gl_extensions();
}

gl_ext.cpp:

#include "gl_ext.h"

PFNGLCREATESHADERPROC glCreateShader = 0;

namespace glext
{
  bool load_gl_extensions()
  {
    static bool loaded = false;
    if (loaded) {
      return true;
    }
    if (!glCreateShader) {
      glCreateShader = 
        (PFNGLCREATESHADERPROC)(glGetProcAddress("glCreateShader"));
      if (!glCreateShader) {
        throw "Failed to load glCreateShader";
      }
    }
  }
}

extern告诉编译器变量/函数指针 (glCreateShader) 被放置在不同的编译单元中(每个 .cpp 文件被编译为不同的单元)。然后链接器插入变量的正确内存地址。也许您应该对 C++ 编译和链接的工作原理进行一些研究。

于 2013-06-24T19:42:14.680 回答
0

该问题的解决方案包括使方法内联并将函数指针声明为静态。

于 2013-06-24T20:46:43.617 回答