QBS: qbs fails to run moc when class is declared through a macro in another file

220 Views Asked by At

In my project I need to create QObject derived classes (with Q_OBJECT and signals) using a macro. The macro resides in a separate file. Here is a simplified example:

The macro is declared in the file CreateQtClass.h:

#ifndef __CREATEQTCLASS_H__
#define __CREATEQTCLASS_H__

#define CREATE_QT_CLASS( ClassName ) \
class ClassName : public QObject \
{ \
  Q_OBJECT \
\
 signals: \
  Q_SIGNAL void mySignal( void ); \
}; 

#endif //__CREATEQTCLASS_H__

I use the macro to create my class in the file MyQtClass.h

#ifndef __MYQTCLASS_H__
#define __MYQTCLASS_H__

#include <QObject>
#include "CreateQtClass.h"

CREATE_QT_CLASS( MyQtClass );

#endif //__MYQTCLASS_H__

In my .qbs file, I add MyQtClass.h to the files property, like this:

import qbs

QtApplication {
    name: "HelloWorld-Qt"
    files: [ "main.cpp", "MyQtClass.h" ]
}

Now, when running qbs build, qbs doesn't run 'moc' on MyQtClass.h. It looks like it doesn't do the scanning correctly, and doesn't detect the Q_OBJECT inside the macro.

(I may note that if the macro declaration and usage are in the same file, everything works fine).

My question:

Is there a way for the user to manually force qbs to run 'moc' on a file?

Maybe we need something like a "force_moc" fileTag (the opposite of "unmocable") which I can apply to a group containing MyQtClass.h.

Addition:

I am adding a simple Makefile and main.cpp to demonstrate that moc works well with the above approach:

The file main.cpp:

#include <QDebug>
#include "MyQtClass.h"

static void mySlot( void )
{
  qDebug() << "Hello slot";
}

int main( void )
{
  MyQtClass c;
  QObject::connect( &c, &MyQtClass::mySignal, &mySlot );
  emit c.mySignal();
  return 0;
}

The Makefile:

CXX = /usr/bin/g++
MOC = /home/user/programs/Qt5.11.2/5.11.2/gcc_64/bin/moc

INCLUDES = \
    -I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/include \
    -I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/include/QtCore \
    -I/home/user/programs/Qt5.11.2/5.11.2/gcc_64/mkspecs/linux-g++ \
    -I/usr/include

LINK_FLAGS = \
    -Wl,-m,elf_x86_64,-rpath,/home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib \
    -L/home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib \
    -m64 /home/user/programs/Qt5.11.2/5.11.2/gcc_64/lib/libQt5Core.so.5.11.2 \
    -lpthread

C_FLAGS = \
    -g \
    -O0 \
    -Wall \
    -Wextra \
    -m64 \
    -pipe \
    -fexceptions \
    -fvisibility=default \
    -fPIC \
    -DQT_CORE_LIB \
    $(INCLUDES) \
    -std=c++11

SOURCES = main.cpp
OBJS = $(SOURCES:%.cpp=%.cpp.o)

HEADERS_THAT_NEED_MOC = MyQtClass.h
MOC_OBJS = $(HEADERS_THAT_NEED_MOC:%.h=moc_%.cpp.o)

all: HelloWorld-Qt

HelloWorld-Qt: $(OBJS) $(MOC_OBJS)
    $(CXX) $^ $(LINK_FLAGS) -o $@

%.cpp.o : %.cpp
    $(CXX) $(C_FLAGS) -c $^ -o $@

moc_%.cpp: %.h
    $(MOC) -DQT_CORE_LIB $(INCLUDES) $^ -o $@

clean:
    rm -f *.cpp.o HelloWorld-Qt moc_*.cpp
1

There are 1 best solutions below

5
On

I don't think your approach can work, independent of the build tool you use. Keep in mind that moc looks for the Q_OBJECT macro. No such macro can ever be found in MyQtClass.h, because neither moc nor the build tool supporting it will expand the CREATE_QT_CLASS macro, because macro expansion would also expand away Q_OBJECT. Note that if you add CreateQtClass.h to your qbs file, you will notice that qbs does run moc -- but on the CreateQtClass file. That's the correct behavior, because that's where the Q_OBJECT macro occurs. I double-checked with qmake and cmake, and they all behave the same way: If you do not list CreateQtClass in the project file, they will not run moc. If you do list it, moc is run on that file. If you want to keep using your macro, you'll have to make sure to reference Q_OBJECT at the calling site, e.g. as a macro parameter. But even then, I'm not sure moc itself will be fond of that construct.