Debug build fails while building in release works

Hey, I am currently having trouble getting the debug build working.
I am getting undefined reference to vtable for Effect’` as error from the linker.
But when I build it with build_type release the error disappears.
I have seen many workarounds with not using an inline destructor. But that just simply is not working for me.

Complete error:

Linking .pio\build\dev-lamp\firmware.elf
.pio\build\dev-lamp\src\effects\BasicEffect.cpp.o:(.literal._ZN11BasicEffectD2Ev+0x0): undefined reference to `vtable for Effect'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\dev-lamp\firmware.elf] Error 1

I have several child classes that implement the Effect class and only the BasicEffect class has problems while linking with build_typ = debug.

Effect.h:

#pragma once
#include <Constants.h>
#include <FastLED.h>

class Lamp;

class Effect
{
private:
    Lamp * lamp;/* data */
    bool needsSpectrum = false;
public:
    Effect(Lamp* owner) {
        lamp = owner;
    };
    virtual ~Effect() {};


    Lamp * getLamp() {
        return lamp;
    };

    bool getNeedsSpectrum() {
        return needsSpectrum;
    }

    void setNeedsSpectrum(bool newValue) {
        needsSpectrum = newValue;
    }

    virtual void run();
};

BasicEffect.h

#pragma once

#include "effects/Effect.h"

class BasicEffect : public Effect
{
private:
    /* data */
public:
    BasicEffect(Lamp* owner) : Effect(owner) {

    };
    void run();
    //Destuctor
    ~BasicEffect();
};

BasicEffect.cpp

#include "effects/BasicEffect.h"
#include <Lamp.h>

static const char* TAG = "BaiscEffectModule";

BasicEffect::~BasicEffect() {

}


void BasicEffect::run() {
    Lamp* lamp = getLamp();
    
    if (lamp->getPatternMode())
    {
        fill_palette(lamp->getLeds(), NUM_LEDS, lamp->getTransformingCounter(), lamp->getZoom(), *lamp->getObjPalette(), lamp->getBrightness(), LINEARBLEND);
    }
    else
    {
        fill_solid(lamp->getLeds(), NUM_LEDS, lamp->getCrntColor());
    }
    if (lamp->getEffect() == 6)
    {
        FastLED.setBrightness(dim8_raw(scale8(lamp->getMappedMSGEQ7(2), lamp->getBrightness())));
    }
    else
    {
        FastLED.setBrightness(lamp->getBrightness());
    }
    FastLED.show();
}

Normaly i wouldnt mind this and just keep using the build_typ = release but since i want to get the JTAG debugger working for my ESP32 in this project it seems like i need to take care of this error befor I can start the JTAG.

Any suggestions what causes this error?

Usually indicates that the .cpp file for the Effect class wasn’t found. I see you have implemented the class directly in a header file though. Does the error change when you split Effect.h into Effect.h and Effect.cpp for declaration and implementation?

I tryed :
Effect.h

#pragma once
#include <Constants.h>
#include <FastLED.h>

class Lamp;

class Effect
{
private:
    Lamp * lamp;/* data */
    bool needsSpectrum = false;
public:
    Effect(Lamp* owner): lamp(owner) 
    {

    };
    virtual ~Effect() = 0;

    Lamp * getLamp();

    bool getNeedsSpectrum();

    void setNeedsSpectrum(bool newValue);

    virtual void run();
};

Effect.cpp:

#include "effects/Effect.h"

Lamp *Effect::getLamp()
{
    return lamp;
}

Effect::~Effect()
{
}


bool Effect::getNeedsSpectrum()
{
    return needsSpectrum;
}

void Effect::setNeedsSpectrum(bool newValue)
{
    needsSpectrum = newValue;
}

Same error:

Linking .pio\build\dev-lamp\firmware.elf
.pio\build\dev-lamp\src\effects\Effect.cpp.o:(.literal._ZN6EffectD2Ev+0x0): undefined reference to `vtable for Effect'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\dev-lamp\firmware.elf] Error 1

At the same time as

? Regarding c++ - Undefined reference to vtable - Stack Overflow you might try to remove your virtual destructor to see if that’s the culptrit

If i remove the virtual Destructor it will always use the destructor of the Effect class?

I tried using a normal destructor, virtual and a pure virtual destructor.
Nothing seems to work.

Well…
I figured it out. The error messages were misleading since the error was not caused by the destructor rather than by the virtual run() method that was not implemented.

It still surprises me that running it in normal build mode did not have any problems compiling and linking the program but running it in debug build mode threw everything at me.

3 Likes

I’m pretty sure that’s standard operating procedure for compilers… they are very good at misleading and pointing to the wrong thing! :laughing: Usually because they choke on the next instruction, and whine about that, rather than saying ‘hang on a minute… how did I get here?’ :man_facepalming:

I am so thankful I found this; I had the same problem, and just like you pointed out, the error message led me in so many directions but the right one.