From 5ab38063471a456b03dcb13b59fb7de1c3a55b4f Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 31 Dec 2025 13:38:12 -0500 Subject: [PATCH] Improve configuration-related documentation - Separate configuration selection and description merging into separate documents and formalize "appendix" as the preferred term for supplemental, non-configuration-specific files. (This has been in use in other contexts, including CMake's implementation, but previously the specification itself did not provide a specific term for these.) This should also help the description merging documentation to be more discoverable, since, while configuration-specific files are one of the things that need merging, merging is not a sub-topic of configuration selection. - Clarify what contents are allowed in an appendix. (This information was previously missing.) Clarify meaning of `default_license` when used in an appendix. - Specify that configurations shall be treated as case insensitive. - Improve explanation of configurations and add much more extensive recommendations on how configurations should be used. - Fix minor error in multi-axis configuration example. --- configurations.rst | 96 ++++++++------------------- index.rst | 1 + merging.rst | 88 +++++++++++++++++++++++++ overview.rst | 2 +- recommendations.rst | 148 +++++++++++++++++++++++++++++++++++++++--- sample.rst | 2 +- schema-supplement.rst | 5 ++ schema.rst | 2 +- 8 files changed, 262 insertions(+), 82 deletions(-) create mode 100644 merging.rst diff --git a/configurations.rst b/configurations.rst index 1798477..ff88801 100644 --- a/configurations.rst +++ b/configurations.rst @@ -1,22 +1,42 @@ Package Configurations ====================== -Configurations provide a mechanism -for a package to provide multiple configurations -from a single distribution. -Such configurations might include -separate debug and release libraries, -builds with and without thread safety, -and so forth. +Configurations allow packages to provide +multiple "flavors" of binary objects +in a single distribution, +which have been compiled using different options +to facilitate different use cases. +Nominally, such objects must be *type-homogeneous*, +meaning all configurations of a component +must be of the same `type`_. +(See `Multi-Axis Configurations`_ +for a way to work around this restriction; +however, be aware of the caveats described therein.) + +Typical configuration axes include +presence or omission of instrumentation code, +optimization level, +and selection of interchangeable implementations. The possible configurations are determined by each individual package, and it is left to the consumer and build system to decide when and how to select a non-default configuration. +Refer to `Configuration Use Cases`_ for guidance +on what should or should not be expressed as a configuration. + +Like appendices, configurations support partial installation. +This allows a package to be built in several configurations, +while permitting users to install only one desired configuration. +Refer to `Description Merging`_ for additional information. + +Configuration Selection +''''''''''''''''''''''' When a consumer consumes a component, the build system must determine the attribute values for that component by selecting which configuration of the component to use (if the component has multiple configurations). +Selection shall treat configuration names as case insensitive. It is recommended that build systems select a configuration as follows: - For each package, the consumer shall have a mechanism @@ -60,68 +80,6 @@ otherwise, a value of :keyword:`null` shall be treated as the attribute being unset (and shall suppress falling back to the non-configuration-specific value). -Configuration Merging -''''''''''''''''''''' - -Some build systems may desire to output -separate specifications per configuration, -and/or to output separate CPS files per component. -This is especially useful to permit piecemeal installation -of individual components and/or configurations -(for example, a "base" package -with release libraries and common components, -an optional package with debug libraries, -and another optional package with optional components). - -When a tool locates a CPS file, :var:`name`\ :path:`.cps`, -the tool shall look in the same directory for any files -which match any of the patterns -(the asterisk (``*``) represents file globbing): - - - :var:`name`\ :path:`:`\ :glob:`*`\ :path:`.cps` - - - :var:`name`\ :path:`-`\ :glob:`*`\ :path:`.cps` - - - :var:`name`\ :path:`@`\ :glob:`*`\ :path:`.cps` - - - :var:`name`\ :path:`:`\ :glob:`*`\ :path:`@`\ :glob:`*`\ :path:`.cps` - - - :var:`name`\ :path:`-`\ :glob:`*`\ :path:`@`\ :glob:`*`\ :path:`.cps` - -Patterns containing colon (``:``) shall be skipped -on platforms for which that character -is not permitted in file names (e.g. Windows). - -If any such package specifications are found, -they shall be loaded at the same time, -and their contents appended to the information loaded from the base CPS. -(Note, however, that tools are permitted -to ignore the information in any such supplemental CPS file -as they may determine is not relevant to the user's needs. -In particular, see `Transitive Dependencies`_.) - -A ``.cps`` file whose name contains ``@`` -is a configuration-specific CPS. -The structure of a configuration-specific CPS -is the same as a common CPS, with three exceptions: - -- The only defined :object:`package` keys are - `name`_, `configuration`_, and `components `_. - The first two are required. - Use of other attributes specified in the schema is ill-formed. - -- The per-configuration specification may not specify - any :object:`component` attributes (e.g. :attribute:`type`). - Only :object:`configuration` attributes are allowed. - -- An attribute on a :object:`component` - is considered to belong instead - to the component-configuration - identified by the configuration-specific CPS. - -The order in which the data from multiple CPS files is appended -is implementation-defined. - .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. .. kate: hl reStructuredText diff --git a/index.rst b/index.rst index 67d8292..eb29fbd 100644 --- a/index.rst +++ b/index.rst @@ -57,6 +57,7 @@ Core Specification components configurations searching + merging Appendices '''''''''' diff --git a/merging.rst b/merging.rst new file mode 100644 index 0000000..d5dc799 --- /dev/null +++ b/merging.rst @@ -0,0 +1,88 @@ +Description Merging +=================== + +Some build systems may desire to output +separate specifications per configuration, +and/or to break a package's components into multiple output files, +often according to functional groups. +This is especially useful to permit piecemeal installation +of components and/or configurations +(for example, a "base" package +with release libraries and common components, +an optional package with debug libraries, +and another optional package with optional components). +This also allows build tools to import only those components +which are actually required by a consumer. + +When a tool locates a CPS file, :var:`name`\ :path:`.cps`, +the tool shall look in the same directory for any files +which match any of the patterns +(the asterisk (``*``) represents file globbing): + + - :var:`name`\ :path:`:`\ :glob:`*`\ :path:`.cps` + + - :var:`name`\ :path:`-`\ :glob:`*`\ :path:`.cps` + + - :var:`name`\ :path:`@`\ :glob:`*`\ :path:`.cps` + + - :var:`name`\ :path:`:`\ :glob:`*`\ :path:`@`\ :glob:`*`\ :path:`.cps` + + - :var:`name`\ :path:`-`\ :glob:`*`\ :path:`@`\ :glob:`*`\ :path:`.cps` + +.. note:: + + Patterns containing colon (``:``) shall be skipped + on platforms for which that character + is not permitted in file names (e.g. Windows). + +If any such package specifications are found, +they shall be loaded at the same time, +and their contents appended to the information loaded from the base CPS. +However, tools are permitted and encouraged +to ignore the information in any such supplemental CPS files +as they may determine is not relevant to the user's needs. +In particular, see `Transitive Dependencies`_.) + +A ``.cps`` file whose name contains ``@`` +is a configuration-specific CPS. +The structure of a configuration-specific CPS +is the same as a base CPS, with three exceptions: + +- The only defined :object:`package` keys are + `name`_, `cps_version`_, `configuration`_, + and `components `_. + The first three are required. + Use of other attributes specified in the schema is ill-formed. + +- The per-configuration specification may not specify + any :object:`component` attributes (e.g. :attribute:`type`). + Only :object:`configuration` attributes are allowed. + +- An attribute on a :object:`component` + is considered to belong instead + to the component-configuration + identified by the configuration-specific CPS. + +A ``.cps`` file which supplements the components +of the package's base CPS +is known as an "appendix". +The structure of a CPS appendix +is the same as a base CPS, with two exceptions: + +- The only defined :object:`package` keys are + `name`_, `requires `_, `default_license`_ + and `components `_. + The first is required. + Use of other attributes specified in the schema is ill-formed. + +- An appendix may not specify components + which are described in the base CPS + or in any other appendix. + +The order in which the data from multiple CPS files is collated +is implementation-defined. +Behavior when a supplemental CPS file's `cps_version`_ +differs from the base CPS's version +is implementation-defined. +(However, for obvious reasons, +this is strongly discouraged.) diff --git a/overview.rst b/overview.rst index add0d1e..d6287c8 100644 --- a/overview.rst +++ b/overview.rst @@ -75,7 +75,7 @@ Advantages of CPS CPS allows a package to provide targets in multiple configurations, with no restriction on the naming of configurations. - Use of interface targets (see `Configurations as Flags`_) + Use of interface targets (see `Multi-Axis Configurations`_) allows consumers to select the appropriate configuration by specifying target points along multiple axes. This especially facilitates creation and use of packages diff --git a/recommendations.rst b/recommendations.rst index fdc9cdb..d8757f5 100644 --- a/recommendations.rst +++ b/recommendations.rst @@ -1,15 +1,130 @@ Usage and Implementation Recommendations ======================================== -Configurations as Flags +Configuration Use Cases ''''''''''''''''''''''' +First and foremost, package authors are **strongly recommended** +to set `configurations (package)`_ +to a sensible list of default configurations +if their package provides multiple configurations. +This ensures that consumers +never fall back on unspecified behavior +when selecting a configuration. +The first default should be the configuration +that is most likely to be used by consumers +and/or is the most "safe" choice. +Additional, frequently used configurations +may be listed in priority order, +especially for packages where it would be reasonable +for the only available (installed) configuration +to be other than the first choice. + +Recommended Use Cases +^^^^^^^^^^^^^^^^^^^^^ + +Because CPS configurations originated in CMake +and from the need to support CMake's existing usage, +it is natural that they support and expect similar use-cases. +In the context of CMake, configurations would typically be used +to select between possible build options, +but not between different configuration options. +While the line between these can be fuzzy, +a guideline we would recommend is that configurations +should select between *functionally compatible artifacts*. +The most typical usage in extant CMake projects |--| +selecting between builds with and without debug information, +or compiled at different optimization levels |--| +is an excellent example of a recommended use. + +A similar suggested use is to select between builds +which have various levels of instrumentation enabled. +This might take the form of internal mechanisms, +or might encompass ABI-visible changes, +such as compiler-implemented "sanitization" functionality +("asan", "tsan", "ubsan", etc.). + +Again, none of these use cases affect the *function* of an artifact. +This means that, in principle, a consumer's configuration selection +does not affect program behavior (aside from performance considerations). +In an ideal world, configurations would also be *ABI compatible*. +However, in practice, heterogeneous configuration selections +may result in incompatibilities. + +At this time, the safest course of action +is to provide one or more configurations +which are ABI compatible with 'production-ready' artifacts. + +Borderline Use Cases +^^^^^^^^^^^^^^^^^^^^ + +Without departing from our principle of functional interchangeability, +a library might offer internal differences +that do not affect its logical behavior, +such as providing multiple back-ends to accomplish the same task, +using different memory allocators internally, +or enabling parallel processing via OpenMP or GPU compute. +This seems like another good use case for configurations. +Another 'obvious' case is when offering both static and shared libraries. + +A significant concern with these use cases, however, +is that they are likely to be orthogonal to, +and used in combination with, +the recommended "build style" use cases. +This shows that, in reality, +"configuration" is a combinatorial space +which is presently represented +only by a one-dimensional value. + +At this time, we advise caution in choosing to use configurations +for the sorts of use cases described in this section. +While not impossible (see `Multi-Axis Configurations`_, below), +current tooling support is limited, +and problems may arise. + +Non-Recommended Use Cases +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Selecting Between Functionally Incompatible Libraries: + As noted above, we advise using configurations + only for selection of *functionally interchangeable* builds. + Accordingly, we do *not* recommend using configurations + to select between builds that provide different feature sets + (for example, a network library with or without SSL support). + + Additionally, to the extent that consumers + may need to be aware of such optional features + when they do not otherwise affect the build interface, + we recommend using symbolic components + to communicate the availability of such optional features. + +Selecting Between Semantically Incompatible Libraries: + Use of configurations to select different components for linking + is discouraged, both because of the combinatorial challenges, + and because it makes it more difficult for consumers + to understand what components are ultimately being linked. + Additionally, selection of semantics + (e.g. static vs. shared libraries) + should typically be left to the user + who is compiling the project and organizing the build environment, + rather than being enforced by the consuming project. + +Selecting Between Incompatible Platforms: + Although platform compatibility is an area + which is still very much under development in CPS, + it is likely that compatibility will be expressed at the package level. + Therefore, we do not recommend using configurations + as a mechanism for platform selection. + +Multi-Axis Configurations +''''''''''''''''''''''''' + Let's say your package includes several configurations of a library, where the configuration is logically specified as a set of orthogonal attributes (e.g. debug/release, static/shared). -What's the best way to provide these to your users? +How can this be exposed to consumers? This is best accomplished via interface components. For example: @@ -34,8 +149,8 @@ For example: "foo": { "type": "interface", "configurations": { - "static": { "requires": [ "foo-static" ] }, - "shared": { "requires": [ "foo-shared" ] } + "static": { "requires": [ ":foo-static" ] }, + "shared": { "requires": [ ":foo-shared" ] } } }, }, @@ -52,12 +167,23 @@ The tool will then select the transitive component on the remaining debug/release axis. Longer chains can be constructed to support configuration choices of arbitrary complexity. -Where appropriate -(and assuming that the package does not wish to support -the user naming the "real" components directly), -the component graph can be constructed in a way -that allows shared attributes -to be specified at the higher level interface components. + +Be aware, however, that tooling support for this method is limited. +In particular, existing tools may not support the *creation* +of artifacts with different configuration sets within a single build, +which makes the construction of such package descriptions problematic. +Additionally, while direct use may be practical, +indirect consumers of packages using such techniques +may run into issues. + +It is hoped that the tooling ecosystem can improve in this respect, +however, at this time, anyone wishing to use such techniques +should be aware of the present limitations. +Nevertheless, it is recognized +that some projects, especially for legacy reasons, +may require the ability to allow consumers +to select from otherwise incompatible components +on the basis of configuration selection. Single Package, Multiple Platforms '''''''''''''''''''''''''''''''''' @@ -180,4 +306,6 @@ is not installed in the first place.) .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. ... .. +.. |--| unicode:: U+02014 .. em dash + .. kate: hl reStructuredText diff --git a/sample.rst b/sample.rst index ff6bb0d..eebf8bb 100644 --- a/sample.rst +++ b/sample.rst @@ -8,7 +8,7 @@ a compiled CABI library with four configurations an executable tool, and a Java archive. Many of the most commonly used attributes are demonstrated, -as is the technique discussed in `Configurations as Flags`_. +as is the technique discussed in `Multi-Axis Configurations`_. .. literalinclude:: sample.cps :language: json diff --git a/schema-supplement.rst b/schema-supplement.rst index eb8a4fb..f4a1e02 100644 --- a/schema-supplement.rst +++ b/schema-supplement.rst @@ -32,6 +32,11 @@ By definition, none of the following attributes are required. that are not reflected by a component (such as data files) when most or all of the compiled artifacts use the same license. + If specified by an appendix, + this shall apply to all components in the appendix + which do not specify a component-level `license`_, + superseding any information specified by the base CPS. + The value shall be a well formed |SPDX|_ `License Expression`_ . diff --git a/schema.rst b/schema.rst index f31d5cf..f4d239a 100644 --- a/schema.rst +++ b/schema.rst @@ -179,7 +179,7 @@ Attribute names are case sensitive. Specifies the name of the configuration described by a configuration-specific ``.cps`` - (see `Configuration Merging`_). + (see `Description Merging`_). This attribute is required in a configuration-specific ``.cps``, and shall be ignored otherwise.