Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 69 additions & 2 deletions _extensions/cps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
import jsb

from sphinx import addnodes, domains
from sphinx.roles import XRefRole
from sphinx.util import logging
from sphinx.util.docutils import SphinxRole
from sphinx.util.nodes import clean_astext
from sphinx.util.nodes import clean_astext, make_refnode

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -300,6 +301,19 @@ def run(self):
node = nodes.reference(self.rawtext, self.text, refuri=uri)
return [node], []

# =============================================================================
class AttributeRefRole(XRefRole):
refdomain = 'cps'
reftype = 'attribute'
classes = ['code', 'attribute']

# -------------------------------------------------------------------------
def run(self) -> tuple[list[Node], list[system_message]]:
if self.disabled:
return self.create_non_xref_node()
else:
return self.create_xref_node()

# =============================================================================
@dataclass
class Attribute:
Expand Down Expand Up @@ -361,13 +375,13 @@ def __init__(self, *args, **kwargs):

# Site-specific roles
self.roles['schema'] = SchemaRole()
self.roles['attribute'] = AttributeRefRole()

# Additional site-specific roles (these just apply styling)
self.add_role('hidden')
self.add_role('applies-to')
self.add_role('separator')
self.add_code_role('object')
self.add_code_role('attribute')
self.add_code_role('feature')
self.add_code_role('feature.opt', styles=['feature', 'optional'])
self.add_code_role('feature.var', styles=['feature', 'var'])
Expand Down Expand Up @@ -428,6 +442,59 @@ def add_role(self, name, styles=None, parent=roles.generic_custom_role):
def add_code_role(self, name, styles=None, parent=roles.code_role):
self.add_role(name, styles, parent)

# -------------------------------------------------------------------------
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
if typ != 'attribute':
logger.warning('unknown xref type',
location=node, type='ref', subtype=typ)
return None

short = False
if target.startswith('~'):
short = True
target = target[1:]

if '.' in target:
context, _, name = target.partition('.')
else:
name = target
context = None

attr = self.attributes.get(name)

if attr is None:
logger.warning('attribute %r not found', target,
location=node, type='ref', subtype=typ)
return None

if context is None:
if len(attr.instances) > 1:
logger.warning('attribute %r is ambiguous', target,
location=node, type='ref', subtype=typ)
return None

_, docname, refnode = next(iter(attr.context.values()))
qualified = False

else:
c = attr.context.get(context)
if c is None:
logger.warning('overloaded attribute %r not found', target,
location=node, type='ref', subtype=typ)
return None

_, docname, refnode = c
qualified = not short and len(attr.instances) > 1

label = refnode['names'][0]

cont = nodes.literal('', name, classes=['attribute'])
if qualified:
ccont = nodes.inline('', f' ({context})', classes=['applies-to'])
cont = [cont, ccont]

return make_refnode(builder, fromdocname, docname, label, cont)

# =============================================================================
def write_schema(app, exception):
Expand Down
6 changes: 3 additions & 3 deletions components.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ by the at-sign (``@``) and a configuration name.
The special case of using the at-sign as a configuration name
(e.g. ``foo:foo-core@@``) means that the named configuration
is the same as the configuration in which the name appears.
(For example, the component ``foo-ui`` has
non-configuration-specific :attribute:`requires` :string:`":foo-core@@"`
and :attribute:`configurations` :string:`"A"` and :string:`"B"`.
(For example, the component ``foo-ui`` has non-configuration-specific
:attribute:`~component.requires` :string:`":foo-core@@"`
and :attribute:`~component.configurations` :string:`"A"` and :string:`"B"`.
The :string:`"A"` configuration of ``foo-ui``
therefore requires ``:foo-core@A``,
and similar for other configurations.)
Expand Down
5 changes: 3 additions & 2 deletions configurations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ It is recommended that build systems select a configuration as follows:
the build system may implement a mechanism to prefer a configuration
which "matches" the consuming project's active configuration.

- The package's `configurations (package)`_ shall be searched.
- The package's :attribute:`~package.configurations` shall be searched.
The first configuration in this list
which matches an available configuration of the component
shall be used.
Expand Down Expand Up @@ -106,7 +106,8 @@ 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 <components\ (package)>`_.
:attribute:`name`, :attribute:`configuration`,
and :attribute:`~package.components`.
The first two are required.
Use of other attributes specified in the schema is ill-formed.

Expand Down
6 changes: 3 additions & 3 deletions recommendations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ it can be addressed in one of two manners:
- If a "full" dependency
merely needs to be linked *after* a link-only dependency,
the dependency can simply be listed twice;
once in :attribute:`requires`,
once in :attribute:`~component.requires`,
and again in :attribute:`link_requires`.
(Tools are encouraged to add link-only dependencies
after "full" dependencies.)
Expand All @@ -134,8 +134,8 @@ Transitive Dependencies
'''''''''''''''''''''''

When a package is located,
it is intended that the tool would also
locate any `requires (package)`_ mentioned by the package.
it is intended that the tool would also locate
any :attribute:`~package.requires` mentioned by the package.
In some cases, however, a user may want to use
only some components of a package,
which may have a more limited set of dependencies
Expand Down
8 changes: 5 additions & 3 deletions schema-supplement.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ By definition, none of the following attributes are required.
:type: string
:context: package

Specifies the `license`_ that is assumed to apply to a component,
Specifies the :attribute:`license`
that is assumed to apply to a component,
if none is otherwise specified.
This is convenient for packages
that wish their `license`_ to reflect portions of the package
that wish their :attribute:`license`
to reflect portions of the package
that are not reflected by a component (such as data files)
when most or all of the compiled artifacts use the same license.

Expand Down Expand Up @@ -65,7 +67,7 @@ By definition, none of the following attributes are required.
If parts of a package use different licenses,
this attribute may also be specified on a component
if doing so helps to clarifying the licensing.
(See also `default_license`_.)
(See also :attribute:`default_license`.)

.. ----------------------------------------------------------------------------
.. cps:attribute:: meta_comment
Expand Down
46 changes: 24 additions & 22 deletions schema.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ Attribute names are case sensitive.
with which this version is compatible.
This information is used when a consumer requests a specific version.
If the version requested is equal to or newer
than the :attribute:`compat_version`,
than the :attribute:`!compat_version`,
the package may be used.

If not specified,
the package is not compatible with previous versions
(i.e. :attribute:`compat_version`
is implicitly equal to :attribute:`version`).
(i.e. :attribute:`!compat_version`
is implicitly equal to :attribute:`~package.version`).

.. ----------------------------------------------------------------------------
.. cps:attribute:: compile_features
Expand All @@ -120,7 +120,7 @@ Attribute names are case sensitive.

A map may be used instead to give different values
depending on the language of the consuming source file.
Handling of such shall be the same as for `definitions`_.
Handling of such shall be the same as for :attribute:`definitions`.

.. ----------------------------------------------------------------------------
.. cps:attribute:: compile_requires
Expand All @@ -129,7 +129,7 @@ Attribute names are case sensitive.

Specifies additional components required by a component
which are needed only at the compile stage.
Unlike `requires (component)`_,
Unlike :attribute:`component.requires`,
only the required components' compilation-related attributes
should be applied transitively;
link requirements of the required component(s) should be ignored.
Expand Down Expand Up @@ -244,7 +244,8 @@ Attribute names are case sensitive.
(which will be known by the tool).
See also `Prefix Determination`_ for details.

Exactly **one** of ``cps_path`` or `prefix`_ is required.
Exactly **one** of :attribute:`!cps_path` or :attribute:`prefix`
is required.

.. ----------------------------------------------------------------------------
.. cps:attribute:: cps_version
Expand All @@ -260,7 +261,7 @@ Attribute names are case sensitive.
CPS version numbering follows |semver|_.
That is, tools that support CPS version ``<X>.<Y>``
are expected to be able to read files
with :attribute:`cps_version` ``<X>.<Z>``,
with :attribute:`!cps_version` ``<X>.<Z>``,
even for Z > Y
(with the understanding that, in such cases, the tool
may miss non-critical information that the CPS provided).
Expand Down Expand Up @@ -314,7 +315,7 @@ Attribute names are case sensitive.

Specifies additional components required by a component
which are needed only by the dynamic library loader.
Unlike `requires (component)`_ or `link_requires`_,
Unlike :attribute:`component.requires` or :attribute:`link_requires`,
these are not used to resolve symbol references of the consumer,
but represent "private" implementation requirements
of the component on which this attribute appears.
Expand Down Expand Up @@ -367,7 +368,7 @@ Attribute names are case sensitive.

A map may be used instead to give different values
depending on the language of the consuming source file.
Handling of such shall be the same as for `definitions`_.
Handling of such shall be the same as for :attribute:`definitions`.

.. ----------------------------------------------------------------------------
.. cps:attribute:: isa
Expand Down Expand Up @@ -448,7 +449,7 @@ Attribute names are case sensitive.
:default: ["c"]

Specifies the ABI language or languages of a static library
(`type`_ :string:`"archive"`).
(:attribute:`type` :string:`"archive"`).
Officially supported (case-insensitive) values are
:string:`"c"` (no special handling required) and
:string:`"cpp"` (consuming the static library
Expand All @@ -462,7 +463,7 @@ Attribute names are case sensitive.
Specifies a list of additional libraries (as paths, not components)
that must be linked against when linking code that consumes the component.
(Note that packages should avoid using this attribute if at all possible.
Use `requires (component)`_ instead whenever possible.)
Use :attribute:`component.requires` instead whenever possible.)

.. ----------------------------------------------------------------------------
.. cps:attribute:: link_location
Expand All @@ -476,7 +477,7 @@ Attribute names are case sensitive.
on platforms where the library is separated into multiple file components.
For example, on Windows,
this attribute shall give the location of the ``.lib``,
while `location`_ shall give the location of the ``.dll``.
while :attribute:`location` shall give the location of the ``.dll``.

If the path starts with ``@prefix@``,
the package's prefix is substituted
Expand All @@ -494,7 +495,7 @@ Attribute names are case sensitive.

Specifies additional components required by a component
which are needed only at the link stage.
Unlike `requires (component)`_,
Unlike :attribute:`component.requires`,
only the required components' link dependencies
should be applied transitively;
additional properties such as compile and include attributes
Expand All @@ -514,7 +515,7 @@ Attribute names are case sensitive.
such as a ``.so`` or ``.jar``.
(For Windows DLL components,
this should be the location of the ``.dll``.
See also `link_location`_.)
See also :attribute:`link_location`.)

If the path starts with ``@prefix@``,
the package's prefix is substituted
Expand All @@ -535,8 +536,8 @@ Attribute names are case sensitive.
the name of the CPS file
without the ``.cps`` suffix
must exactly match (including case)
either :attribute:`name` as-is,
or :attribute:`name` converted to lower case.
either :attribute:`!name` as-is,
or :attribute:`!name` converted to lower case.

.. ----------------------------------------------------------------------------
.. cps:attribute:: platform
Expand Down Expand Up @@ -568,7 +569,8 @@ Attribute names are case sensitive.
for non-relocatable package.
See also `Prefix Determination`_.

Exactly **one** of `cps_path`_ or ``prefix`` is required.
Exactly **one** of :attribute:`cps_path` or :attribute:`!prefix`
is required.

.. ----------------------------------------------------------------------------
.. cps:attribute:: requires
Expand All @@ -580,12 +582,12 @@ Attribute names are case sensitive.
This is used, for example, to indicate transitive dependencies.
Relative component names are interpreted relative to the current package.
Absolute component names must refer to a package required by this package
(see `requires (package)`_).
(see :attribute:`package.requires`).
Compile and link attributes should be applied transitively,
as if the consuming component also directly consumed the components
required by the component being consumed.

See also `link_requires`_.
See also :attribute:`link_requires`.

.. ----------------------------------------------------------------------------
.. cps:attribute:: requires
Expand Down Expand Up @@ -650,7 +652,7 @@ Attribute names are case sensitive.
:overload:

Specifies the version of the package.
The format of this string is determined by `version_schema`_.
The format of this string is determined by :attribute:`version_schema`.

If not provided, the CPS will not satisfy any request
for a specific version of the package.
Expand All @@ -664,7 +666,7 @@ Attribute names are case sensitive.
Specifies the required version of a package.
If omitted, any version of the required package is acceptable.
Semantics are the same
as for the :attribute:`version` attribute of a |package|.
as for the :attribute:`~package.version` attribute of a |package|.

.. ----------------------------------------------------------------------------
.. cps:attribute:: version_schema
Expand Down Expand Up @@ -692,7 +694,7 @@ Attribute names are case sensitive.
It does not imply anything
about the compatibility or incompatibility
of various versions of a package.
See also `compat_version`_.
See also :attribute:`compat_version`.

- :string:`simple`

Expand Down
9 changes: 5 additions & 4 deletions searching.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ or to provide the location of a package
which is not installed to any of the standard search paths.

When a candidate ``.cps`` file is found,
the tool shall inspect the package's `platform`_.
the tool shall inspect the package's :attribute:`platform`.
If the package's platform does not match the target platform,
the tool should ignore the ``.cps`` and continue the search.
This allows for the installation of packages for different platforms
Expand All @@ -127,13 +127,14 @@ it is necessary to know the package's prefix
as :var:`prefix`, above).
This is accomplished in one of two ways:

- If a package specifies `prefix`_, that value is used.
- If a package specifies :attribute:`prefix`,
that value is used.

- If a package specifies `cps_path`_,
- If a package specifies :attribute:`cps_path`,
the prefix shall be determined from that value
in combination with the absolute location of the ``.cps`` file.

A correctly specified `cps_path`_ will match the location
A correctly specified :attribute:`cps_path` will match the location
(that is, the path without the final ``.cps`` file name)
of the ``.cps`` file.
For example, ``/usr/local/lib/cps/foo/foo.cps``
Expand Down
Loading