【问题标题】:Manual OpenGL Extension Loading LNK2005 and LNK1169手动 OpenGL 扩展加载 LNK2005 和 LNK1169
【发布时间】:2019-08-12 21:43:43
【问题描述】:

我正在使用 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:\Development\Test\Debug\Test.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:\Development\Test\Debug\Test.exe : fatal error LNK1169: one or more multiply defined symbols found

我还已经确保“#pragma once”在任何文件中,标头保护,将“OpenGL32.lib”添加到 Visual Studio 的附加依赖项中,为 lib 添加 pragma 注释,设置指针相等在声明中为空,即使在谷歌搜索问题之后,我也完全无法尝试其他任何尝试。就我而言,使用 GLEW 或任何其他扩展加载库,因为这正是我想要创建的。

【问题讨论】:

    标签: visual-studio opengl visual-c++


    【解决方案1】:

    OpenGL wiki 在文章Load OpenGL Functions 中没有很好地解释这一点,但只需执行以下操作。在 cpp 文件中将指针设置为 null 将解决此问题。 例如:

    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")
    

    【讨论】:

      【解决方案2】:

      在 C 和 C++ 中,声明定义之间有一个重要的区别。表格声明

      extern <type> <symbol>;
      

      声明有一些符号somewhere,但它实际上并没有让它存在。这更像是对编译器的承诺,符号将在其他地方定义。当你写了

      extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
      extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
      

      您实际上并没有为这些函数指针创建变量,您只是为您的程序“在目录中列出了它们”。您实际上必须在某处定义它们。 IE。在某些编译单元中你必须编写(没有外部)。

      PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
      PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
      

      正如@EricLopushansky 所暗示的,这与初始化完全无关;这一切都是关于它们被实际定义的。由于这些是全局范围,因此它们无论如何都会被初始化为 0,即使您没有明确写出 = 0

      【讨论】:

      • 谢谢。您的解释比我的要简洁得多,并且可能对其他在直接从 OpenGL wiki 复制代码时遇到相同问题的人更有帮助。
      猜你喜欢
      • 1970-01-01
      • 2014-10-14
      • 2021-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多