#visual-studio #opengl #visual-c
#visual-studio #opengl #visual-c
Вопрос:
Я использую Visual C и вручную пытаюсь загрузить расширения OpenGL. Однако по какой-то причине определение указателей из предоставленных Khronos Groups заголовков приводит к ошибкам компоновщика, и поэтому я никогда не получаю изменений даже для определения этих функций в моем контексте OpenGL. Ниже я включил упрощенную версию моего кода и его структуру, которая вызывает ту же проблему.
//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;
};
При компиляции этого я получаю следующие ошибки компоновщика:
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:DevelopmentTestDebugTest.exe : fatal error LNK1120: 2 unresolved externals
Поскольку проблема была неразрешена с внешними символами, я попытался удалить ключевое слово extern, чтобы вместо этого получить эти две ошибки:
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:DevelopmentTestDebugTest.exe : fatal error LNK1169: one or more multiply defined symbols found
Я также уже убедился, что «#pragma once» был во всех файлах, защита заголовка, добавление «OpenGL32.lib» в дополнительные зависимости в visual studio, добавление комментария pragma для библиотеки, установка указателей равными null в объявлении, и я просто в полной растерянности, что еще можно попробовать, даже после поиска проблемы в Google. И в моем случае, используя GLEW или любую другую библиотеку загрузки расширений, потому что это именно то, что я пытаюсь создать.
Ответ №1:
В C и C есть важное различие между объявлением и определением. Заявление по форме
extern <type> <symbol>;
заявляет, что где-то есть какой-то символ, но на самом деле он не создает его. Это больше похоже на обещание компилятору, что символ будет определен где-то в другом месте. Когда ты писал
extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
на самом деле вы не создавали переменные для этих указателей на функции, вы просто «перечислили их в оглавлении» своей программы. На самом деле вам нужно где-то их определить. Т.е. в каком-то модуле компиляции вы должны написать (без extern).
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
Это не имеет абсолютно ничего общего с инициализацией, как намекнул @EricLopushansky; все дело в том, что они действительно определяются. Поскольку это глобальная область видимости, они в любом случае будут инициализированы значением 0, даже если вы явно этого не напишете = 0
.
Комментарии:
1. Спасибо. Ваше объяснение было намного более кратким, чем мое, и, вероятно, более полезным для других людей, которые сталкиваются с такой же проблемой при прямом копировании кода из OpenGL wiki, не слишком задумываясь.
Ответ №2:
Это не очень хорошо объясняется OpenGL wiki в статье Загрузка функций OpenGL, но просто сделайте следующее. Установка указателя на null в файле cpp устранит проблему. Например:
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
Для всех, кому интересно, вот соответствующий код из GLEW, который служит той же цели:
//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")