c++ubuntulinkergcc4.4

Why do I get a multiple definition error while linking?


I use these two files here and here.

I created a class in two separate files:

modul1.h

#ifndef MODUL1_H
#define MODUL1_H

#include <iostream>
#include <fstream>

#include "easylogger.h"

class Modul1
{
    public:
        Modul1(std::string name);
    protected:
    private:
        easylogger::Logger *log;
};

#endif // MODUL1_H

and modul1.cpp

#include "modul1.h"

Modul1::Modul1(std::string name):log(new easylogger::Logger(name))
{
    //ctor
    //std::ofstream *f = new std::ofstream(name.c_str(), std::ios_base::app);
    //log->Stream(*f);
    //log->Level(easylogger::LEVEL_DEBUG);
    //LOG_DEBUG(*log, "ctor ende!");
}

Now I want to use this class in another file (main.cpp):

#include "modul1.h"

int main()
{
    std::cout << "Hello world!" << std::endl;
    Modul1 mod1("test.log");
    return 0;
}

When I compile it with the following Makefile, I get a "multiple definition of..." error:

g++ main.o modul1.o -o main
modul1.o: In function easylogger::Logger::Format(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
modul1.cpp:(.text+0x0): multiple definition of easylogger::Logger::Format(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
main.o:main.cpp:(.text+0x0): first defined here
modul1.o: In function easylogger::Logger::WriteLog(easylogger::LogLevel, easylogger::Logger*, char const*, unsigned int, char const*, char const*): modul1.cpp:(.text+0x2a): multiple definition of easylogger::Logger::WriteLog(easylogger::LogLevel, easylogger::Logger*, char const*, unsigned int, char const*, char const*)
main.o:main.cpp:(.text+0x2a): first defined here
collect2: ld returned 1 exit status

(At first I compiled it with code::blocks and got the same error)

How can I modify my Modul1 in order not to get this linking error? I don't think it is important, but I am using some Ubuntu 64bit with g++ 4.4.3

Makefile:

CC=g++
CFLAGS=-c -Wall

all: log_test

log_test: main.o easylogger.h modul1.o
    $(CC) main.o modul1.o -o main

main.o: main.cpp modul1.h
    $(CC) $(CFLAGS) main.cpp

modul1.o: modul1.cpp modul1.h
    $(CC) $(CFLAGS) modul1.cpp

Solution

  • The way you are building this, easylogger.h (and consequently easylogger-inl.h) gets included twice, once for modul1.h and once for main.cpp

    Your usage of it is wrong. But you can do this to make it work:

    In modul1.h (remove #include "easylogger.h") and make it look like this

    #ifndef MODUL1_H
    #define MODUL1_H
    
    #include <iostream>
    #include <fstream>
    //#include "easylogger.h"
    
    namespace easylogger { class Logger; };
    
    class Modul1
    {
        public:
            Modul1(std::string name);
        protected:
        private:
            easylogger::Logger *log;
    };
    
    #endif // MODUL1_H
    

    and for modul1.cpp, include the real thing

    #include "modul1.h"
    #include "easylogger.h"
    
    Modul1::Modul1(std::string name):log(new easylogger::Logger(name))
    {
        //ctor
        //std::ofstream *f = new std::ofstream(name.c_str(), std::ios_base::app);
        //log->Stream(*f);
        //log->Level(easylogger::LEVEL_DEBUG);
        //LOG_DEBUG(*log, "ctor ende!");
    }
    

    Good luck!