Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 715
Burkhard Avatar asked Mar 31 '12 20:03

Burkhard


2 Answers

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!

like image 172
bendervader Avatar answered Oct 12 '22 23:10

bendervader


You include "easylogger-impl.h" in both of your translation units. There are function definitions in easylogger-impl.h. Therefore, you have multiple definitions of your functions.

The one definition rule says that you must have one, and only one, definition of any object or function.

You may solve this problem either by marking all of the easylogger-impl functions as inline, or by ensuring that they appear in only one translation unit.

like image 35
Robᵩ Avatar answered Oct 12 '22 23:10

Robᵩ