QMAKE_EXTRA_COMPILERS in qmake

Reading time ~3 minutes

When reading the documentation for qmake one finds something called QMAKE_EXTRA_COMPILERS. The documentation is clear, but not really an everyday use-case. So I thought I would try to explain QMAKE_EXTRA_COMPILERS with a “real” use-case from a project I’m currently working on for one of Combitechs many customers.

Background

In this project we generate code based on the content of a number of XML-files. Maybe one day I should write a bit about why we are generating code and how we wrote the code-generator as well. But for now the only thing we need to know is that there is a list of XML-files that we use as input to the code-generator and out comes a number of header-files.

When I proposed the code-generator for the rest of the project I promised them that this should be simple and easy to use for the rest. I might have said something like:

Just a parameter with the XML-files in the pro-file

So integrating the code-generation into our qmake-based build was of highest priority. And thanks to QMAKE_EXTRA_COMPILERS it was fairly simple.

What does QMAKE_EXTRA_COMPILERS do

You can read the full documentation of QMAKE_EXTRA_COMPILERS at qt.io. But in short:

  • you setup an executable that qmake will execute.
  • you provide the executable with input argument. You do not have to do, but would be strange not to.
  • you add, if needed the output or data to some other qmake-parameter.

The example on qt.io is based around moc and how to setup your own moc-solution. But in this example we are going to pass a list of XML-files in to this.

Setting it up for code-generation

The goal was to keep the implementation in the main project file as simple as possible.

CG_INPUT += \
    fileA.xml \
    fileB.xml
include(code-generator.pri)

The above code will just create a parameter call CG_INPUT that, in this case, holds fileA.xml and fileB.xml. The next thing we do is to load code-generator.pri.

cg.name = "Internal code generator"
cg.input = CG_INPUT
cg.output = $$OUT_PWD/generated/${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)}
cg.variable_out = HEADERS
cg.commands = \
    $$OUT_PWD/../code-generator/bin/cg -s -o $$OUT_PWD/generated -r ${QMAKE_FILE_IN}
QMAKE_EXTRA_COMPILERS += cg

DISTFILES += CG_INPUT

Let’s look what the code above does. cg.name just sets a name on the extra compiler we are adding. cg.input = CG_INPUT tells the extra compiler what its input are, in this case our XML-files (fileA.xml and fileB.xml).

cg.output list the output files. This is where it starts to get a bit strange, to be honest. QMAKE_FILE_BASE is one of de “undocumented” things in qmake. What it will do is actually take the filename of, each and every, file from cg.input and remove the file-ending (.xml). After that we add the header-file ending. So our outputs, in this example, will be fileA.h and fileB.h.

cg.variable_out is very useful. You use that to tell which parameter to append the output files to. In this example we append them to the HEADERS-list. This will make sure qmake knows about them. cg.command is the command you would like to execute. I’ve used ${QMAKE_FILE_IN} as input to our code generator. ${QMAKE_FILE_IN} will be fileA.xml resp. fileB.xml. Because we have two XML-files this application will be called twice.

The last, and most important thing, is to append cgto the list of extra compilers. This is done by adding QMAKE_EXTRA_COMPILERS += cg. The name cg is short for code-generation but this variable could have any name, not just cg.

Running it in QtCreator/qmake

This setup makes the use and integration of a proprietary code-generator really simple in QtCreator and qmake. It requires a really small amount of code in the project files to pull this simple hack off.

One thing that took a while to understand is that qmake will execute the cg.command once for every file in CG_INPUT, but only if the output header-file is used somewhere in the code. Offcourse it holds dependencies “back” to the XML-file. If the XML-file content is change the code-generator will be executed on next compilation.

Using QML:s new DelegateChooser

Clang-Tidy is a really great tool that does static code analysis on your code. To be honest I've become a much better C++ developer thanks to Clang-Tidy. So how can this be integrated into CMake. Continue reading

Integrate Clang-Tidy into CMake

Published on February 06, 2019

Using ccache together with qmake and QtCreator

Published on January 30, 2019