Почему я получаю многократную ошибку при связывании?
Я использую эти два файла здесь и здесь.
Я создал класс в двух отдельных файлах:
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
и 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!");
}
Теперь я хочу использовать этот класс в другом файле (main.cpp):
#include "modul1.h"
int main()
{
std::cout << "Hello world!" << std::endl;
Modul1 mod1("test.log");
return 0;
}
Когда я компилирую его с помощью следующего Makefile, я получаю ошибку "множественное определение...":
g ++ main.o modul1.o -o main modul1.o: в функции
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, std::allocator > const&)' main.o:main.cpp:(.text+0x0): сначала определен здесь modul1.o: в функции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): сначала определено здесь collect2: ld вернул 1 статус выхода
(Сначала я скомпилировал его с code::blocks и получил ту же ошибку)
Как я могу изменить мой Modul1, чтобы не получать эту ошибку связывания? Я не думаю, что это важно, но я использую Ubuntu 64bit с 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
3 ответа
Как вы это делаете, easylogger.h (и, следовательно, easylogger-inl.h) включается дважды, один раз для modul1.h и один раз для main.cpp.
Ваше использование этого неправильно. Но вы можете сделать это, чтобы заставить это работать:
В modul1.h (удалите #include "easylogger.h") и сделайте так
#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
и для modul1.cpp, включите реальную вещь
#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!");
}
Удачи!
Вы включаете "easylogger-impl.h" в обе ваши единицы перевода. В easylogger-impl.h есть определения функций. Поэтому у вас есть несколько определений ваших функций.
Одно правило определения гласит, что у вас должно быть одно и только одно определение любого объекта или функции.
Вы можете решить эту проблему, пометив все функции easylogger-impl как inline
или гарантируя, что они появляются только в одной единице перевода.
Это не решение для вашего конкретного случая, но я упомяну об этом для других, которые найдут эту тему, поскольку это может привести к той же ошибке.
Если вы запускаете компилятор и опускаете флаг, а копия вашего бинарного файла уже существует, компилятор попытается связать новый объектный файл с этим бинарным файлом. И новый объектный файл, и бинарный файл будут иметь свои собственные
main
и различные другие символы и предупреждают вас о них.
> g++ MyTest.cxx -g MyTest -I.
/usr/bin/ld: MyTest: in function `main':
/t/proj/MyTest/MyTest.cxx:172: multiple definition of `main'; /tmp/cccYfx2V.o:/t/proj/MyTest/MyTest.cxx:172: first defined here
:
:
:
collect2: error: ld returned 1 exit status
> g++ MyTest.cxx -g -o MyTest -I.
>
Обратите внимание, что вторая команда имеет
-o
вариант, и успешно без комментариев.