this task discusses possible implementations of the syntax & semantics of user-level dependency constraints defined in QBS-1625.
conceptually, all available Modules (which may be Products) shall exist in a single logical pool, and one uses constraints to fish out the needed ones. that means that Depends items are basically filters.
it would appear that putting conditions into the Modules to make them filter themselves would be sufficient. this, however, has multiple downsides:
- it makes it hard to display the information in a meaningful way, because it's code rather than data
- it distributes (and duplicates) logic all over the place, which makes the system excessively verbose and hard to modify
- it requires that each tried Module is loaded and at least partially property-merged before the condition is evaluated, which complicates the loader and is a massive performance problem
therefore, it is preferable to introduce a mechanism which externally applies constraints to simple literal-assigned properties.
a module must constrain its dependencies to build variants which are compatible with its own configuration. compatibility-critical properties must be marked as such, so the exporter knows that it must put respective constraints into the generated Modules.
the easiest way to represent this for direct dependencies is by putting the constraints into the Depends items themselves, just as one would in Products.
for transitive dependencies, one might:
- generate dedicated configuration items which might be identical to the ones which need to be used to declare Project-wide constraints.
- generate nested Depends items. note that
- these items would be really quite a different thing than actual dependencies - more like dedicated items, just re-using the existing name (the syntax would be probably identical in either case). that can be considered ugly.
- it would be somewhat random inside which direct dependency the nested ones would end up, which is also somewhat ugly.
- beyond the first level, the hierarchy of the transitive deps can (and probably should) be flattened, to keep verbosity down and be independent of changes in the dependency structure.
constraints may propagate also in reverse: in a Product, one would typically configure/constrain the cpp module (usually implicitly by the host environment), but not the higher-level dependencies. the available candidates would be automatically constrained by their own declared dependencies.
in this model, module properties automatically become available as constraints. the naming and semantics of the resulting constraints are determined by hard-coded type-specific rules - the same way as already done for name and version. it may make sense to require marking which properties are usable as constraints, via PropertyOptions or better a new keyword.
in this model, constraints need to be declared explicitly.
compared to the automatic model, it is more flexible, but also more verbose, slower, complicates application in module providers (the constraints need to be applied to properties which aren't in a module yet), and would require explicit reverse rules to be at all applicable to configuring not yet built dependencies (QBS-1197).