[QBS] Proposal: improvements to the config system

devtomsci at me.com devtomsci at me.com
Thu Mar 22 17:12:40 CET 2012

Hi list,

I've been thinking about the interaction between properties that are set in qbs files, on the command line and by "qbs config", and it feels like a little rationalising is needed.

The biggest problem is that properties effectively have 3 different names, depending where you set them from. For example, to set the default platform from qbs config you set the key "defaults/platform":
qbs config --global defaults/platform mingw32

To specify the platform on the command line when building it is referred to as "platform" (ok "qbs.platform" can be used here too)
qbs build platform:mingw32

And in your qbs file to read the platform property you use "qbs.platform":
myprop: qbs.platform === "msvc2010" ? "something": "something else"

For setting up the qt version to use, the situation is even messier. For setting the default config it is "qt/default/path" (focussing on the simplest setup where only the path needs setting):
qbs config --global qt/default/path = D:\QtSDK-1.1\Desktop\Qt\4.7.2\mingw

On the command line it is "qt/core.qtVersionName" (thanks Joerg for answering that one!) which has another twist in that you're not specifying exactly the same thing:
qbs release qt/core.qtVersionName:x64

And inside a .qbs that property is "qtcore.qtVersionName" (depending on what id you've given the Depends block)
Depends { id:qtcore; name: "qt.core" }
property var x: qtcore.qtVersionName

On top of everything else, this all makes it very difficult to do a global search for everywhere a particular property is used.

The proposal:

1) Have the "qbs config" command-line use dot-separated properties just like the property syntax on the command-line and inside qbs files, rather than slashes.
For example instead of "qbs config defaults/platform" you'd say "qbs config defaults.platform". (Although as per (2) I propose this particular item is replaced by "qbs.platform" instead).

I know internally config is implemented using QSettings which uses slashes but there's no real reason the user has to be concerned with that implementation detail. It would be simpler for the user to have only one syntax to remember. They can be mapped into QSettings-compatible slash-separated paths internally.

2) All properties should use the same fully-qualified name wherever they are accessed

So instead of using "defaults/platform" you would have a global config value for the key "qbs.platform", which could be overridden on the command-line with "qbs.platform:x86" (or, as currently, "platform:x86" for convenience). Another way of looking at this is that the config keyspace should mirror the module and property layout. This has a few corollaries:

2a) Abolish (or deprecate) the "defaults" group in qbs config

I think pretty much everything currently in the defaults group would move into the "qbs" group, as they all map directly to properties in the qbs module. (Except for defaults/qtVersionName, see (3) for info on that)

2b) Everything set in "qbs config" are automatically set as properties, as if every key in the config were specified on the commandline

This would simplify .qbs files as they wouldn't need to worry about explicitly using qbs.configurationValue() to support config and thus it will be less places for bugs/typos to sneak in. Instead modules would just define properties and they would magically get set from the config in the same way as if they were specified manually on the command-line today. It would also mean that all properties could be specified in qbs config without qbs files having to explicitly support it.

2c) Properties in submodules should be referrable to using the syntax module.submodule.property even in .qbs files

Remove the slightly messy workaround of using an id inside the Depends:
Depends { name: "qt.core" } // no "id:qtcore" needed
property var x: qt.core.version // Rather than qtcore.version or whatever

and on the command line:
qbs qt.core.version:4.7.2

3) Rework how the "qt" config group and qtcore module properties work

The "qt" group in qbs config is a slightly special case because it doesn't map directly onto a module, and rather it defines a set of configurations for the qtcore module. So it's not possible to make use of the automatic propagation of config keys to module properties I proposed above. There are 2 possibilities that occur to me:

3a) Continue with qt/qtVersionName/settings

This would be largely the same structure and qtcore.qbs file as now, although I think "defaults/qtVersionName" should move to "qt.configName" or somesuch:
qt.configName: "x64" // If undef, assume "default"
qt.default.path: "D:\QtSDK-1.1\Desktop\Qt\4.7.2\mingw"
qt.x64.path: "D:\QtSDK-1.1\QtSources\4.7.2-msvc2010-x64"

And have the qtcore Module set qtPath, qtNamespace, binPath etc based on the value of qt.configName.

... or ...
3b) Take the proposed alias support and make it generic enough to support setting the Qt config using it

This would mean the qt properties are no longer a special case, and are just an example of a set of aliases (or perhaps "profile" would be a better word in this context) for the qtcore module. I like this option more because it means qtcore.qbs doesn't need to know anything about qbs.configurationValue() and the config path for a given setting is the same regardless of what Qt version you're using.

So from the point of view of the property namespace, qbs files would see:

qt.core.path: "D:\QtSDK-1.1\Desktop\Qt\4.7.2\mingw" // Or whatever
qt.core.binPath: // etc

The way we'd represent this in the QSettings keyspace would be something like this. I've modelled this on my setup where for a given qt version I need to set the architecture and platform at the same time - with this proposal these can be setup in exactly the same way.

profiles.myDefaultSetup.qt.core.path: "D:\QtSDK-1.1\Desktop\Qt\4.7.2\mingw"
profiles.myDefaultSetup.qbs.platform: "mingw32"
profiles.myDefaultSetup.qbs.architecture: "x86"

profiles.x64.qt.core.path: "D:\QtSDK-1.1b\QtSources\4.7.2-msvc2010-x64"
profiles.x64.qbs.platform: "msvc2010"
profiles.x64.qbs.architecture: "x86_64"

if you were to run "qbs build release --profile x64" then all the keys under profiles.x64 would be set (ie qbs.platform would be set to "msvc2010" etc)

There would have to be some way of specifying a default profile to use - for simple setups you could just set the relevant qbs.platform directly, but personally I like being able to define some configs and switch which is default. So maybe you'd have a top-level "profile" key which determined what profile(s) were enabled, something like:

profile: "myDefaultSetup"
profiles.myDefaultSetup.qt.core.path: "D:\QtSDK-1.1\Desktop\Qt\4.7.2\mingw"
profiles.myDefaultSetup.qbs.platform: "mingw32"
profiles.myDefaultSetup.qbs.architecture: "x86"
profiles.x64.qt.core.path: "D:\QtSDK-1.1b\QtSources\4.7.2-msvc2010-x64"
profiles.x64.qbs.platform: "msvc2010"
profiles.x64.qbs.architecture: "x86_64"

and then the command-line syntax could be:

qbs build release profile:x64

which would expand to (effectively)

qbs build release qt.core.path:D:\QtSDK-1.1b\QtSources\4.7.2-msvc2010-x64 qbs.platform:msvc2010 qbs.architecture:x86_64

That handles the case where you want to override the default profile, and how you express what profile(s) you want, without having to introduce any new syntax. I don't know if the "property:value" command line syntax supports arrays (nor does qbs config I imagine) so we'd probably want to allow multiple profiles to be enabled by using a comma separated format, eg: profile:x64,somethingElse

4) qbs should support a mode whereby all the calculated properties are dumped out

To aid debugging, especially if profiles from (3b) are being used, qbs should support a mode where it dumps out the complete tree of calculated properties, taking into account the global and local config, command line args, profiles, and the evaluations from the .qbs files themselves including additions to cpp.defines from Modules etc. In other words the full state from just before the build starts. For example:

D:\myproj> qbs properties release profile:x64
qbs.platform: "msvc2010"
qbs.architecture: "x86_64"
qbs.buildVariant: "release"
cpp.defines: ["UNICODE", "QT_GUI_LIB", "MY_PRODUCT_MACRO"]
cpp.includePaths: [...]
qt.core.path: "D:\QtSDK-1.1b\QtSources\4.7.2-msvc2010-x64"
qt.core.binPath: "D:\QtSDK-1.1b\QtSources\4.7.2-msvc2010-x64/bin"
project.myProperty: ...

Outstanding questions:

* Does this sound like a good idea, and something we'd want in qbs?
* Go with (3a) or (3b)? 3b seems to me to be the more elegant and powerful solution
* Currently I'm referring to "qt.core.path" etc because that's how the Qt qbs files are structured. It would be nice if we could eliminate the "core" bit somehow? But only if it can be done without invoking 'magic' :)

What do people think? Basically, it took me a couple of hours getting my head around the nuances of how config and properties work and interact, and I'd rather no-one else had to spend as long. I like the idea of unifying qbs config with the other ways of setting a property, and sorting out the qt path config using profiles which also can be used for setting the correct architecture/platform at the same time. All feedback welcome - I could even be persuaded to implement some of it if people are in favour :-)


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/qbs/attachments/20120322/2fa12d8b/attachment.html>

More information about the Qbs mailing list