Thread: error LNK2019: unresolved external symbol

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    32

    Question error LNK2019: unresolved external symbol

    Hi everyone,

    I am using a singleton class called "Slipnet" which is defined in two files: slipnet.hpp and slipnet.cpp. (relevant source code included below)

    Then, I am including Slipnet.hpp in my main.cpp file and calling Slipnet::getInstance() in the main function.

    I keep getting the following error:
    Code:
    main.obj : error LNK2019: unresolved external symbol "public: static class Slipnet * __cdecl Slipnet::getInstance(void)" (?getInstance@Slipnet@@SAPAV1@XZ) referenced in function _main
    Debug/integratedApp.exe : fatal error LNK1120: 1 unresolved externals
    What am I missing?

    Slipnet.hpp
    Code:
    #ifndef SLIPNET_H
    #define SLIPNET_H
    
    #include <string>
    #include "ConceptNode.hpp"
    #include <map>
    #include <vector>
    
    using namespace std;
    
    
    // a directed graph where each vertex represents a concept
    // and each edge represents the semantic connection from one
    // conept to another.  This is read from a text file that explains
    // what concepts lead to what other concepts and to what degree.
    // Codelets of certain type represent a concept of sorts and
    // then can find themselves a node in the slipnet that matches
    // their concept - from there, they know to codelets of what
    // concept they can bind and they know what types of codelets to
    // post to the coderack in case they manage to bind.
    class Slipnet
    {
        private:
    		Slipnet();
    		static bool instanceFlag;
    		// totally static network, read once from file: /data/slip.net
    		static std::map<std::string, ConceptNode*> net;
    		//singleton instance.
    		static Slipnet* instance;
    		// facilitates traversal of the graph
    		static ConceptNode* getNode(std::string type);
    		// loads the file in "../../data/slip.net"
    		static bool loadFile(std::string filePath);
    		// helper functions to read the text file
    		static bool parseChildrenAndParents(ConceptNode* node, std::string& children, std::string& parents);
    		static void trim(std::string& str);
    	
    	public:
    		static Slipnet* getInstance();
    		// these functions can be called externally to get the neighbors of a given concept so that
    		// new codelets can be generated accoring to the semantic slippage of ideas.
    		static std::vector<std::pair < std::string, double > > getPossibleChildren(std::string codeletType);
    		static std::vector<std::pair < std::string, double > > getPossibleParents(std::string codeletType);
    };
    
    
    #endif
    Slipnet.cpp
    Code:
    #include "Slipnet.hpp"
    #include <fstream>
    
    using namespace std;
    
    Slipnet* Slipnet::instance = NULL;
    bool Slipnet::instanceFlag = false;
    std::map<std::string, ConceptNode*> Slipnet::net;
    
    Slipnet::Slipnet()
    {
    	// do nothing
    }
    
    bool Slipnet :: loadFile(std::string filePath)
    // each concept node in the file is set up like this:
    // concept : child1(weight), child2(weight) .. childN(weight) : parent1(weight), parent2(weight) .. parentM(weight) ;
    {
    	ifstream in;
    	in.open(&filePath[0]);
    	if(!in)
    	{
    		printf("error opening slipnet file not found in %s",filePath);
    		return false;
    	}
    
    	std::string line;
    	int lineNumber = 0;
    
    
    	while(getline(in,line))
    	{
    		line = line.substr(0,line.find_first_of("//"));
    		trim(line);
    		if(line.length() == 0)
    		{
    			lineNumber++;
    			continue;
    		}
    		std::string concept;
    		std::string children;
    		std::string parents;
    		// make sure there are exactly 2 ':'s and 1 ';'s.
    		int colonCounter = 0;
    		int semicolonCounter = 0;
    		int index = 0;
    		while(index < line.length())
    		{
    			if(line.c_str()[index] == ':')
    			{
    				colonCounter++;
    				if(colonCounter > 2)
    				{
    					printf("there can't be more than two colons in a slipnet file line, error at line %d character %d",lineNumber,index);
    					in.close();
    					return false;
    				}
    			}
    			else if(line.c_str()[index] == ';')
    			{
    				semicolonCounter++;
    				if(semicolonCounter > 1)
    				{
    					printf("there can't be more than one semicolon in a slipnet file line, error at line %d character %d",lineNumber,index);
    					in.close();
    					return false;
    				}
    			}
    			index++;
    		}
    		if(colonCounter < 2)
    		{
    			printf("there must be exactly 2 colons in each slipnet file line, error found in line %d",lineNumber);
    			in.close();
    			return false;
    		}
    		if(semicolonCounter < 1)
    		{
    			printf("there must be exactly 1 semicolon in each slipnet file line, error found in line %d",lineNumber);
    			in.close();
    			return false;
    		}
    		// find 1st and 2nd colon and the semicolon.
    		int indexOf1stColon = line.find_first_of(':');
    		int indexOf2ndColon = line.find_first_of(':',indexOf1stColon + 1);
    		int indexOfSemiColon = line.find(';');
    		concept = line.substr(0,indexOf1stColon);
    		trim(concept);
    		// children is everything from after the first : and before the second :
    		children = line.substr(indexOf1stColon+1,indexOf2ndColon - indexOf1stColon - 1);
    		trim(children);
    		// parents is everything after the second : and to the ';'
    		parents = line.substr(indexOf2ndColon+1,indexOfSemiColon - indexOf2ndColon - 1);
    		trim(parents);
    
    		ConceptNode* node = new ConceptNode(concept);
    		if(!parseChildrenAndParents(node,children,parents))
    		{
    			printf("error, make sure every child and parent node is followed by a parenthesized double for the weight of the link, error in line %d",lineNumber);
    			in.close();
    			return false;
    		}
    		net.insert(make_pair(concept,node));
    
    		lineNumber++;
    	}
    
    	in.close();
    
    	return true;
    }
    
    bool Slipnet :: parseChildrenAndParents(ConceptNode* node, std::string& children, std::string& parents)
    {
    	std::string helper;
    	int helperIndex;
    	while(children.length() > 0)
    	{
    		helperIndex = children.find(',');
    		if(helperIndex == -1)
    			helperIndex = children.length();
    		helper = children.substr(0,helperIndex);
    		if(helperIndex == children.length())
    			children = "";
    		else
    			children = children.substr(helperIndex+1,children.length() - helperIndex - 1);
    		trim(helper);
    
    		// separate concept name from weight
    		int indexOfParenthsStart = helper.find('(');
    		int indexOfParenthsEnd =   helper.find(')');
    		if(indexOfParenthsStart == -1 || indexOfParenthsEnd == -1)
    			return false;
    		std::string weightString = helper.substr(indexOfParenthsStart+1,indexOfParenthsEnd - indexOfParenthsStart-1);
    	    helper = helper.substr(0,indexOfParenthsStart);
    		trim(helper);
    		double weight = atof(&weightString[0]);
    
    		node->addChild(helper, weight);
    	}
    	while(parents.length() > 0)
    	{
    		helperIndex = parents.find(',');
    		if(helperIndex == -1)
    			helperIndex = parents.length();
    		helper = parents.substr(0,helperIndex);
    		if(helperIndex == parents.length())
    			parents = "";
    		else
    			parents = parents.substr(helperIndex+1,parents.length() - helperIndex - 1);
    		trim(helper);
    
    		// separate concept name from weight
    		int indexOfParenthsStart = helper.find('(');
    		int indexOfParenthsEnd =   helper.find(')');
    		if(indexOfParenthsStart == -1 || indexOfParenthsEnd == -1)
    			return false;
    		std::string weightString = helper.substr(indexOfParenthsStart+1,indexOfParenthsEnd - indexOfParenthsStart-1);
    	    helper = helper.substr(0,indexOfParenthsStart);
    		trim(helper);
    		double weight = atof(&weightString[0]);
    
    		node->addChild(helper, weight);
    	}
    	return true;
    }
    
    void Slipnet :: trim(std::string& str)
    {
    	int beginIndex = 0;
    	int endIndex = str.length();
    	while(str.c_str()[beginIndex] == ' ')
    		beginIndex++;
    	while(str.c_str()[endIndex] == ' ')
    		endIndex--;
    	str = str.substr(beginIndex,endIndex - beginIndex);
    }
    
    ConceptNode* Slipnet :: getNode(std::string type)
    {
    	std::map<std::string, ConceptNode*>::iterator it = net.find(type);
    	if(it != net.end())
    		return it->second;
    	return NULL;
    }
    
    Slipnet* Slipnet :: getInstance()
    {
        if(!instanceFlag)
    	{
    		instance = new Slipnet();
    		instanceFlag = true;
    		loadFile("../../../data/slip.net");
    	}
    	return instance;
    }
    
    std::vector<std::pair < std::string, double > > Slipnet :: getPossibleChildren(std::string codeletType)
    {
    	std::vector<std::pair < std::string, double > > answer;
    	ConceptNode* node = getNode(codeletType);
    	if(node != NULL)
    		answer = node->getChildren();
    	return answer;
    }
    
    std::vector<std::pair < std::string, double > > Slipnet :: getPossibleParents(std::string codeletType)
    {
    	std::vector<std::pair < std::string, double > > answer;
    	ConceptNode* node = getNode(codeletType);
    	if(node != NULL)
    		answer = node->getParents();
    	return answer;
    }
    main.cpp

    Code:
    #include "Slipnet.hpp"
    
    using namespace std;
    
    int main(int argc,char* argv [])
    {
       Slipnet* slipnet = Slipnet::getInstance();
        .
        .
        .
        return 0;
    }

  2. #2
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    How are you compiling it all together?
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Looks like you need to add Slipnet.cpp to your project.

  4. #4
    Registered User
    Join Date
    May 2006
    Posts
    32
    Slipnet.hpp and Slipnet.cpp are under a project named "codelets"
    main.cpp is under a separate project named "main"
    Both projects are under the same solution.
    I'm using Visual Studio.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Did both projects get built? codelets should be a dependent of main in the Project Dependencies. (Edit... I had this backwards originally.)

    Are you linking to codelets.lib when you build the main project? I assume codelets is intended to be a static library, not a dll, is that correct?

  6. #6
    Registered User
    Join Date
    May 2006
    Posts
    32
    Codelets is a static lib.
    main is the "start-up" project... I don't know what you mean by project dependencies...
    The codelets project gets built when I build it on its own...

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Under Project > Project Dependencies, the main project depends on codelets. Checking that box allows Visual Studio to make sure changes to codelets get build before changes to main. If you build codelets manually first then that should do the same thing (although you should probably fix the dependency anyway just for your own sake). Set main as the Startup Project as well.

    If you've built codelets, then a codelets.lib file should have been created, correct? Are you linking to that lib in the main project properties? Make sure the main project is selected and go to Project > Properties. Then go to Linker > Input and make sure codelets.lib is in the additional dependencies. You might also have to add the path to the codelets lib under the Additional Library Directories property of Linker > General.

    That will allow the executable created when you build the main project to link to the library created by the codelets project. If you haven't done that, then you'll get the errors you indicated.

    (Note that depending on which version of Visual Studio you're using, the terminology I used might be different than what you see. However, all the options should be very similar in your version. I checked VC++ 2003 for the above terms.)

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    By checking a dependency to a dynamic library or static library, Visual Studio will automatically link against its lib file to to speak, so there's no need to do it manually. Just make sure there's a dependency.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    May 2006
    Posts
    32

    Resolved

    <resolved>

    You guys,
    You were right, a quick trip into project > properties and the issue was resolved.
    Thank you for your time!

    </resolved>

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Compiling sample DarkGDK Program
    By Phyxashun in forum Game Programming
    Replies: 6
    Last Post: 01-27-2009, 03:07 AM
  2. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  3. Including lib in a lib
    By bibiteinfo in forum C++ Programming
    Replies: 0
    Last Post: 02-07-2006, 02:28 PM
  4. Stupid compiler errors
    By ChrisEacrett in forum C++ Programming
    Replies: 9
    Last Post: 11-30-2003, 05:44 PM
  5. debug to release modes
    By DavidP in forum Game Programming
    Replies: 5
    Last Post: 03-20-2003, 03:01 PM