Reputation: 31
I'm using Visual C++ and manually attempting to load OpenGL extensions. However, for some reason defining the pointers from the Khronos Groups' provided headers leads to linker errors and as such I never get the change to even define these functions within my OpenGL context. Below I have included a simplified version of my code and it's structure that causes the same issue.
//Test.cpp
#include "MyGL.h"
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
}
//MyGL.h
#pragma once
#include "MyGLOpenGL.h"
//MyGL.cpp
#include "MyGL.h"
//MyGLOpenGL.h
#pragma once
#include <windows.h> // Windows functions
#include <GL/gl.h> // Provided w/ Compiler
#include "GL/glext.h" // Put out by Khronos Group
#include "GL/wglext.h" // Put out by Khronos Group
#pragma comment(lib, "opengl32.lib") // Provided w/ Compiler
#ifndef GL_OPENGL
#define GL_OPENGL
void glInitPointers(); // Defines pointers to opengl functions
void* glGetAnyProcAddress(const char* name); // Gets a pointer to any OpenGL function
extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
#endif
//MyGLOpenGL.cpp
#include "MyGLOpenGL.h"
void glInitPointers() {
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)glGetAnyProcAddress("wglChoosePixelFormatARB"); //load function
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)glGetAnyProcAddress("wglCreateContextAttribsARB"); //load function
return;
}
void* glGetAnyProcAddress(const char* name) {
void *pointer = (void *)wglGetProcAddress(name);
if (pointer == 0 || (pointer == (void*)0x1) || (pointer == (void*)0x2) || (pointer == (void*)0x3) || (pointer == (void*)-1)) {
HMODULE module = LoadLibraryW(L"opengl32.dll");
pointer = (void *)GetProcAddress(module, name);
}
return pointer;
};
Compiling this gives me the following linker errors:
1>MyGLOpenGL.obj : error LNK2001: unresolved external symbol "int (__stdcall* wglChoosePixelFormatARB)(struct HDC__ *,int const *,float const *,unsigned int,int *,unsigned int *)" (?wglChoosePixelFormatARB@@3P6GHPAUHDC__@@PBHPBMIPAHPAI@ZA)
1>MyGLOpenGL.obj : error LNK2001: unresolved external symbol "struct HGLRC__ * (__stdcall* wglCreateContextAttribsARB)(struct HDC__ *,struct HGLRC__ *,int const *)" (?wglCreateContextAttribsARB@@3P6GPAUHGLRC__@@PAUHDC__@@PAU1@PBH@ZA)
1>G:\Development\Test\Debug\Test.exe : fatal error LNK1120: 2 unresolved externals
As the issue was unresolved external symbols, I tried removing the extern keyword to arrive at getting these two errors instead:
1>MyGLOpenGL.obj :error LNK2005: "int (__stdcall* wglChoosePixelFormatARB)(struct HDC__ *,int const *,float const *,unsigned int,int *,unsigned int *)" (?wglChoosePixelFormatARB@@3P6GHPAUHDC__@@PBHPBMIPAHPAI@ZA) already defined in MyGL.obj
1>MyGLOpenGL.obj : error LNK2005: "struct HGLRC__ * (__stdcall* wglCreateContextAttribsARB)(struct HDC__ *,struct HGLRC__ *,int const *)" (?wglCreateContextAttribsARB@@3P6GPAUHGLRC__@@PAUHDC__@@PAU1@PBH@ZA) already defined in MyGL.obj
1>Test.obj : error LNK2005: "int (__stdcall* wglChoosePixelFormatARB)(struct HDC__ *,int const *,float const *,unsigned int,int *,unsigned int *)" (?wglChoosePixelFormatARB@@3P6GHPAUHDC__@@PBHPBMIPAHPAI@ZA) already defined in MyGL.obj
1>Test.obj : error LNK2005: "struct HGLRC__ * (__stdcall* wglCreateContextAttribsARB)(struct HDC__ *,struct HGLRC__ *,int const *)" (?wglCreateContextAttribsARB@@3P6GPAUHGLRC__@@PAUHDC__@@PAU1@PBH@ZA) already defined in MyGL.obj
1>G:\Development\Test\Debug\Test.exe : fatal error LNK1169: one or more multiply defined symbols found
I've also already made sure that "#pragma once" was in ever file, header guards, adding "OpenGL32.lib" into the additional dependencies in visual studio, adding a pragma comment for the lib, setting the pointers equal to null in the declaration, and I'm just at a complete loss for anything else to try, even after googling the issue. And in my case, using GLEW or any other extension loading library because that is exactly what I'm trying to create.
Upvotes: 0
Views: 443
Reputation: 31
This isn't very well explained by the OpenGL wiki in the article Load OpenGL Functions but simply do the following. Setting the pointer to null within the cpp file will fix the issue. For example:
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
For anyone interested, here is the relevant code from GLEW that serves the same purpose:
//glew.h
#ifdef GLEW_STATIC
# define GLEWAPI extern
#else
# ifdef GLEW_BUILD
# define GLEWAPI extern __declspec(dllexport)
# else
# define GLEWAPI extern __declspec(dllimport)
# endif
#endif
#define GLEW_FUN_EXPORT GLEWAPI
//wglew.h
#define WGLEW_GET_FUN(x) x
#define wglChoosePixelFormatARB WGLEW_GET_FUN(__wglewChoosePixelFormatARB)
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#define WGLEW_FUN_EXPORT GLEW_FUN_EXPORT
WGLEW_FUN_EXPORT PFNWGLCHOOSEPIXELFORMATARBPROC __wglewChoosePixelFormatARB;
//glew.c
# define glewGetProcAddress(name) wglGetProcAddress((LPCSTR)name)
PFNWGLCHOOSEPIXELFORMATARBPROC __wglewChoosePixelFormatARB = NULL;
r = ((wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)glewGetProcAddress((const GLubyte*)"wglChoosePixelFormatARB")) == NULL) || r;
//I would be using this static so it would evaluate in my code to
//MyGLOpenGL.h
#define wglChoosePixelFormatARB __wglewChoosePixelFormatARB
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
extern PFNWGLCHOOSEPIXELFORMATARBPROC __wglewChoosePixelFormatARB;
//MyGLOpenGL.cpp
PFNWGLCHOOSEPIXELFORMATARBPROC __wglewChoosePixelFormatARB = NULL;
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress((const GLubyte*)"wglChoosePixelFormatARB")
Upvotes: 0
Reputation: 162164
In C and C++ there's an important difference between declaration and definition. A statement of the form
extern <type> <symbol>;
declares that there is some symbol somewhere, but it doesn't actually bring it into existence. It's more like a promise to the compiler, that the symbol will be defined somewhere else. When you wrote
extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
you actually didn't create the variables for those function pointers, you just "listed them in the table of contents" for your program. You actually have to define them somewhere. I.e. in some compilation unit you have to write (without the extern).
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
This has absolutely nothing to do with initialization, as hinted by @EricLopushansky; it's all about them being getting actually defined. Since these are global scope, they'll be initialized to 0 anyway, even if you don't explicitly write that = 0
.
Upvotes: 2