How to: Compile Qt projects which use the Q_OBJECT macro in Code::Blocks

I need to write some C++ cross-platform GUI code soon, and after umming-and-ahhing about whether to use GTK or Qt, I’ve decided to try out the latter despite the recent Microsoft buy-out. However, as soon as I started to get into it and write some simple GUI code, I hit a snag; Qt uses what it calls slots to bind buttons to functions, where a function that can be executed as an action is defined as being a slot. To give an example, if you had a integer counter and you wanted to add five to the counter when you clicked the “Plus Five” button, then your onPlusFive function which actually increments the counter would be considered a slot.

This is all well and good, until you write the code and it won’t compile – instead giving you errors about vtables and such. To fix this, you need to do two things, the first of which is to add the Q_OBJECT macro definition to your QWidget-extending class.


I’m really new to Qt, so any experienced coders might roll their eyes at this – but I expected to be able to just write some code that creates a window, some buttons, layouts, menu options etc, and then just compile it and we’re good to go a-la Java’s AWT/Swing interface kits. But no, unfortunately not. Instead, you have to add the Q_OBJECT macro to your class like this, and then do some pre-processing:

#include <QtGui/QWidget>
#include <QtGui/QApplication>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
class Communicate : public QWidget
	Q_OBJECT // Define our class to use the Q_OBJECT macros (required for adding new slots)
		Communicate(QWidget *parent = 0); // Constructor
	private slots: // Functions for buttons
		void onPlusFive();
		void onMinusFive();
		QLabel *label;

That doesn’t seem too bad, right? You just plonk the word Q_OBJECT at the top of your class, and list all slots (functions that get executed as button actions) under the private slots: label. Well, yeah – it’s not so bad, but it’s not going to work that easily either. For this to work properly, we also need to do some pre-processing with a Qt utility called moc

Moc Pre-processing Steps

AFAIK, the pre-processing that needs to occur must happen on all header files (and header files only) that utilise Qt in your project. You can do it by hand like this:

moc <some-class>.h -o moc_<some-class>.cpp

For example, if you had a MainWindow class separated into .h and .cpp files, you might run:

moc MainWindow.h -o moc_MainWindow.cpp

Once that’s done, you need to add the newly generated moc_MainWindow.cpp file (for this example) to your Code::Blocks project, and it’ll all compile and work as expected.

So good so far, but what happens when you add a new slot? Yup, you have to go and manually re-run the command on all header files to generate the new moc_<some-class>.cpp files before it’ll play ball again – well sod that, let’s automate it!

Quick & Dirty Pre-Processing via Bash

I’m sure there are better ways of invoking the moc as a pre-build script, but I don’t know enough about pre-processing scripts to get it working (however, you might like to read this and have more luck than I did) – so I knocked together a quick bash script to generate all the moc files for us, like this:

genQtMoc Script

# Script to generate Qt moc files for all headers in the current directory | 16/06/2011 | r3dux
# For each header file in the current directory...
for file in ./*.h; do
	# If a file exists with a given extension...
	if [ -e "$file" ]; then
		fileWithoutPath=$(basename $file)
		moc "$file" -o "$mocName"
	fi # End of if file exists condition				
done # End of for each file loop

This is fine if all your .cpp and .h files are in the same folder like the project root, but if you’ve split them off into include and src directories you’ll have to twiddle the script a little to take that into account.

Putting it to work

Once you’ve put the script into a file called genQtMoc or such, and made it executable with chmod +x genQtMoc, sling it somewhere in the path like /usr/local/bin/ and we can then call for it to be executed as a pre-build script in Code::Blocks by going to Project | Build options… | Pre/post build steps and just putting the name of the script to call in the pre section, like this:

Code::Blocks Pre-Build Script

All sorted – the only other thing to re-iterate is that you need to have each moc_<some-file>.cpp file attached to your project, and that if you have the file open for editing in Code::Blocks, it’ll moan that “the file has been changed externally, would you like to reload it?” each time its contents change. You can get around this by simply not having the file open for editing (but still included in your project), which stops the annoying pop-up from occurring and is fine as it’s an auto-generated file that shouldn’t really be hand-edited anyway.

Anyways, I hope this helps anyone stuck in a similar situation – and please, if you do know a better of way of going about this, I’d love to hear about it. Cheers!

8 thoughts on “How to: Compile Qt projects which use the Q_OBJECT macro in Code::Blocks”

  1. Thanks.. helped me alot here .. I was stuck for a while with the

    undefined reference to vtable

    error. Your tip helped me solve the problem

  2. i had a problem with your linux bash script(eror), the bat script for windows worked as it should(thanks).
    here is a fix(and it is a recursive)

    for filename in `find . -type f -name "*.h" | sed 's/.h*$//g' | sed 's/.\///g'` ; do echo moc $filename.h -o moc_$filename.cpp ; done ; unset filename
  3. the echo was for testing..
    it should be (i have just removed the echo)

    for filename in `find . -type f -name "*.h" | sed 's/.h*$//g' | sed 's/.\///g'` ; do moc $filename.h -o moc_$filename.cpp ; done ; unset filename

    you welcome )

  4. Thanks for this post. I used a slightly more ghetto solution based on it:

    In project->build options, under pre/post build steps, in the field pre-build steps, I add something such as:

    moc include/mainwindow.h -o src/moc_mainwindow.cpp

    If you do this for every class, it should all compile/link. It’s working for me so far

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.