tags:

views:

58

answers:

4

Ok I'm trying to get my head around g++ and librarys. I have a few files that I've compiled into a library

from the make file

$(CC) -fPIC -c -o $@ $< -O2 -D__PS2

then

$(CC) -shared -o $@ $(OBJ_FILES) -O2 -D__PS2

this compiles fine.

from the program that uses the lib

$(CC) -c -o $@ $< -I./

compiles fine

$(CC) -o $@ $(OBJ_FILES) I./ -Llib -mootPS2lib.so

Linking the obj's together and it goes BOOM!

ld: duplicate symbol Moot::loggerInstance() in object_files/foo.o and object_files/main.o

foo.hpp

//include guards
#include <Moot/Logger.hpp>
class Foo
{
public:
    void show();
}

foo.cpp

 #include "Foo.hpp"
 void Foo::show() { Moot::loggerInstance().turnLoggerOn(true); }

the main.cpp only includes foo and calls the show method.

Thanks for anyhelp.

UPDATE I wasn't clean with the details of the question, sorry.

I've got this working on Windows by making it a static library.

Logger.hpp looks like this. * Its not quite finished so I know there are a few things missing. but it works.

#ifndef MOOT_LOGGER_HPP
#define MOOT_LOGGER_HPP

#include <Moot/Platform.hpp>
#include <Moot/Utilities.hpp>
#include <iostream>
#include <fstream>
#include <string>

namespace Moot
{
    //! Outputs info to a text file. By default the logger is off.
    //! On the PS2 cout is used to output info onto the screen.
    class Logger
    {
        Logger()
        {
            std::ofstream logfile;
            logfile.open ("logfile.txt", std::ios::trunc);
            logfile << "LogFile - most recent at the bottom\n";
            logfile << "-----------------------------------\n \n";
            logfile.close();

            m_isLoggerOn = false;
        }


        Logger(const Logger&);
        Logger& operator=(const Logger&);

        ~Logger() {}

        bool m_isLoggerOn;

        template <typename T>
        void logMessage(T type)
        {
            # if (MOOT_ON_PS2)
                std::cout << type;
            # else
                std::ofstream logfile;
                logfile.open ("logfile.txt", std::ios::in | std::ios::app);
                logfile << type;
                logfile.close();
            #endif
        }


        //! Overiden << to allow you string together types.
        template <typename T>
        Logger& operator<< (T type) 
        {
            if (m_isLoggerOn) logMessage(type);

            return *this;
        }


        //! Overiden << to allow you string together types.
        Logger& operator<< (std::wstring wideStr)
        {
            if (m_isLoggerOn) logMessage(Moot::Utilities::convertWstringToString(wideStr));

            return *this;
        }

    public:

        //! Instance of the logger.
        static Logger& getInstance()
        {
            static Logger log;
            return log;
        }

        //! Switch Logging off or on. It is set to off by default.
        void turnLoggerOn(bool setLogger)
        {
            m_isLoggerOn = setLogger;
        }

    }; // Logger


    Logger& loggerInstance()
    {
        return Logger::getInstance();
    }


    //! Convenience variables
    namespace {
        Logger& lStart    = loggerInstance();
        const char lEnd   = '\n';
    }
} // Moot


#endif
A: 

I expect that you have something like this in your logger.h file:

namespace Moot
   {
   LoggerInstance &loggerInstance()
      {
      static LoggerInstance myself:
      return myself;
      }
   }

This is a common approach for implementing a singleton (albeit not completely threadsafe).

The solution is to move the implementation of loggerInstance to a separate .CPP file.

Patrick
Thats what I did, I'll try it.
PhilCK
A: 

Make sure that your headers are only included once. i.e.

#ifndef M_H
#define M_H
//Your code
#endif

Seems to me that there is a double inclusion of a header.

nakiya
I have link guards, was first thing I checked. Which left me abit puzzled.
PhilCK
+1  A: 

It doesn't look like you actually need to include Logger.hpp in your Foo.hpp . Try including it in Foo.cpp where the Logger object is actually used.

As a general rule, don't include things in headers unless you absolutely need to as doing so can create dependencies that don't need to be there. I.e.

foo.hpp

#ifndef FOO_HPP
#define FOO_HPP

class Foo 
{ 
public: 
    void show(); 
}

#endif // FOO_HPP

foo.cpp

 #include "Foo.hpp" 
 #include <Moot/Logger.hpp>
 void Foo::show() { Moot::loggerInstance().turnLoggerOn(true); } 
Robin Welch
Ah, I see, I've been including everything in the headers :/
PhilCK
That worked, although I don't quite get it. ho hum.
PhilCK
@PhilCK: The real problem was the (non-inline) definition of `Moot::loggerInstance` in the header file. For non-inline function, only a single definition can occur in a program, but including "Moot/Logger.hpp" in the "Foo.hpp" header caused the "Moot/Logger.hpp" file to be included in both .cpp files and as a consequence two definitions of the `Moot::loggerInstance` function.
Bart van Ingen Schenau
+1  A: 

A solution is to declare loggerInstance inline.

This is the real use of the inline keyword. Your function will be inlined if the compiler wishes, but it won't be defined twice.

Alexandre C.