0

I'm having an issue with a pretty simple code I am following the tutorial of chrono::engine http://www.chronoengine.info/mediawiki/index.php/Demo_fourbar I do not have much experience in C++ programming (I have some experience in Java), therefore I tried to define MyEventReceiver (a class from the tutorial) in a different file (MyEventReceiver.h and MyEventReceiver.cpp) to get my head around classic structure of a C++ code

Here is the version of the code

MyEventReceiver.h

#ifndef RECEIVER_H
#define RECEIVER_H

#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"
#include "core/CHrealtimeStep.h"

#include <irrlicht.h>


// Use the namespace of Chrono
using namespace chrono;

// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class MyEventReceiver : public IEventReceiver
{
public:
    MyEventReceiver(ChSystem* asystem, IrrlichtDevice* adevice,     ChSharedPtr<ChLinkEngine> aengine);
    bool OnEvent(const SEvent& event);
    void setText_enginespeed(IGUIStaticText* _text_enginespeed);
    IGUIStaticText* getText_enginespeed();
private:
    IGUIStaticText* text_enginespeed;
    ChSystem*       msystem;
    IrrlichtDevice* mdevice;
    ChSharedPtr<ChLinkEngine> mengine;
};

#endif

with the implementation as follows in MyEventReceiver.cpp

#include "MyEventReceiver.h"


// Constructor
MyEventReceiver::MyEventReceiver(ChSystem *asystem, IrrlichtDevice *adevice, ChSharedPtr<ChLinkEngine> aengine)
{
    // store pointer to physical system & other stuff
    // so we can tweak them by user keyboard
    msystem = asystem;
    mdevice = adevice;
    mengine = aengine;
}



bool MyEventReceiver::OnEvent(const SEvent& event)
{
    // check if user moved the sliders with mouse..
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = mdevice->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {
            case EGET_SCROLL_BAR_CHANGED:
                    if (id == 101) // id of 'engine speed' gui
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        double newspeed = 10*(double)pos/100.0;

                        // set the speed into engine object
                        ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
                        spe_funct->Set_yconst(newspeed);


                        // show speed as formatted text in interface screen
                        char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
                        text_enginespeed->setText(core::stringw(message).c_str());

                    }
            break;
            }

        }

        return false;
}


void MyEventReceiver::setText_enginespeed(IGUIStaticText* _text_enginespeed)
{
    text_enginespeed = _text_enginespeed;
}


IGUIStaticText* MyEventReceiver::getText_enginespeed()
{
    return text_enginespeed;
}

and the main file in Main_2.cpp (which I emptied, it gives me the same error with or without the code inside - which is basically only setting up the 3D engine Irrlicht and some mechanics features from the collision model of chrono::engine)

#include "MyEventReceiver.h"

int main()
{
    return 0;
}

Basically the code defines an event receiver, so that the user after running the program can interact with the 3D environment built from the chrono::engine and Irrlicht engine through GUI manipulation I define all the required libraries in the MyEventReceiver.h file and the required namespaces

The problem is that it does not compile (please note that I already tested the engines - with the same #include and using namespaces in just one file and it was working in a different project - ), i think the problem is coming from the structure of the header files

I got those lines of error

1>MyEventReceiver.obj : error LNK2005: "public: virtual bool __thiscall irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)" (?OnEvent@RTSCamera@scene@irr@@UAE_NABUSEvent@3@@Z) already defined in Main_2.obj
1>MyEventReceiver.obj : error LNK2005: "public: virtual void __thiscall irr::scene::RTSCamera::OnRegisterSceneNode(void)" (?OnRegisterSceneNode@RTSCamera@scene@irr@@UAEXXZ) already defined in Main_2.obj

etc... (it goes on like this) and the final mistake

1>C:\Users\****\Documents\Visual Studio 2010\Projects\TutorialChronoEngine\Debug\TutorialChronoEngine_2.exe : fatal error LNK1169: one or more multiply defined symbols found

I am using Visual Studio 2010 C++. I defined one global solution, and several projects in this very solution (the program I wrote above is one project among others) I am sure it must be pretty easy to solve, but can't really find the solution. Let me know if you need further details

Thanks a lot Best regards Vincent

Edit : If I put all the codes in one single file as follows

#include "physics/CHapidll.h"
#include "physics/CHsystem.h"
#include "irrlicht_interface/CHbodySceneNode.h"
#include "irrlicht_interface/CHbodySceneNodeTools.h"
#include "irrlicht_interface/CHdisplayTools.h"
#include "irrlicht_interface/CHirrWizard.h"

#include <irrlicht.h>



// Use the namespace of Chrono

using namespace chrono;

// Use the main namespaces of Irrlicht
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Get rid of the command windows that pops up when compiling and running
#ifdef _IRR_WINDOWS_
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif

IGUIStaticText* text_enginespeed = 0;

class MyEventReceiver : public IEventReceiver
{
public:

    MyEventReceiver(ChSystem* asystem,
                    IrrlichtDevice *adevice,
                    ChSharedPtr<ChLinkEngine> aengine)
    {
        // store pointer to physical system & other stuff
        // so we can tweak them by user keyboard
        msystem = asystem;
        mdevice = adevice;
        mengine = aengine;
    }

    bool OnEvent(const SEvent& event)
    {

        // check if user moved the sliders with mouse..
        if (event.EventType == EET_GUI_EVENT)
        {
            s32 id = event.GUIEvent.Caller->getID();
            IGUIEnvironment* env = mdevice->getGUIEnvironment();

            switch(event.GUIEvent.EventType)
            {
            case EGET_SCROLL_BAR_CHANGED:
                    if (id == 101) // id of 'engine speed' gui
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        double newspeed = 10*(double)pos/100.0;

                        // set the speed into engine object
                        ChFunction_Const *spe_funct = dynamic_cast <ChFunction_Const*> (mengine->Get_spe_funct());
                        spe_funct->Set_yconst(newspeed);

                        // show speed as formatted text in interface screen
                        char message[50]; sprintf(message,"Engine speed: %g [rad/s]",newspeed);
                        text_enginespeed->setText(core::stringw(message).c_str());
                    }
            break;
            }

        }

        return false;
    }

private:
    ChSystem*       msystem;
    IrrlichtDevice* mdevice;
    ChSharedPtr<ChLinkEngine> mengine;
};



int main(int argc, char* argv[])
{

    return 0;
}

In that way, I avoid defining several times functions from the Irrlicht 3D engine that are not defined as inline. Unfortunately, this way of coding can become really cumbersome if a project becomes big (having to define all classes that rely on the 3D engine in one unique .cpp file), is there a design pattern to follow so that it is possible to avoid multiple defined objects with each class defined in a separate file ?

Thanks a lot

Best

Vincent

Vincent
  • 1,616
  • 2
  • 16
  • 18
  • Your first eror mesage referrs to `irr::scene::RTSCamera::OnEvent`. This is not shown by your presented code. The code you present **is not the real code**. We are not telepathic. – Cheers and hth. - Alf Feb 09 '13 at 13:15
  • Is this the real code? The linker is complaining about functions being defined multiple times, which is usually the case when you define a function in a header without marking it as `inline`. – Andy Prowl Feb 09 '13 at 13:16
  • Thanks for your reply. Actually, irr::scene::RTSCamera::OnEvent are functions defined within the engine irrlicht. By including and using the 5 namespaces irr,core,scene,video,io,gui I can use those functions (it works well in an other project where I only use one file (without defining any other classes, just one main)). – Vincent Feb 09 '13 at 13:27
  • @Vincent: In my answer I tried to explain the most likely scenario, but I guess we need to see the `irrlicht.h` file in order to tell with 100% certainty. Please upload it somewhere and post a link. – Andy Prowl Feb 09 '13 at 13:33

1 Answers1

2

The linker is complaining about two of your functions being defined multiple times. As you could probably figure out from the errors, these functions are:

irr::scene::RTSCamera::OnEvent(struct irr::SEvent const &)
irr::scene::RTSCamera::OnRegisterSceneNode(void)

What's most likely happening here is that these two functions are defined in a header file, but:

  • Their definition does not appear directly in the class definition (so they are not implicitly declared to be inline);
  • Their out-of-class definition in the header file is not explicitly marked as inline.

As a result, if the header is included multiple times in different translation units (i.e. in different .cpp files), multiple definitions of the same functions will end up being present in the object code of those translation units.

When merging them, the linker will complain that you are breaking the ODR (One Definition Rule).

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Thanks a lot for your answer. The two functions you are mentioning are part of a global 3D library, therefore I would rather not modify them. What is the usual design pattern to deal with multiple include ? What I understood is that Main_2.cpp and MyEventReceiver.cpp both includes MyEventReceiver.h, which refers to the two functions that are not explicitly marked as inline. Then the compiler understands that I am defining twice those functions. I thought that using #ifndef RECEIVER_H #define RECEIVER_H ..code.. #endif would prevent such multiple compiling – Vincent Feb 09 '13 at 13:38
  • @Vincent: The include guards work in a single translation unit: if you `#include` the same header file multiple times from the same `.cpp` file, they will be included only once. However, each `.cpp` file is processed separately. See **[this Q&A](http://stackoverflow.com/questions/14425262/why-include-guards-do-not-prevent-multiple-function-definitions/14425299#14425299)** for more information. If those functions are not marked as `inline` and are defined in a header, then you can include that header only in one translation unit (`.cpp` file). – Andy Prowl Feb 09 '13 at 13:43
  • Thanks a lot that is a very helpful. I solved my problem by putting all the code inside Main_2.cpp file. Now it compiles and runs. Now I am wondering what would be the ideal solution to avoid having to put all files that rely on the irrlicht library in the same file ? It can become quite cumbersome having to define all classes that rely on the graphical 3D engine in one .cpp file. Thanks again for your help – Vincent Feb 09 '13 at 17:02
  • @Vincent: That's an unfortunate design of the `irrlicht.h` file, indeed. I do not see any other option at the moment than including that file in one translation unit only. Btw, if my answer helped you, please consider accepting it or at least upvoting it. – Andy Prowl Feb 09 '13 at 17:07
  • Hello, I solved my problem by inlining methods in the irrlicht.h file. Is there a drawback to this method ? I want to be cautious as I am modifying files from an external library. Thanks a lot – Vincent Feb 12 '13 at 16:53