Uploaded image for project: 'Qbs ("Cubes")'
  1. Qbs ("Cubes")
  2. QBS-995

add a generic way to constrain dependencies

    XMLWordPrintable

Details

    • Suggestion
    • Resolution: Unresolved
    • Not Evaluated
    • None
    • None
    • None

    Description

      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.

      Constraint Propagation

      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.

      Solution 1: Automatic Constraints

      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.

      Solution 2: Manual Constraints

      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).

      // file: Module.qbs
      // this is a hypothetical implementation of the Module Item itself,
      // just to demonstrate the concept.
      Item {
          property string name
          Constraint {
              // this is the "selector" property that can appear in Depends items.
              // this one actually matches the constrained property's name itself,
              // but this is not required.
              property string name
              // the callback is invoked on each candidateModule in the pool which
              // has not been eliminated by other Constraints yet. dependsItem is
              // the Depends item which is attempting to pull in this dependency.
              callback: { return candidateModule.name === dependsItem.name }
              // caveat: this operation is obviously slow. the implementation
              // could be smart enough to recognize callbacks which do a simple
              // equality comparison by their AST structure, and turn them into
              // a hash lookup. this would avoid the need to introduce a separate
              // syntax for this optimized type of Constraint.
          }
          property version version
          Constraint {
              property version versionAtLeast
              property version versionBelow
              callback: { return (!candidateModule.version || !dependsItem.versionAtLeast
                                  || candidateModule.version >= dependsItem.versionAtLeast)
                              && (!candidateModule.version || !dependsItem.versionBelow
                                  || candidateModule.version < dependsItem.versionBelow) }
          }
      }
      
      // file: MyModule.qbs
      Module {
          property string fnord
          Constraint {
              property string wantedFnord
              callback: { return !candidateModule.fnord || !dependsItem.wantedFnord
                                 || candidateModule.fnord === dependsItem.wantedFnord }
          }
      }
      
      // provide two alternative versions of the same Module.
      
      // file: dependency1.qbs
      MyModule {
          name: "dependency"
          version: "1.0"
          fnord: "knolf"
      }
      
      // file: dependency2.qbs
      MyModule {
          name: "dependency"
          version: "3.0"
          fnord: "knolf"
      }
      
      // now select one version explicitly.
      
      // file: dependant.qbs
      Product {
          name: "dependant"
          Depends {
              name: "dependency"
              versionAtLeast: "2.0"
              wantedFnord: "knolf"
          }
      }
      

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              Unassigned Unassigned
              buddenha Oswald Buddenhagen
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes