[C++] Błąd kompilacji: multiple definition of


(kijek) #1

Witam.

Piszę właśnie obiektowo pewien program. Cały projekt podzieliłem na pliki - *.h (w sumie powinny być *.hpp) i *.cpp. Jedna z moich klas korzysta z biblioteki Simple SVG. Nieco ją zmodyfikowałem na swój użytek, dodając do klasy Document prostą metodę set:

void set(std::string fname, Layout lay)

{

	file_name = fname;

	layout = lay;

}

Mój problem polega na tym, że we własnej klasie chciałbym zainicjować obiekty klas Dimensions i Document. W tym celu do pliku nagłówkowego swojej klasy includuję bibliotekę Simple SVG. Niestety, wówczas przy kompilacji otrzymuję następujące błędy:

Plik nagłówkowy klasa.h jest jedynym plikiem, w którym załączam tą bibliotekę. Co ciekawe, gdy załączę ją w pliku klasa.cpp, kompilator nie wypluwa żadnych błędów. Wówczas jednak nie mam możliwości inicjacji obiektów we własnej klasie, a jest mi to niezbędne. Co robię źle?


(Fizyda) #2

Bo jak załączasz .h z svg to jest to tylko api tego komponentu który jest skompilowany gdzie indziej i linkowany przez linkera w momencie kompilacji. Jeśli zmieniasz .h gotowych bibliotek ich źródło nie zgadza się z plikiem nagłówkowym i masz błędy.

 

Jeśli chcesz edytować bibliotekę, pobierz jej cały kod źródłowy, edytuj skompiluj i dodaj do środowiska. Tylko tak się nie robi, bo potem będzie ktoś inny chciał wprowadzić zmiany w programie załączy oryginalną bibliotekę, a nie modyfikowaną przez Ciebie, bo skąd będzie wiedział że ktoś wpadł na pomysł modyfikowania gotowych bibliotek i nie będzie mógł skompilować kodu.


(kijek) #3

Niepotrzebnie dodałem informację o edycji kodu biblioteki, bowiem nie ma on związku z błędem, który pojawia się w trakcie kompilacji. Proszę również zwrócić uwagę, iż autor biblioteki nie dostarcza jej plików binarnych, a jedynie plik nagłówkowy z kodem, który includuję w swoim projekcie.


(Fizyda) #4

Podrzuć zmodyfikowaną bibliotekę.


(kijek) #5

Problem nie jest wynikiem dokonanych przeze mnie modyfikacji. Zwyczajnie zaincludowanie tego pliku do headera w moim projekcie powoduje wysypanie takich błędów. Poniżej przykładowy kod, wykorzystujący niezmodyfikowaną bibliotekę.

 

wykres.hpp

#include "simple_svg_1.0.0.hpp"



class Wykres

{

public:

	Wykres();

	~Wykres();



	void generujWykres();

};

 

wykres.cpp

#include "wykres.hpp"



Wykres::Wykres()

{



}



Wykres::~Wykres()

{



}



void Wykres::generujWykres()

{

    svg::Dimensions rozmiar(250, 300);

	svg::Document grafika("wykres.svg", svg::Layout(rozmiar, svg::Layout::TopLeft));

	grafika << svg::Rectangle(svg::Point(20, 20), 200, 20, svg::Color::Black);

	grafika.save();

}

main.cpp

#include "wykres.hpp"



using namespace std;



int main()

{

    Wykres nowyWykres;

    nowyWykres.generujWykres();

}

 

Jeśli teraz zaincludowałbym simple_svg_1.0.0.hpp w pliku wykres.cpp (usuwając include w wykres.hpp), to program skompilowałby się. Sęk w tym, że ja potrzebuję zainicjować obiekty svg::Dimensions i svg::Document w klasie, bowiem kilka metod ma operować na tych obiektach.


(Fizyda) #6

Ponieważ błędy są w bibliotece simple_svg.


(kostek135) #7

@OP Jak dla mnie teorie z błędami w bibliotece bez sensu.
Najbardziej prawdopodobne, to że nie pokazujesz nam poprawnej (takiej jak masz naprawdę) hierarchii include-ów i dołączasz nie wprost w swoich klasach bibliotekę (jej plik nagłówkowy) dwa razy (albo i więcej). Wnioskuję po tym, że jak coś gdzieś zmienisz w include-ach to ci zadziałało w jednym z postów. Żeby zobaczy czy faktycznie te funkcję się dublują jak mówią błędy (o multi definicjach) użyj: http://stackoverflow.com/questions/4900870/can-gcc-output-c-code-after-preprocessing żeby zapobiec temu błędowi skorzystaj z: https://en.wikipedia.org/wiki/Include_guard

PS
To jest aż nazbyt oczywiste:

obj\Release\chart.o:klasa.cpp|| first defined here|

obj\Release\main.o:main.cpp|| multiple definition of `svg::translateX(double, svg::Layout const&)'|

Znajduje pierwszą definicje danej metody w klasa.cpp, a potem kolejną w main.cpp
 


(kijek) #8

Istotnie, pokazany powyżej kod jest zupełnie inny od tego w moim projekcie. Jednakże nawet tak prosty kod nie chce się kompilować i wyrzuca te same błędy. Jak widać - jedynym miejscem, w którym includuję bibliotekę, jest wykres.hpp. Jeśli jednak przeniósłbym include z wykres.hpp do wykres.cpp , to program kompilowałby się bez problemu. I byłoby to do przeżycia, jednak ja potrzebuję obiektów svg::Dimensions i svg::Document zainicjowanych w klasie, jak niżej:
wykres.hpp

#include "simple_svg_1.0.0.hpp"



class Wykres

{

	svg::Dimensions rozmiar;

	svg::Document grafika;

	

public:

	Wykres();

	~Wykres();



	void generujWykres();

};

 


(Fizyda) #9

Jeśli o mnie chodzi to ja nie rozumiem co Ty robisz i kiedy Ci coś działa a kiedy nie, nie mam pojęcia jak wygląda kod i co gdzie przenosisz. Szklanej kuli nie posiadam bo oddałem do serwisu, a jak mam zgadywać to w dalszym ciągu utrzymuję że to przez błędnie edytowaną bibliotekę simple_svg.


(kijek) #10

Działa:

wykres.hpp

class Wykres

{

public:

	Wykres();

	~Wykres();



	void generujWykres();

};

wykres.cpp

#include "wykres.hpp"

#include "simple_svg_1.0.0.hpp"



Wykres::Wykres()

{

}



Wykres::~Wykres()

{

}



void Wykres::generujWykres()

{

    svg::Dimensions rozmiar(250, 300);

	svg::Document grafika("wykres.svg", svg::Layout(rozmiar, svg::Layout::TopLeft));

	grafika << svg::Rectangle(svg::Point(20, 20), 200, 20, svg::Color::Black);

	grafika.save();

}

main.cpp

using namespace std;



int main()

{

    Wykres nowyWykres;

    nowyWykres.generujWykres();

}

 

 

Nie działa:

wykres.hpp

#include "simple_svg_1.0.0.hpp"



class Wykres

{

public:

	Wykres();

	~Wykres();



	void generujWykres();

};

wykres.cpp

#include "wykres.hpp"



Wykres::Wykres()

{

}



Wykres::~Wykres()

{

}



void Wykres::generujWykres()

{

    svg::Dimensions rozmiar(250, 300);

	svg::Document grafika("wykres.svg", svg::Layout(rozmiar, svg::Layout::TopLeft));

	grafika << svg::Rectangle(svg::Point(20, 20), 200, 20, svg::Color::Black);

	grafika.save();

}

main.cpp

#include "wykres.hpp"



using namespace std;



int main()

{

    Wykres nowyWykres;

    nowyWykres.generujWykres();

}

 


(kostek135) #11

Nie mam  pod ręką kompilatora, więc spróbuj w tym drugim przypadku zrobić tak:
plik: wykres.hpp

#ifndef WYKRES_H

#define WYKRES_H



#include "simple_svg_1.0.0.hpp"

class Wykres {



public:

	Wykres();

	~Wykres();



	void generujWykres();



};



#endif // WYKRES_H

 


(kijek) #12

Niestety, include guard nie pomaga. Wciąż ten sam błąd.


(kostek135) #13

Po googlałem chwilę i wychodzi na to, że użytkownik @Fizyda miał rację. To jest błąd biblioteki związany z tym, że pliki znajdują się w innej jednostce translacji w zależności gdzie je załączysz: https://code.google.com/archive/p/simple-svg/issues błąd o id=2, w środku znajdziesz svn-owy patch, który ktoś wrzucił jako rozwiązanie problemu.


(kijek) #14

Dzięki serdeczne za pomoc :slight_smile: Mam jednak jeszcze jedno pytanie - jak zaaplikować plik .patch do pliku nagłówkowego?


(kostek135) #15

~ $ patch < simple_svg.patch # zakładając, że masz je w tym samym katalogu


(kijek) #16

Windows, niestety. Próbowałem już Windowsowego portu ale po wywołaniu wysypuje się. No nic, trzeba postawić GNU/Linuxa na wirtualce :slight_smile: