Skip to content

document/best practice for tracking ABI apart from package version #2401

Open
@minrk

Description

@minrk

Your question:

Many libraries version their ABI separately from their API/package version. ABI stability varies widely, with some being extremely stable (major package revisions don't break the ABI for years and are backward compatible), while others are the opposite (patch releases can break the ABI). Right now, we only have a standard of semver-pinning the package (with varying degrees of strictness, as appropriate), assuming the package version is a good-enough proxy. I think that works okay most of the time.

What I'd like is to document a standard/recommended approach for packagers who want to explicitly track the ABI, so that it's not the wild west of different strategies for different packages. I expect this to be a relatively small number of packages, only those that have explicit ABI stability plans / versioning.

Strategies include:

  • put SOVERSION in the package name, as is done in most linux distros (e.g. libzmq5). This can technically lead to allowing concurrent installation of multiple ABI versions, if we really want (I'm not sure we do)
  • track versioned libsomething_abi package with the SOVERSION as the major version (minor/patch version may not always be the most obvious, but might come from the package version or the library filename). There is some precedent in python_abi, though it has more to consider than the version.
  • others?

It would be nice to have written down:

  • a preferred strategy, package naming
  • how run_exports/constraints should be done
  • migration process for existing packages (repodata patches, if needed)

As a simplest possible example, libfabric has an explicitly versioned ABI, and the upcoming 2.0 release drops some old APIs but maintains backward compatibility in the ABI, so it is a minor release (ABI 1.8). This cannot be represented as a version constraint in the package, because <2.0 excludes a compatible version, and <3.0 may exclude a compatible version, we cannot know until 3.0 is planned/released.

So the correct run_exports should result in a build with libfabric 1.19.1 being runtime compatible with:

  • libfabric 1.14 (older, same abi)
  • libfabric 2.0 (newer, major package release, minor abi release)

but if/when there is an abi break, it won't be accepted at runtime, and the package version in which it will happen cannot be known.

My current thought is to have:

  • libfabric_abi empty metapackage, version matching the documented ABI version (set build string to avoid/ensure duplicate uploads?)
  • libfabric has:
    run_exports:
    - {{ pin_subpackage('libfabric_abi', max_pin='x') }}
    -  libfabric # unconstrained
    run:
    - libfabric_abi {{ abi_version }}.*

which would allow safe backward-and-forward ABI compatibility. Relevant to this strategy is that the unconstrained libfabric means we would need repodata patches for all published libfabric builds to depend on libfabric_abi, otherwise the run_exports won't properly constrain the libfabric builds that are published without a dependency on libfabric_abi. We could avoid the repodata patch if libfabric_abi also had a run_constrained on libfabric to exclude any previously-published libfabric versions that are not ABI compatible.

but I don't want to do this if other strategies are preferred and would be (or already are?) taken elsewhere in conda-forge.

links:

This is related to #2326 in that it is another case where the package version doesn't adequately capture the ABI, but in that case there are other inputs to the ABI (the compiler version), whereas this is purely about the contents of the package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions