Discussion:
[Scons-users] Two limitations of Qt's Moc invocations
Olivier Renaud
2018-05-24 09:58:40 UTC
Permalink
Hi,

I am trying to compile some Qt code using SCons. I am not the author of
this code. This is a public code
(https://github.com/itay-grudev/SingleApplication) that does not use
SCons, and that I want to integrate into my SCons-based project. I was
able to compile it and to make it work, but I encountered two issues
with SCons' Qt Moc invocation, and I'd like to share it with you.

Two important things to know about this project:
- There are 3 source files in the project: 1 cpp and 2 headers. The cpp
includes both, and one of the header includes the other.
- This project declares a class SingleApplication that inherits from a
base class. The base class can be QCoreApplication, QGuiApplication or
QApplication, and this is abstracted away using a macro as the name of
the base class (QAPPLICATION_CLASS).

My SConscript is basically:

env.Append( CPPDEFINES = {'QAPPLICATION_CLASS' : 'QApplication'} )
env.SharedLibrary('SingleApp', ['singleapplication.cpp'])

That is, I define the macro to select the base class I need, and I
compile the cpp file. This triggers the Automoc feature of Scons.

My first problem is that moc does only a partial job. It generates a moc
file only for one of the headers (moc_singleapplication.cc). This leads
to a link error down the road. I would expect Automoc to discover both
header files and to generate two files.

The workaround I found is to ask moc to run explicitly. My SConscript
became:

env.Append( CPPDEFINES = {'QAPPLICATION_CLASS' : 'QApplication'} )
obj = env.Moc(['singleapplication_p.h'])
lib = env.SharedLibrary('SingleApp', ['singleapplication.cpp', obj])

My second problem is that, at runtime, the following code fails:
qobject_cast<QApplication*>(mySingleApp);

qobject_cast does not rely on RTTI, but instead it uses the information
generated by moc to know the class hierarchy, and to check the validity
of the cast. In my case, moc did not understand that SingleApplication
inherits from QApplication. This is because the base class QApplication
is hidden behind a macro, and that moc did not know about the value of
this macro.

The workaround is to add an argument to the moc invocation, that defines
the value of this macro.

env.Append( CPPDEFINES = {'QAPPLICATION_CLASS' : 'QApplication'} )
env.Append(QT_MOCFROMHFLAGS = '-DQAPPLICATION_CLASS=QApplication')
obj = env.Moc(['singleapplication_p.h'])
lib = env.SharedLibrary('SingleApp', ['singleapplication.cpp', obj])

In my opinion, the correct thing to do when SCons invokes moc is to
forward all the macros defined in CPPDEFINES, so that moc has the same
knowledge of the macros as the compiler.

I hit these issues with both SCons 2.x and 3.0.1, on Windows 7 using
MSVC 2017. I am using Qt 5.9.0.

--Olivier Renaud

Loading...