Skip to content

Features

Features enable automatic dependency resolution between components. A feature is a plain string that can be associated with a component using the provides keyword. Other components can depend on a feature using the requires keyword, or indicate that they are mutually exclusive using the conflicts keyword.

When a component requires a feature, it is up to the dependency resolver run during project generation to find another component that provides the feature. In the case where multiple components provide the same feature, the choice is deferred to the user, and the user records their preferred choice in the .slcp file.

Components cannot directly depend on each other by id, they must provide and require features. This allows additional components from the project or SDK extensions to replace the functionality of a component, and in general allows for multiple implementations of APIs for generic drivers.

A component may associate a condition with each of its provides, requires and conflicts. When guarded by a condition, the feature only comes into play when the condition matches a list of features provided by the project or its component dependencies. All features listed must be present for the condition to be active.

Dependency Resolution

A project is typically seeded with a list of components using the component keyword. These components typically require additional features, and dependency resolution is needed.

Dependency resolution can be considered a step-by-step process according to the following algorithm:

  1. The project contains a set of components C.
  2. The set of requirements R, provides P, and conflicts K are extracted from the set of components.
  3. The set of unsatisfied requirements U = R - P is computed. For each unsatisfied requirement:
    1. Find all components in the SDK that provide the unsatisfied requirement, while not providing anything in K.
      1. For this purpose, a component can be considered to provide a feature if all its conditions are satisfied by the set R + P, rather than just considering P. This is an optimization that takes advantage of the fact that outstanding requirements will be provided at some point, else dependency resolution will have failed.
    2. If only one new component is found, add it to C.
  4. If at least one component was added in step 3, continue from step 2.
  5. Dependency resolution is unable to add more components, and is considered finished:
    1. If all of the following conditions are true, the project has been resolved successfully.
      1. R is a subset of P
      2. No two components provide the same feature (unless the allow_multiple flag is set on all instances of the provide)
      3. K is disjoint from P
    2. If not, dependency resolution has failed.

If dependency resolution fails, the project generation tool shall present the failure and possible avenues of fixing it. This may include listing options when multiple components provide the same feature.

Recommendations

If dependency resolution fails because a required feature is provided by multiple candidate components, any component present in the partially resolved project may provide hints to further dependency resolution. Components may use the recommends key to recommend specific components by id. A recommended component is only considered for inclusion in the project if it provides a feature in the set of unsatisfied requirements U, and if its provided features are disjoint from those of all other recommended components. If the set of provided features is not disjoint from another recommended component, it is considered a conflict at the same level as if neither component was recommended, but the project generation tool may highlight these components when presenting a fix to the user, indicating that both may be better suited than a third component that wasn't recommended at all.

Given the list of recommended components considered for inclusion, only one recommendation is added to C at a time, re-starting the dependency resolution process after each addition. If multiple candidate components are considered for inclusion (each satisfying a different requirement), the first candiate component as sorted alphabetically by id is always selected.

A recommendation may specify one or more instance names for instantiable components. When added to the project, all instances are added. If different components recommend different instance names for the same component, the choice of what instance name to use must be given to the user in the same way as the choice between competing components for a feature.

If the user adds an explicitly named instance of a component to the project itself, this necessarily means that the automatically recommended instance is no longer in play, since the recommendation is no longer considered during dependency resolution. GUI tools shall attempt to notice when this happens, and prompt the user whether they desire to also make the recommended instances explicit, or continue with removing them. Alternatively, GUI tools may automatically make the recommended instances explicit without user interaction. This behavior is only possible when using a tool that watches the project and remembers the state of the previous project generation, and is therefore not required for CLI tools.

Back to top