moc cpp generation fails with "No relevant classes found. No output generated."



  • I have a class D11 that inherits from class B1 that inherits QObject. B1 has declared Q_OBJECT, and so does D11. (Well, D11 tries to). But I'm running into the infamous 'undefined reference to vtable' error in the constructor and destructor of D11.

    This issue has popped up many times before on these forums, and I have tried all the usual recommendations:

    1. The failing class is indeed in separate files (D11.h and D11.cpp).
    2. I have tried Build > Run qmake from QtCreator.
    3. Deleted the build dir, run qmake from QtCreator, and run build again.

    The moc build step to generate moc_D11.cpp results in the following:
    D11.h:0: Note: No relevant classes found. No output generated.
    and indeed, moc_D11.cpp is an empty file.

    I have many other files in my project with the exact same hierarchies:
    QObject <-- B1 <-- D11
    QObject <-- B1 <-- D12
    QObject <-- B1 <-- D13
    QObject <-- B2 <-- D21

    None of these have any problems. In particular, D12 and D13 that derive from B1 and are (obviously) fairly similar to D11 are fine and have their moc_D12.cpp and moc_D13.cpp generated just fine.

    This is being cross-compiled to an RPi, but not sure that that should matter. The moc command is fairly long, but I have checked it meticulously, switch-by-switch, between the versions that work (D12, D13) vs D11, which doesn't work.

    Unfortunately the project is both large as well as proprietary, so I cannot post it - and of course a toy example is not going to show this (and/or would be easy to resolve). Still, if there is anything else I can try, I will welcome suggestions.


  • Qt Champions 2018

    @vikramg Can you show your D11 class?



  • Not sure if it will help, but here is an obfuscated version. D11.h:

    #ifndef D11_H
    #define D11_H
    
    #include "b1.h"
    
    class B2;
    
    class D11 : public B1
    {
        Q_OBJECT  // <-- this is causing "undefined reference to vtable for D11" WHY!??
    public:
        D11(const B2& s);
        ~D11() override;
        void processRawData(const QByteArray& etba) override;
    
    protected:
        void initFSMs() override;
        void setLock(byte prefix) override;
        void dropLock() override;
        void updateFsm1(byte prefix) override;
        void updateFsm2(byte prefix) override;
        bool updateFsm3(byte dataByte) override;
        bool extractVals(byte dataByte) override;
        void signExtend(int& val) override;
    
    signals:
        void signal1();
        void signal2();
    
    private:
        const int CONST1    = 0b1000'0000;    
        const int CONST2    = 0b0100'0000;     
        const int MASK      = 0b0010'0000;     
    
        // About 15-20 int and bool private members here...
    
        enum class Fsm1State    { ...names here... };
        enum class Fsm2State    { ...names here... };
        enum class Fsm3State    { ...names here... };
    
        Fsm1State   mFsm1State;
        Fsm2State   mFsm2State;
        Fsm3State   mFsm3State;
    
        bool fn1(byte dataByte);
        bool fn2(byte dataByte);
        bool fn3(byte dataByte);
        bool fn4(byte dataByte);
    
    };
    
    #endif // D11_H
    

    D11.cpp:

    #include "d11.h"
    #include "B2dir/b2.h"
    
    D11::D11(const B2& s) : B1(s)
    {
        initFSMs();
    }
    
    D11::~D11()
    {
        qDebug("D11 dtor");
    }
    
    void D11::initFSMs()
    {
        mFsm1State  = Fsm1State::NAME1;
        mFsm2State  = Fsm2State::NAME1;
    }
    
    void D11::processRawData(const QByteArray &etba)
    {
        for (byte dataByte : etba) {
            
            . . .
    
        }
        emit mBase2.b2signal();
    
    }
    
    // Other vanilla member function definitions here...
    

    B1.h:

    #ifndef B1_H
    #define B1_H
    
    #include <QObject>
    ...other QIncludes here, like QByteArray etc...
    
    class B2;
    
    class B1 : public QObject
    {
        Q_OBJECT
    public:
        explicit B1(const B2& s, QObject *parent = nullptr);
        virtual ~B1();
    
        using byte = unsigned char;
    
    signals:    
    
    public slots:
    
    public:
        virtual void processRawData(const QByteArray& etba) = 0;
    
    protected:
    
        // some int/bool members here
    
        const B2& mBase2;
    
        virtual void initFSMs() = 0;
        virtual void setLock(byte dataByte) = 0;
        virtual void dropLock() = 0;
        virtual void updateFsm1(byte dataByte) = 0;
        virtual void updateFsm2(byte dataByte) = 0;
        virtual bool updateFsm3(byte dataByte) = 0;
        virtual bool extractVals(byte dataByte) = 0;
        virtual void signExtend(int& val) = 0;
    
    
    };
    
    #endif // B1_H
    

    B1.cpp:

    #include "b1.h"
    #include "B2dir/b2.h"
    
    B1::B1(const B2& s, QObject *parent) :
                    QObject(parent),
                    mBase2(s)
    {
        qDebug("B1 abstract base class ctor");
    }
    
    B1::~B1()
    {
        qDebug("B1 abstract base class dtor");
    }
    

    I'm happy to provide any specific additional information. I can comment out the Q_OBJECT in D11 and of course it builds just fine.


  • Lifetime Qt Champion

    Hi,

    Did you re-run qmake after adding the Q_OBJECT macro ?



  • @sgaist yes, see my first post. In particular, I have tried deleting the build directory, rerunning qmake and rerunning the entire build after that.



  • Is there a verbose mode to the moc command that will elaborate on the No relevant classes found?



  • Quite incredibly, it turned out that the moc error was because of moc parsing not being able to comprehend C++14 digit separators in the constants I had in the private section of my class! Removing the digit separators enabled the moc compilation to go through without errors! So this doesn't work:

    private:
        const int CONST1    = 0b1000'0000;
    

    This works:

    private:
        const int CONST1    = 0b10000000;
    

    I have found C++14 digit separator support to be abysmal within the Qt ecosystem, from Qt Creator to now moc. I will personally just stop using it till Qt 6 at least; hopefully it will improve by then :P


  • Lifetime Qt Champion

    Opening a feature request will be a better idea, it will make the issue known to moc's developers.



  • @sgaist How/where can I do that?


  • Qt Champions 2018

    Hi @vikramg,

    At bugreports.qt.io

    Please post a link to the report here too, so others can follow later. Thanks!



  • Remove (no clean) build directory and build project.



  • @SGaist @aha_1980
    Bug report here: https://bugreports.qt.io/browse/QTBUG-77421

    I also found other bugs filed against moc that one would need to watch out for:

    These will also result in the No relevant classes found error.


  • Lifetime Qt Champion

    Thanks for sharing your additional findings !


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.