This is a text-only version of the following page on https://raymii.org:
---
Title       : 	Add moc includes to speed up Qt compilation
Author      : 	Remy van Elst
Date        : 	12-12-2022
URL         : 	https://raymii.org/s/blog/Qt_add_moc_includes_to_speed_up_compilation.html
Format      : 	Markdown/HTML
---




The Meta-Object Compiler, `moc`, handles Qt's C++ extensions and it is required for signals and slots and properties in Qt. `moc` reads C++ header files and if the `Q_OBJECT` macro is used, it generates an extra `.cpp` file named `moc_filename.cpp` containing extra (meta-object) code. This post has a bit of background information and a shell script to automatically include `moc_*.cpp` files in your code whenever `Q_OBJECT` is used. If you use `qmake`, this will probably speed up your build and if you use `cmake`, this will probably speed up incremental builds (when `CMAKE_AUTOMOC` is `on`).

<p class="ad"> <b>Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called  Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p>


Below you'll find a shell script that scans your code for missing `moc_*.cpp`
includes and if you pass the `addinclude` flag, the script will add them for you.

Summarized heavily, by including your `moc_*.cpp` files you save the compiler
and linker some work allowing for faster builds and even some optimizations.
Together with something like `ccache`, [precompiled headers][6] and different
`qrc` files (one for assets and one for `.qml` code and scripts), you can
save quite a bit of time of your builds.

### Shell script to include `moc_*.cpp` files

I wrote this script back in 2020, but decided to post it now because
I recently got an email regarding it and had an interesting conversation
with the person (which requested to remain anonymous). 

Save the following file as `fixMocInclude.sh` in your project folder:

	#!/bin/bash
	# Copyright (c) 2022 Remy van Elst
	# This program is free software: you can redistribute it and/or modify
	# it under the terms of the GNU General Public License as published by
	# the Free Software Foundation, version 3.
	# This program is distributed in the hope that it will be useful, but
	# WITHOUT ANY WARRANTY; without even the implied warranty of
	# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	# General Public License for more details.
	# You should have received a copy of the GNU General Public License
	# along with this program. If not, see <http://www.gnu.org/licenses/>.

	for filename in $(grep --recursive --files-with-matches --extended-regexp 'Q_OBJECT|Q_GADGET|Q_NAMESPACE'); do 
		cppfile="${filename%.*}.cpp"; 
		if [[ -f "${cppfile}" ]]; then 
			if grep --quiet "#include \"moc_$(basename ${cppfile})\"" "${cppfile}"; then 
				echo "OK: ${cppfile} HAS moc include"; 
			else 
				echo -n "FAIL: ${cppfile} MISSES moc include. "
				if [[ ${1} == "addinclude" ]]; then			  
					echo "Addding include...";
	        echo "" >> ${cppfile}        
	        echo "#include \"moc_$(basename ${cppfile})\"" >> ${cppfile}
				else
					echo "Add this line to the end of the file: ";
					echo -e "\t#include \"moc_$(basename ${cppfile})\""
				fi
	      echo
			fi; 
		fi; 
	done

	if [[ "${1}" != "addinclude" ]]; then
		echo "Run this script (./${0}) with the flag 'addinclude' to automatically add the moc includes";
		echo "Warning: make sure you have a backup before running this script with that flag."
	fi

Example output, running on the [Leaf Node Monitoring][5] code base:

	OK: lib/src/versioncheck/VersionCheck.cpp HAS moc include
	OK: lib/src/traymenu/TrayMenu.cpp HAS moc include
	OK: lib/src/model/MainModel.cpp HAS moc include
	FAIL: lib/src/viewmodel/AboutViewModel.cpp MISSES moc include. Add this line to the end of the file: 
	        #include "moc_AboutViewModel.cpp"

The next part of the article bundles background information on `moc` and 
this specific optimization. 

### Background information regarding `moc`

Because the Qt documentation currently does not have clear and concise
instructions on this and most documentation on speeding up Qt builds is
spread all over the internet (forum, mailing lists, git repositories, YouTube
video's, etc), I have quoted (with sources) the most important statements
regarding including your `moc_*.cpp` files in one place.

Quoting the [Qt documentation][7]: 

> The Meta-Object Compiler, `moc`, is the program that handles Qt's C++ extensions.

> `moc` reads a C++ header file, if it finds one or more class declarations
  that contain the `Q_OBJECT` macro, it produces a C++ source file containing
  the meta-object code for those classes. Among other things, meta-object
  code is required for the signals and slots mechanism, the run-time type
  information, and the dynamic property system.

> The C++ source file generated by `moc` must be compiled and linked with the
  implementation of the class (or it can be `#included` into the class's
  source file). 

> If you use `qmake` to create your `Makefiles`, build rules will be included
  that call the `moc` when required, so you will not need to use the moc
  directly. For more background information on `moc`, see [Why Does Qt Use
  Moc for Signals and Slots][3]?

Interestingly, the line `(or it can be #included into the class's source
file)` only appears on [this page][3] and not in [the overview][7].

---


KDAB, a large Qt consulting firm, have a python [script][1] that 
does the same including a git hook, but that only was published 5 
months ago and required python. My script is older and only needs
bash. They have also published [a video][4] on the subject with 
benchmarks.


From the [KDAB][1] python repository, another quote:

If you are using `CMake`, you will probably have a line like this in your
`CMakeLists.txt` file:

    set(CMAKE_AUTOMOC ON)

This results in all `moc_*.cpp` files [being included from one file][8], namely
`mocs_compilation.cpp`. The advantage of this is that it speeds up the initial
build, but the disadvantage is that incremental builds (when you
for example touch just a single header file) will be much slower.

Including the `moc` files in the source files, gives us the best of both
worlds, both fast initial build and fast incremental builds.

---

Via `Sze Howe Koh` on [the Qt forum][2], regarding how the `moc_*.cpp` files are 
created and included in the build:

`qmake` is responsible for this. It scans your code and your `*.pro` file to
generate a `Makefile`. Your compiler and linker follow the "recipe" contained
in the `Makefile`. When you don't `#include "moc_myclass.cpp"`, your
QObject-based class spans 2 separate `*.o` files: 

	SOURCES       = ../src/main.cpp \
	                ../src/myclass.cpp moc_myclass.cpp
	OBJECTS       = main.o \
	                myclass.o \
	                moc_myclass.o

When you `#include` your moc file, `qmake` sees this and adjusts the `Makefile`
accordingly, so your class is fully contained within 1 `*.o` file:

	SOURCES       = ../src/main.cpp \
	                ../src/myclass.cpp
	OBJECTS       = main.o \
	                myclass.o



- KDE code and internal Qt code prefer the tactic of `#include` the
  `moc_file.cpp` in the corresponding `.cpp.` 
- This results in fewer `*.o` files fed into the linker. This has been shown
  to speed up builds. 
- This can at times enable the reduction of the header-to-header include
  graph, per [this email][10], which is a tactic I had mentioned on this
  other forum thread as being my main weapon overall against long rebuild
  times (in any C/C++ project, Qt or not). 
- Per the famous [Thiago Macieira (see here)][9], the `#include-your-moc` will
  also allow Clang to provide better diagnostics regarding your class.


---

Quoting [the Qt mailing list][9], regarding the fact that both KDE
and Qt do this (including `moc_` files):


	On Thursday, 28 May 2020 02:06:01 PDT Shawn Rutledge wrote:
	> > On 2020 May 27, at 17:50, Thiago Macieira <thiago.macieira@intel.com>
	> > wrote:> 
	> > On Wednesday, 27 May 2020 03:42:19 PDT Oswald Buddenhagen wrote:
	> >>> this is not something we can subject our users to.
	> >> 
	> >> orly? kde had been doing that for quite a while.
	> > 
	> > And I fixed QtCore to do the same.
	> > 
	> > The only reason not to include the moc output in your .cpp is if you don't
	> > have one (a header-only class whose only non-inline methods are the moc-
	> > generated ones). Otherwise, #include your mocs.
	> 
	> The reason is to speed up compilation, right?  Is there another reason?

	Aside from that benefit and the reason for this thread, it enables some 
	warnings in Clang that aren't otherwise. If it can see all members of a class, 
	including non-inline, it can tell if you forgot to use or initialise some of 
	them.

	Plus the benefit of more inlining, as there's more the compiler can see.


In that same thread, another reason is given to include your `moc_` files:

	Shawn Rutledge (28 May 2020 11:06)
	> The reason is to speed up compilation, right?  Is there another reason?

	Yes, see earlier in this thread: if you #include your .moc in your .cpp,
	your .h can get away with forward-declaring some classes whose headers
	it doesn't #include; the .moc may need to see the actual definition,
	rather than a forward declaration, and the .cpp shall do the needed
	#include, hence make the definition visible, which the .moc then
	benefits from by being #included in the .cpp.

		Eddy.


[1]: https://github.com/KDAB/KDToolBox/tree/master/qt/includemocs
[2]: https://web.archive.org/web/20221212124242/https://forum.qt.io/topic/117973/how-does-include-moc_-cpp-work/8
[3]: https://web.archive.org/web/20221212135618/https://doc.qt.io/qt-6/why-moc.html
[4]: https://www.youtube.com/watch?v=Cx_m-qVnEjo
[5]: https://leafnode.nl/
[6]: https://web.archive.org/web/20221212141026/https://doc.qt.io/qt-5/qmake-precompiledheaders.html
[7]: https://web.archive.org/web/20220922141034/https://doc.qt.io/qt-6/moc.html
[8]: https://web.archive.org/web/20221212142342/https://cmake.org/cmake/help/latest/prop_tgt/AUTOMOC.html#prop_tgt:AUTOMOC
[9]: https://web.archive.org/web/20221021073320/https://lists.qt-project.org/pipermail/development/2020-May/039657.html
[10]: https://web.archive.org/web/20221021073333/https://lists.qt-project.org/pipermail/development/2020-May/039654.html

---

License:
All the text on this website is free as in freedom unless stated otherwise. 
This means you can use it in any way you want, you can copy it, change it 
the way you like and republish it, as long as you release the (modified) 
content under the same license to give others the same freedoms you've got 
and place my name and a link to this site with the article as source.

This site uses Google Analytics for statistics and Google Adwords for 
advertisements. You are tracked and Google knows everything about you. 
Use an adblocker like ublock-origin if you don't want it.

All the code on this website is licensed under the GNU GPL v3 license 
unless already licensed under a license which does not allows this form 
of licensing or if another license is stated on that page / in that software:

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Just to be clear, the information on this website is for meant for educational 
purposes and you use it at your own risk. I do not take responsibility if you 
screw something up. Use common sense, do not 'rm -rf /' as root for example. 
If you have any questions then do not hesitate to contact me.

See https://raymii.org/s/static/About.html for details.