Updated my weird QMake post
This commit is contained in:
parent
0a1db37273
commit
b44b667dd3
@ -1,24 +1,39 @@
|
||||
---
|
||||
layout: post
|
||||
title: QMake hackery: Dependencies & external preprocessing
|
||||
tags: Project, Technobabble
|
||||
status: publish
|
||||
type: post
|
||||
published: true
|
||||
date: November 13, 2011
|
||||
author: Chris Hodapp
|
||||
---
|
||||
* TODO: Put the code here into a Gist?
|
||||
|
||||
[Qt Creator](http://qt-project.org/wiki/Category:Tools::QtCreator) is a favorite IDE of mine for when I have to deal with miserably large C++ projects. At my job I ported a build in Visual Studio of one such large project over to Qt Creator so that builds and development could be done on OS X and Linux, and in the process, learned a good deal about [QMake](http://doc.qt.nokia.com/latest/qmake-manual.html) and how to make it do some unexpected things.
|
||||
[Qt Creator](http://qt-project.org/wiki/Category:Tools::QtCreator) is
|
||||
a favorite IDE of mine for when I have to deal with miserably large
|
||||
C++ projects. At my job I ported a build in Visual Studio of one such
|
||||
large project over to Qt Creator so that builds and development could
|
||||
be done on OS X and Linux, and in the process, learned a good deal
|
||||
about [QMake](http://doc.qt.nokia.com/latest/qmake-manual.html) and
|
||||
how to make it do some unexpected things.
|
||||
|
||||
While I find Qt Creator to be a vastly cleaner, lighter IDE than Visual Studio, and find QMake to be a far more straightforward build system for the majority of things than Visual Studio's build system, some things the build needed were very tricky to set up in QMake. The two main shortcomings I ran into were:
|
||||
* Managing dependencies between projects, as building the application in question involved building 40-50 separate subprojects as libraries, many of which depended on each other.
|
||||
* Having external build events, as the application also had to call an external tool (no, not **moc**, this is different) to generate some source files and headers from a series of templates.
|
||||
While I find Qt Creator to be a vastly cleaner, lighter IDE than
|
||||
Visual Studio, and find QMake to be a far more straightforward build
|
||||
system for the majority of things than Visual Studio's build system,
|
||||
some things the build needed were very tricky to set up in QMake. The
|
||||
two main shortcomings I ran into were:
|
||||
|
||||
QMake, as it happens, has some commands that actually make the project files Turing-complete, albeit in a rather ugly way. The **eval** command is the main source of this, and I made heavy use of it.
|
||||
* Managing dependencies between projects, as building the application
|
||||
in question involved building 40-50 separate subprojects as
|
||||
libraries, many of which depended on each other.
|
||||
* Having external build events, as the application also had to call an
|
||||
external tool (no, not `moc`, this is different) to generate some
|
||||
source files and headers from a series of templates.
|
||||
|
||||
QMake, as it happens, has some commands that actually make the project
|
||||
files Turing-complete, albeit in a rather ugly way. The `eval`
|
||||
command is the main source of this, and I made heavy use of it.
|
||||
|
||||
First is the dependency management system. It's a little large, but I'm including it inline here.
|
||||
|
||||
{% highlight bash %}
|
||||
```bash
|
||||
# This file is meant to be included in from other project files, but it needs
|
||||
# a particular context:
|
||||
# (1) Make sure that the variable TEMPLATE is set to: subdirs, lib, or app.
|
||||
@ -132,19 +147,38 @@ contains(TEMPLATE, "app") | contains(TEMPLATE, "lib") {
|
||||
contains(_valid, "false") {
|
||||
error("Don't recognize template type: " $${TEMPLATE})
|
||||
}
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
It's been sanitized heavily to remove all sorts of details from the huge project it was taken from. Mostly, you need to add your dependent projects into the "Table of Project Locations" section, and perhaps make another file that set up the necessary variables mentioned at the top. Then set the **DEPENDS** variable to a list of project names, and then include this QMake file from all of your individual projects (it may be necessary to include it pretty close to the top of the file).
|
||||
It's been sanitized heavily to remove all sorts of details from the
|
||||
huge project it was taken from. Mostly, you need to add your dependent
|
||||
projects into the "Table of Project Locations" section, and perhaps
|
||||
make another file that set up the necessary variables mentioned at the
|
||||
top. Then set the `DEPENDS` variable to a list of project names, and
|
||||
then include this QMake file from all of your individual projects (it
|
||||
may be necessary to include it pretty close to the top of the file).
|
||||
|
||||
In general, in this large application, each sub-project had two project files:
|
||||
* One with **TEMPLATE = lib** (a few were **app** instead as well). This is the project file that is included in as a dependency from any project that has **TEMPLATE = subdirs**, and this project file makes use of the QMake monstrosity above to set up the include and library paths for any dependencies.
|
||||
* One with **TEMPLATE = subdirs**. The same QMake monstrosity is used here to include in the project files (of the sort in #1) of dependencies so that they are built in the first place, and permit you to build the sub-project standalone if needed.
|
||||
In general, in this large application, each sub-project had two
|
||||
project files:
|
||||
|
||||
...and both are needed if you want to be able to build sub-project independently and without making to take care of dependencies individually.
|
||||
* One with `TEMPLATE = lib` (a few were `app` instead as well). This
|
||||
is the project file that is included in as a dependency from any
|
||||
project that has `TEMPLATE = subdirs`, and this project file makes
|
||||
use of the QMake monstrosity above to set up the include and library
|
||||
paths for any dependencies.
|
||||
* One with `TEMPLATE = subdirs`. The same QMake monstrosity is used
|
||||
here to include in the project files (of the sort in #1) of
|
||||
dependencies so that they are built in the first place, and permit
|
||||
you to build the sub-project standalone if needed.
|
||||
|
||||
The next project down below sort of shows the use of that QMake monstrosity above, though in a semi-useless sanitized form. Its purpose is to show another system, but I'll explain that below it.
|
||||
...and both are needed if you want to be able to build sub-project
|
||||
independently and without making to take care of dependencies
|
||||
individually.
|
||||
|
||||
{% highlight bash %}
|
||||
The next project down below sort of shows the use of that QMake
|
||||
monstrosity above, though in a semi-useless sanitized form. Its
|
||||
purpose is to show another system, but I'll explain that below it.
|
||||
|
||||
```bash
|
||||
QT -= gui
|
||||
QT -= core
|
||||
TEMPLATE = lib
|
||||
@ -233,9 +267,15 @@ for(templatefile, GENERATOR_INPUTS) {
|
||||
# Also add our header files. I doubt it's really necessary, but here it is.
|
||||
HEADERS += $${HEADER}
|
||||
}
|
||||
{% endhighlight %}
|
||||
```
|
||||
|
||||
This one uses a bit more black magic. The entire **GENERATOR_INPUTS** list is a set of files that are inputs to an external program that is called to generate some code, which then must be built with the rest of the project. This uses undocumented QMake features, and a couple kludges to generate some things dynamically (i.e. the filenames of the generated code) from a variable-length list. I highly recommend avoiding it. However, it does work.
|
||||
This one uses a bit more black magic. The entire `GENERATOR_INPUTS`
|
||||
list is a set of files that are inputs to an external program that is
|
||||
called to generate some code, which then must be built with the rest
|
||||
of the project. This uses undocumented QMake features, and a couple
|
||||
kludges to generate some things dynamically (i.e. the filenames of the
|
||||
generated code) from a variable-length list. I highly recommend
|
||||
avoiding it. However, it does work.
|
||||
|
||||
These two links proved indispensable in the creation of this:
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user