Jump to content
  • Advertisement
Sign in to follow this  
ssorc3

Unresolved External Symbols

This topic is 1530 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
Advertisement
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. Edited by Washu

Share this post


Link to post
Share on other sites

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

Edited by Juliean

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!