Advertisement

Unresolved External Symbols

Started by October 09, 2014 10:15 AM
2 comments, last by ssorc3 10 years, 3 months ago

I know this is a common question among beginners of C++ but I have looked at other peoples threads and not found what I was looking for. I understand the unresolved external symbols error usually means missing libraries but these are my classes that it is not accepting. Here is the code and the errors(Sorry it's so messy, I'm in the process of converting it from single file to object orientated):

main.cpp:


#include <iostream>
#include <gl\glew.h>
#include <GL\freeglut.h>
#include <vector>
#include <algorithm>
#include <string>
#include <fStream>
#include <cmath>
#include <array>
#include "ResourceLoader.h"
#include "Shader.h"
#include "Program.h"

#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))

void display();
void reshape();
void init();
void InitializeVertexBuffer();

struct glutWindow
{
	int width;
	int height;
	char* title;

	float fov;
	float zNear;
	float zFar;
};

glutWindow win;
GLuint positionBufferObject;
GLuint vao;

Shader vertex("../Shaders/Vertex.vs");
Shader fragment("../Shaders/Fragment.fs");
Program program;

const float vertexPositions[]
{
	//102 lines of vertex positions I didn't think were necessary to include...
};

int main(int argc, char** argv)
{
	win.width = 800;
	win.height = 700;
	win.title = "OpenGL";
	win.fov = 45;
	win.zNear = 1.0f;
	win.zFar = 500.0f;

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
	glutInitWindowSize(win.width, win.height);
	glutCreateWindow("OpenGL");
	glutDisplayFunc(display);
	glewInit();
	init();
	glutMainLoop();
	return 0;
}

void init()
{
	Shader* shaders[]{&vertex, &fragment};
	program.setShaders(shaders);
	program.InitializeProgram();
	InitializeVertexBuffer();

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

	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CW);
	glCullFace(GL_BACK);
}


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

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

void display()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	program.use();

	program.setUniform2f("offset", 0.5f, 0.5f);

	size_t colorData = (1, 1, 1, 1);
	glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorData);

	glDrawArrays(GL_TRIANGLES, 0, 36);

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glUseProgram(0);

	glutSwapBuffers();
	glutPostRedisplay();
}

Program.h:


#ifndef _PROGRAM_H
#define _PROGRAM_H

#include <gl\glew.h>
#include <GL\freeglut.h>
#include <vector>
#include <algorithm>
#include <map>
#include <cstdarg>
#include "Shader.h"

class Program
{
	public:
		static void CreateProgram(Shader* shaders[]);
		void InitializeProgram();
		static GLuint getUniformLocation(const GLchar* name);
		static void use();
		void setShaders(Shader* shaders[]);
		void setUniform1f(std::string name, float value);
		void setUniform2f(std::string name, float val1, float val2);

		static Shader* shaders[3];

	private:
		static GLuint program;
		static std::map<std::string, GLuint> uniforms;
		
};

#endif

Program.cpp:


#include "Program.h"

void Program::CreateProgram(Shader* shaders[])
{
	GLuint program = glCreateProgram();

	for (size_t iLoop = 0; iLoop < sizeof(shaders) / sizeof(shaders[0]); iLoop++)
		glAttachShader(program, shaders[iLoop]->getShader());

	glLinkProgram(program);

	GLint status;
	glGetProgramiv(program, GL_LINK_STATUS, &status);
	if (status == GL_FALSE)
	{
		GLint infoLogLength;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);

		GLchar *strInfoLog = new GLchar[infoLogLength + 1];
		glGetProgramInfoLog(program, infoLogLength, NULL, strInfoLog);
		fprintf(stderr, "Shader Linker failure: %s\n", strInfoLog);
		delete[] strInfoLog;
	}

	for (size_t iLoop = 0; iLoop < sizeof(shaders) / sizeof(shaders[0]); iLoop++)
		glDetachShader(program, shaders[iLoop]->getShader());

	Program::program = program;
}

void Program::InitializeProgram()
{
	Program::CreateProgram(Program::shaders);

	uniforms["offset"] = this->getUniformLocation("offset");
	uniforms["frustumScale"] = this->getUniformLocation("frustumScale");
	uniforms["zNear"] = this->getUniformLocation("zNear");
	uniforms["zFar"] = this->getUniformLocation("zFar");

	this->use();
	this->setUniform1f("frustumScale", 1.0f);
	this->setUniform1f("zNear", 1.0f);
	this->setUniform1f("zFar", 1.0f);

	glUseProgram(0);

	for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
	{
		glDeleteShader(shaders[i]->getShader());
	}
}

void Program::setUniform1f(std::string name, float value)
{
	glUniform1f(uniforms[name], value);
}

void Program::setUniform2f(std::string name, float val1, float val2)
{
	glUniform2f(uniforms[name], val1, val2);
}

GLuint Program::getUniformLocation(const GLchar* name)
{
	return glGetUniformLocation(Program::program, name);
}

void Program::use()
{
	glUseProgram(Program::program);
}

void Program::setShaders(Shader* shaders[])
{
	for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
	{
		Program::shaders[i] = shaders[i];
	}
}

Shader.h:


#ifndef _SHADER_H
#define _SHADER_H

#include <string>
#include <iostream>
#include <sstream>
#include <gl\glew.h>
#include <GL\freeglut.h>
#include "ResourceLoader.h"

class Shader
{
	public:
		Shader(const char* filePath);
		void loadShader();
		void CreateShader(GLenum eShaderType);

		std::string getContent();
		std::string getFilePath();
		GLuint getShader();

	private:
		const char* filePath;
		GLuint shader;
		std::string content;
};

#endif

Shader.cpp:


#include "Shader.h"

	Shader::Shader(const char* filePath)
	{
		this->filePath = filePath;
		loadShader();
	}

	void Shader::loadShader()
	{
		content = ResourceLoader::readFile(this->filePath);
		if (content == "")
		{
			std::cout << "Shader " << filePath << " could not be loaded." << std::endl;
		}
	}

	std::string Shader::getContent()
	{
		return this->content;
	}

	std::string Shader::getFilePath()
	{
		return this->filePath;
	}

	GLuint Shader::getShader()
	{
		return this->shader;
	}

	void Shader::CreateShader(GLenum eShaderType)
	{
		GLuint shader = glCreateShader(eShaderType);
		std::string strFileData = ResourceLoader::readFile(this->filePath);
		const char* cstrFileData = strFileData.c_str();
		const GLint length = strFileData.length();

		glShaderSource(shader, 1, &cstrFileData, &length);

		glCompileShader(shader);

		GLint status;
		glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
		if (status == GL_FALSE)
		{
			GLint infoLogLength;
			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);

			GLchar *strInfoLog = new GLchar[infoLogLength + 1];
			glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog);

			const char *strShaderType = NULL;
			switch (eShaderType)
			{
			case GL_VERTEX_SHADER: strShaderType = "vertex"; break;
			case GL_GEOMETRY_SHADER: strShaderType = "geometry"; break;
			case GL_FRAGMENT_SHADER: strShaderType = "fragment"; break;
			}

			fprintf(stderr, "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog);
			delete[] strInfoLog;
		}

		this->shader = shader;
	}

ResourceLoader.h:


#ifndef _RESOURCE_LOADER_H
#define _RESOURCE_LOADER_H

#include <string>
#include <fstream>
#include <iostream>

class ResourceLoader
{
	public:
		static std::string readFile(const char* filePath);
};

#endif

ResourceLoader.cpp:


#include "ResourceLoader.h"

std::string ResourceLoader::readFile(const char *filePath)
{
	std::string content;
	std::ifstream fileStream(filePath, std::ios::in);

	if (!fileStream.is_open())
	{
		std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
		return "";
	}

	std::string line = "";
	while (!fileStream.eof())
	{
		std::getline(fileStream, line);
		content.append(line + "\n");
	}

	fileStream.close();
	return content;
}

Errors:


Error	1	error LNK2001: unresolved external symbol "public: static class Shader * * Program::shaders" (?shaders@Program@@2PAPAVShader@@A)	c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj	OpenGL Project

Error	2	error LNK2001: unresolved external symbol "private: static unsigned int Program::program" (?program@Program@@0IA)	c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj	OpenGL Project

Error	3	error LNK2001: unresolved external symbol "private: static class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,unsigned int,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,unsigned int> > > Program::uniforms" (?uniforms@Program@@0V?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@std@@@2@@std@@A)	c:\Users\Ben\documents\visual studio 2013\Projects\OpenGL Project\OpenGL Project\Program.obj	OpenGL Project

Error	4	error LNK1120: 3 unresolved externals	c:\users\ben\documents\visual studio 2013\Projects\OpenGL Project\Debug\OpenGL Project.exe	1	1	OpenGL Project

Thanks

You have declared, but not defined, those static variables.
These:

static Shader* shaders[3];
static GLuint program;
static std::map uniforms;

are declarations, they do not define the actual storage locations.

I also question why they are static, and not instance, not to mention storing a random set of pointers to shaders.

for (size_t iLoop = 0; iLoop < sizeof(shaders) / sizeof(shaders[0]); iLoop++)
does not do what you think it does.

for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
does not do what you think it does.


GLchar *strInfoLog = new GLchar[infoLogLength + 1];
delete[] strInfoLog;
manual string memory management, error prone. Use std::string and std::string::resize.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Advertisement

Static member variables have to be defined in the c++-file like this:


Shader* Program::shaders[3];
GLuint Program::program = 0; // assigns the value of "0" initially

EDIT: Ninja'd :D

Thank you both of you! They now work. In answer to your question, Washu, as to why they were static, I was methods it to different classes when I created the new objects and I originally had to make it static to access it from main.cpp. Now that I've finished, they're no longer static. I just sort of went along with it when errors about non-static references came up and made the variables static.

This topic is closed to new replies.

Advertisement