views:

223

answers:

2

I have a simple logger that is implemented as a singleton. It works like i want when I compile and run it with g++ in linux but when I compile in Visual Studio 9.0 with vc++ I get the following errors. Is there a way to fix this? I don't mind changing the logger class around, but I would like to avoid changing how it is called.

1>Linking...
1>loggerTest.obj : error LNK2005: "public: static class Logger * __cdecl Logger::getInstance(void)" (?getInstance@Logger@@SAPAV1@XZ) already defined in Logger.obj
1>loggerTest.obj : error LNK2005: "public: void __thiscall Logger::log(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?log@Logger@@QAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in Logger.obj
1>loggerTest.obj : error LNK2005: "public: void __thiscall Logger::closeLog(void)" (?closeLog@Logger@@QAEXXZ) already defined in Logger.obj
1>loggerTest.obj : error LNK2005: "private: static class Logger * Logger::_instance" (?_instance@Logger@@0PAV1@A) already defined in Logger.obj
1>Logger.obj : error LNK2001: unresolved external symbol "private: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > Logger::_path" (?_path@Logger@@0V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A)
1>loggerTest.obj : error LNK2001: unresolved external symbol "private: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > Logger::_path" (?_path@Logger@@0V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A)
1>Logger.obj : error LNK2001: unresolved external symbol "private: static class boost::mutex Logger::_mutex" (?_mutex@Logger@@0Vmutex@boost@@A)
1>loggerTest.obj : error LNK2001: unresolved external symbol "private: static class boost::mutex Logger::_mutex" (?_mutex@Logger@@0Vmutex@boost@@A)
1>Logger.obj : error LNK2001: unresolved external symbol "private: static class std::basic_ofstream<char,struct std::char_traits<char> > Logger::_log" (?_log@Logger@@0V?$basic_ofstream@DU?$char_traits@D@std@@@std@@A)
1>loggerTest.obj : error LNK2001: unresolved external symbol "private: static class std::basic_ofstream<char,struct std::char_traits<char> > Logger::_log" (?_log@Logger@@0V?$basic_ofstream@DU?$char_traits@D@std@@@std@@A)

The code, three files Logger.h Logger.cpp test.cpp

#ifndef __LOGGER_CPP__
#define __LOGGER_CPP__
#include "Logger.h"

Logger* Logger::_instance = 0;

//string Logger::_path = "log";
//ofstream Logger::_log;
//boost::mutex Logger::_mutex;

Logger* Logger::getInstance(){
  { 
    boost::mutex::scoped_lock lock(_mutex);
    if(_instance == 0) {
      _instance = new Logger;
   _path = "log";
    }
  } //mutex
  return _instance;
}


void Logger::log(const std::string& msg){
  {
    boost::mutex::scoped_lock lock(_mutex);
    if(!_log.is_open()){
      _log.open(_path.c_str());
    }
    if(_log.is_open()){
    _log << msg.c_str() << std::endl;
    }
  }
}

void Logger::closeLog(){
  Logger::_log.close();
}

#endif

` ...

#ifndef __LOGGER_H__
#define __LOGGER_H__
#include <iostream>
#include <string>
#include <fstream>
#include <boost/thread/mutex.hpp>
#include <boost/thread.hpp>
using namespace std;

class Logger {
  public:
    static Logger* getInstance();
    void log(const std::string& msg);
    void closeLog();
  protected:
    Logger(){}
  private:
    static Logger* _instance;

    static string _path;
    static bool _logOpen;
    static ofstream _log;
    static boost::mutex _mutex; //check mutable
};
#endif

test.cpp `

#include <iostream>
#include "Logger.cpp"
using namespace std;
int main(int argc, char *argv[])
{
  Logger* log = Logger::getInstance();
  log->log("hello world\n");
  return 0;
}
+1  A: 

This is a problem because you've defined the symbol multiple times by compiling the CPP then also including it in test.cpp... By convention you should only include the declaration, not the definition as you've done.

I am surprised that gcc would allow one to be so lax about this.

change

#include "Logger.cpp"

to

#include "Logger.h" 

and give it a try.

Jason D
Thank you! That was all it was.
JeffC
Glad I could help! Please be sure to accept the answer.
Jason D
A: 

The problem is because you have done #include "Logger.cpp" instead of #include "Logger.h" in test.cpp . Because of this, the symbols inside the Logger.cpp will be defined multiple times (once for the translation unit logger.cpp and once for test.cpp). Having multiple inclusion guard doesn't help because it works only within a translation unit.

Naveen