C++ OpenGL LNK2001 when header is included

2019-08-18 05:29发布

问题:

I am getting 28

error LNK2001: unresolved external symbol

messages. I know for a fact, for example, that

glBindVertexArray

is in _int_gl_exts.h, and sure enough I am including it.

#include <glload\_int_gl_exts.h>

I don't know if this is a problem, but there are three underscore characters in my error message

symbol ___gleBindVertexArray

Whereas in the file, there is only two underscores before it. This is the exact line inside the include file

extern PFNGLBINDVERTEXARRAYPROC __gleBindVertexArray;
#define glBindVertexArray __gleBindVertexArray

I am pulling much of my stuff directly from a tutorial, and even when my includes and functions are the same, I still have problems. I'll post full code if necessary, but I am out of ideas after about 2 days stuck here.

EDIT: I do in fact have both

#pragma comment(lib, "opengl32.lib")

as well as I tried changing the Project Properties in Linker to add this to additional libraries.

My entire code is as follows. I understand there's a lot of other stuff that needs changed, but this is what I'm trying to get past first.

#include <algorithm>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <string.h>
#include <glload/gl_3_3.h>
#include <glload/gll.hpp>
#include <glutil/Shader.h>
#include <GL/freeglut.h>
#include "framework.h"
#include "directories.h"
#include <glload/_int_gl_exts.h>

#ifdef LOAD_X11
#define APIENTRY
#endif

namespace Framework
{
GLuint LoadShader(GLenum eShaderType, const std::string &strShaderFilename)
{
    std::string strFilename = FindFileOrThrow(strShaderFilename);
    std::ifstream shaderFile(strFilename.c_str());
    std::stringstream shaderData;
    shaderData << shaderFile.rdbuf();
    shaderFile.close();

    try
    {
        return glutil::CompileShader(eShaderType, shaderData.str());
    }
    catch(std::exception &e)
    {
        fprintf(stderr, "%s\n", e.what());
        throw;
    }
}

GLuint CreateProgram(const std::vector<GLuint> &shaderList)
{
    try
    {
        GLuint prog = glutil::LinkProgram(shaderList);
        std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
        return prog;
    }
    catch(std::exception &e)
    {
        std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
        fprintf(stderr, "%s\n", e.what());
        throw;
    }
}

float DegToRad(float fAngDeg)
{
    const float fDegToRad = 3.14159f * 2.0f / 360.0f;
    return fAngDeg * fDegToRad;
}

std::string FindFileOrThrow( const std::string &strBasename )
{
    std::string strFilename = LOCAL_FILE_DIR + strBasename;
    std::ifstream testFile(strFilename.c_str());
    if(testFile.is_open())
        return strFilename;


    strFilename = GLOBAL_FILE_DIR + strBasename;
    testFile.open(strFilename.c_str());
    if(testFile.is_open())
        return strFilename;

    throw std::runtime_error("Could not find the file " + strBasename);
}
}


void init();
void display();
void reshape(int w, int h);
void keyboard(unsigned char key, int x, int y);

unsigned int defaults(unsigned int displayMode, int &width, int &height);

void APIENTRY DebugFunc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
           const GLchar* message, GLvoid* userParam)
{
std::string srcName;
switch(source)
{
case GL_DEBUG_SOURCE_API_ARB: srcName = "API"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: srcName = "Window System"; break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: srcName = "Shader Compiler"; break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: srcName = "Third Party"; break;
case GL_DEBUG_SOURCE_APPLICATION_ARB: srcName = "Application"; break;
case GL_DEBUG_SOURCE_OTHER_ARB: srcName = "Other"; break;
}

std::string errorType;
switch(type)
{
case GL_DEBUG_TYPE_ERROR_ARB: errorType = "Error"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: errorType = "Deprecated Functionality"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: errorType = "Undefined Behavior"; break;
case GL_DEBUG_TYPE_PORTABILITY_ARB: errorType = "Portability"; break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB: errorType = "Performance"; break;
case GL_DEBUG_TYPE_OTHER_ARB: errorType = "Other"; break;
}

std::string typeSeverity;
switch(severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB: typeSeverity = "High"; break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB: typeSeverity = "Medium"; break;
case GL_DEBUG_SEVERITY_LOW_ARB: typeSeverity = "Low"; break;
}

printf("%s from %s,\t%s priority\nMessage: %s\n",
    errorType.c_str(), srcName.c_str(), typeSeverity.c_str(), message);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);

int width = 500;
int height = 500;
unsigned int displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH | GLUT_STENCIL;
displayMode = defaults(displayMode, width, height);

glutInitDisplayMode (displayMode);
glutInitContextVersion (3, 3);
glutInitContextProfile(GLUT_CORE_PROFILE);
#ifdef DEBUG
glutInitContextFlags(GLUT_DEBUG);
#endif
glutInitWindowSize (width, height); 
glutInitWindowPosition (300, 200);
int window = glutCreateWindow (argv[0]);

glload::LoadFunctions();

glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);

if(!glload::IsVersionGEQ(3, 3))
{
    printf("Your OpenGL version is %i, %i. You must have at least OpenGL 3.3 to run this tutorial.\n",
        glload::GetMajorVersion(), glload::GetMinorVersion());
    glutDestroyWindow(window);
    return 0;
}

if(glext_ARB_debug_output)
{
    glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
    glDebugMessageCallbackARB(DebugFunc, (void*)15);
}

init();

glutDisplayFunc(display); 
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

#pragma comment(lib, "opengl32.lib")

#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <glload/gl_3_3.h>
#include <glload\_int_gl_exts.h>
#include <GL/freeglut.h>
#include <glload\_int_gl_1_5.h>
#include <glload\_int_gl_1_1_rem_3_1.h>
#include "../../framework/framework.h"

#define GL_GLEXT_PROTOTYPES
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

GLuint theProgram;
GLuint elapsedTimeUniform;

void InitializeProgram()
{
std::vector<GLuint> shaderList;

shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, "calcOffset.vert"));
shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, "calcColor.frag"));

theProgram = Framework::CreateProgram(shaderList);

elapsedTimeUniform = glGetUniformLocation(theProgram, "time");

GLuint loopDurationUnf = glGetUniformLocation(theProgram, "loopDuration");
GLuint fragLoopDurUnf = glGetUniformLocation(theProgram, "fragLoopDuration");


glUseProgram(theProgram);
glUniform1f(loopDurationUnf, 5.0f);
glUniform1f(fragLoopDurUnf, 10.0f);
glUseProgram(0);
}

const float vertexPositions[] = {
0.25f, 0.25f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 1.0f,
};

GLuint positionBufferObject;
GLuint vao;

void createCube() {
  glBegin(GL_LINES);
  glLineWidth(99.0);

  glColor3f(   1.0,  0.0, 1.0 );

  glVertex3f(  0.5,0.5,0.5 );
  glVertex3f(  0.5,0.5,-0.5 );

  glVertex3f( 0.5,0.5,-0.5 );
  glVertex3f( -0.5,0.5,-0.5 );

  glVertex3f( -0.5,0.5,-0.5 );
  glVertex3f( -0.5,0.5,0.5 );

  glVertex3f( -0.5,0.5,0.5 );
  glVertex3f( 0.5,0.5,0.5 );

  glVertex3f(  0.5,-0.5,0.5 );
  glVertex3f(  0.5,-0.5,-0.5 );

  glVertex3f( 0.5,-0.5,-0.5 );
  glVertex3f( -0.5,-0.5,-0.5 );

  glVertex3f( -0.5,-0.5,-0.5 );
  glVertex3f( -0.5,-0.5,0.5 );

  glVertex3f( -0.5,-0.5,0.5 );
  glVertex3f( 0.5,-0.5,0.5 );

  glVertex3f( 0.5,0.5,0.5 );
  glVertex3f( 0.5,-0.5,0.5 );

  glVertex3f( -0.5,-0.5,-0.5 );
  glVertex3f( -0.5,0.5,-0.5 );

  glVertex3f( 0.5,0.5,-0.5 );
  glVertex3f( 0.5,-0.5,-0.5 );

  glVertex3f( -0.5,0.5,0.5 );
  glVertex3f( -0.5,-0.5,0.5 );

  glEnd();
}

void InitializeVertexBuffer()
{
glGenBuffers(1, &positionBufferObject);

glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
void init()
{
InitializeProgram();
InitializeVertexBuffer();

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
}

//Called to update the display.
//You should call glutSwapBuffers after all of your rendering to display what you rendered.
//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
void display()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(theProgram);

glUniform1f(elapsedTimeUniform, glutGet(GLUT_ELAPSED_TIME) / 1000.0f);

glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);


createCube();
glColor3f(1.0,0.0,0.0);
glutSolidSphere(0.04,10,10);

glDrawArrays(GL_TRIANGLES, 0, 3);

glDisableVertexAttribArray(0);
glUseProgram(0);

glutSwapBuffers();
glutPostRedisplay();
}

    //Called whenever the window is resized. The new window size is given, in pixels.
    //This is an opportunity to call glViewport or glScissor to keep up with the change in size.
void reshape (int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
}

//Called whenever a key on the keyboard was pressed.
//The key is given by the ''key'' parameter, which is in ASCII.
//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
//exit the program.
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
    glutLeaveMainLoop();
    return;
}
}


unsigned int defaults(unsigned int displayMode, int &width, int &height) {return displayMode;}

回答1:

It would be good if you actually stated what library you were trying to link to. The only reason I know which one it is is because I recognize my own work ;)

In any case, the documentation makes it clear what library you should link to. If you're using the Premake4 build system, then you should just have UseLibs {"glload"} in your premake4.lua project. If you're using something else, then you need to manually link to glloadD or glload in debug and release respectively. On Windows, you need a .lib suffix; on Linux, you would use libglloadD and such.

Whether you link with a pragma or use the project settings is irrelevant.



回答2:

Including the declarations is one thing; their definitions are another.

You must link against the OpenGL library when you build your executable.

Follow the instructions in your OpenGL book or reference, but typically you'll pass something like -lopengl32 to your build command; it looks like you might be using Visual Studio, which handles the specific build command for you, in which case you should add the OpenGL libraries to your project properties or use #pragma:

#pragma comment(lib, "opengl32.lib")


回答3:

You probably didn't link the opengl lib file.

In your compiler settings, add to the list of included libraries "opengl32.lib".