-
-
Notifications
You must be signed in to change notification settings - Fork 281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
document/best practice for tracking ABI apart from package version #2401
Comments
I prefer the |
I actually wrote a CFEP a few years ago to propose tracking the ABI in the build string, but @isuruf convinced me that appending the soname to the package name is the better approach. This approach already deployed by myself and others in multiple feedstocks including: https://github.com/conda-forge/dav1d-feedstock |
Great, thanks for linking to that prior discussion! Sorry I didn't find it in my search. There does seem to be some inconsistency in how files are packaged for the packages that are doing something like this already. For example:
So none of these seem to quite follow the same conventions as each other in terms of which files go in which package and how dependencies relate and the split output names. I'm not suggesting any of these need to change, but they do suggest to me that it would be a good idea to have a canonical example to reference for other packages to follow. For the libfabric example, the ABI has its own version number. Would we use that version number anywhere, or just to help us look up the package version to use in the lower bound of run_exports? i.e. libfabric 1.19 is ABI 1.6, so it would have run_exports How's this for a sketch to document:
Any other suggestion on what to say for if/when this is worth doing? Personally, I'm mostly concerned with correctly expressing how broad ABI compatibility is in some packages I maintain, since the standard package pinning practice is currently far too strict. Or suggestions for example tests to verify e.g. |
Here's what I think should happen
{% set libfoo_soversion = 5 %}
- name: libfoo-devel
build:
run_exports:
- {{ pin_subpackage("libfoo", max_pin=None) }}
- {{ pin_subpackage("libfoo" ~ libfoo_soversion, max_pin=None) }}
requirements:
run:
- {{ pin_subpackage("libfoo" ~ libfoo_soversion, exact=True) }}
- {{ pin_subpackage("libfoo", exact=True) }}
files:
- lib/libfoo.so
- lib/libfoo.a
- include/foo.h
- name: libfoo
requirements:
run:
- {{ pin_subpackage("libfoo" ~ libfoo_soversion, max_pin=None) }}
- name: libfoo{{ libfoo_soversion }}
requirements:
host:
- libbar
files:
- lib/libfoo.so.{{ libfoo_soversion }}
- lib/libfoo.so.{{ full_version }}
{% set libfoo_soversion = 5 %}
- name: libfoo-devel
build:
run_exports:
- {{ pin_subpackage("libfoo" ~ libfoo_soversion, max_pin=None) }}
requirements:
run:
- {{ pin_subpackage("libfoo" ~ libfoo_soversion, exact=True) }}
- {{ pin_subpackage("libfoo", exact=True) }}
files:
- lib/libfoo.so
- lib/libfoo.a
- include/foo.h
- name: libfoo{{ libfoo_soversion }}
requirements:
host:
- libbar
files:
- lib/libfoo.so.{{ libfoo_soversion }}
- lib/libfoo.so.{{ full_version }} |
Got it, thank you! It looks like the presence of What needs to be said about Windows, since it doesn't do SOVERSION as I recall? It always needs to be mutually exclusive, right? Unless special consideration is taken? I see |
The dav1d-feedstock has a mutex package for Windows which serves the same purpose as the unversioned library packages in @isuruf's examples.
That's correct. Windows doesn't have a native mechanism for sonames. It hasn't quite caught on in the Windows platform to include an ABI version in the library name by convention. For example, |
Disallowing co-installation implies channel-wide pinnings and migrators because you want to keep all the packages in sync in order to prevent older packages from holding newer packages back. However, it (edit: it being co-installation) may result in larger environments because multiple copies of the same library are installed. |
Thanks for pointing that out! This variety of approaches to the same goal is why I would like to have something written down. Not because there's anything wrong with one approach or another, just to have a reference pattern for new packages to adopt as a default, at least.
Allowing co-installation is what results in this, right? Not Disallowing it? Maybe I misunderstood what I'll try to summarize these things in a KB entry for you to review. Thanks for all your insights. In the meantime, I've tried applying your suggestions to libfabric in conda-forge/libfabric-feedstock#16 |
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:
libzmq5
). This can technically lead to allowing concurrent installation of multiple ABI versions, if we really want (I'm not sure we do)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 inpython_abi
, though it has more to consider than the version.It would be nice to have written down:
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:
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: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 onlibfabric_abi
. We could avoid the repodata patch iflibfabric_abi
also had arun_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:
libpmix2
is proposed, which I haven't seen suggested elsewhereThis 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.
The text was updated successfully, but these errors were encountered: