Why is moc slow for some classes?
-
Hello,
I'm currently in the process of optimizing our build time and I figured that moc takes a significant time of our build. While usually, it takes about 0.6 sec for moc to produce moc_* file, for some headers, it takes about 6-10 sec (we have hundreds of such files). Does anyone know what can cause moc to be so slow? Are there any good practices what to avoid in headers parsed by moc?The typical file that takes long looks like this:
#ifndef GUARD #define GUARD namespace a { class Reader : public BaseR<A, B, C> { using BaseClass = BaseR<A, B, C>; public: explicit Reader(int); X read(const X& x) const; Y load() const; }; struct Traits { using A = B; using C = D; using E = F; static const int G = 1; static const int ID = 2; static const bool B = true; }; class Table : public BaseT<Traits> { Q_OBJECT using BaseClass = BaseT<Traits>; public: Table (A* a, B* b, C* c, D* d); protected: virtual Type getType() const override { return E_TYPE; } virtual B* getReader() const override; virtual void createDetails(const A* a, B* b) const override; }; } #endif
There are about 10 more base classes between BaseT and QObject. Can that be an issue?
The headers are usually not longer than 50 lines. Can it be the templated base class that causes the problem? Does moc need to instantiate the template?
Thanks for any help.
-
@Dan-Princ
not entierly sure, but it might help, to remove theQ_OBJECT
Makro in classes where you don't define any new Signals & Slots. -
@J.Hilk I would advice against. Documentation states:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.
-
@artwaw I have not measured, but the files that are slow are all similar and there are a few thousands other files on the project, which mostly take about 0.5-0.6 sec to parse, so it seems unlikely to be caused by I/O. (and obviously this is reproducible, it's not one time measurement)
@J.Hilk It is a possibility I'm considering, but we still use some other features of metaObject(), so it would require a little more effort.
-
Hi
moc does not expand templates. its not a compiler.I tried a few combinations but I could not make moc hang/be slow on any files.
Do you have a concrete example that compiles and is known to take extra time?
-
@Dan-Princ
ok, i understand.I did try with some class with lots of base classes but saw no effect.
Only by make extremely large .h file i could get time up but it sounds your case
is different. -
@Dan-Princ Just an idea: do you include many header files which include other header files and so on?
-
@jsulm Well if I compile the file with /showIncludes, it prints ~3800 includes (mostly from libraries - 2600 from boost, 500 from Qt). If I run preprocessor on the header file, it has about 780000 lines. But I don't know how relevant it is as these numbers will be similar for most of the files I think...
-
@Dan-Princ said in Why is moc slow for some classes?:
- 2600 from boost
Boost is a template library (mostly) and as any template library is notorious for terrible compilation times, which is a consequence of how templates work.
it has about 780000 lines
And you have your answer. That's a huge file to parse.
And by the way, as @mrjj already said, you can't mix templates andQObject
. -
@kshegunov That's a huge file to parse, true, but there are many other files that have similar (500000) number of lines after preprocessor and moc takes 0.6sec. So I'm not sure this is the main factor.
You can't put Q_OBJECT inside a template, but AFAIK you can have templated base class.
-
@Dan-Princ said in Why is moc slow for some classes?:
You can't put Q_OBJECT inside a template, but AFAIK you can have templated base class.
Yes if it doesn't derive from
QObject
you can do something like:class A : public QObject, public MyTemplatedClass< ... > //< QObject derived class always goes first! { };
But even then it's rather clumsy.
QObject
doesn't play well with templates.