AcademySoftwareFoundation / openexr

The OpenEXR project provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the motion picture industry.
http://www.openexr.com/
BSD 3-Clause "New" or "Revised" License
1.62k stars 610 forks source link

ABI changes depending on the build-time imath version #1090

Open antonio-rojas opened 3 years ago

antonio-rojas commented 3 years ago

Even though imath was split to a separate library with an (apparently) independent release schedule, the imath version is hardcoded into openexr's ABI. So two builds of the exact same openexr version can be ABI-incompatible if they were built with different imath versions, even though they have the same soversion. This makes things complicated for binary packaging, as it is not clear that programs compiled with a certain openexr version will stay compatible with subsequent builds of the same openexr library.

eg.: openexr 3.0.5 compiled against imath 3.0.5 provides Imf_3_0::Chromaticities::Chromaticities(Imath_3_0::Vec2<float> const&, Imath_3_0::Vec2<float> const&, Imath_3_0::Vec2<float> const&, Imath_3_0::Vec2<float> const&)

whereas the same openexr version compiled against imath 3.1 provides Imf_3_0::Chromaticities::Chromaticities(Imath_3_1::Vec2<float> const&, Imath_3_1::Vec2<float> const&, Imath_3_1::Vec2<float> const&, Imath_3_1::Vec2<float> const&)

cary-ilm commented 3 years ago

I see the problem, but not an easy solution. Should the openexr cmake build set the soversion differently depending on which Imath version it's built against? That seems necessary, but it will further complicate matters.

Are there examples of other projects dealing with this sort of issue?

lgritz commented 3 years ago

I have essentially the same situation in OIIO, which exposes some Imath types in its API. So you could have an OIIO built against Imath 3.1, an OIIO built against Imath 3.0, and what the heck, one built against OpenEXR/IlmBase 2.4 -- all the same OIIO version that will name their .so files identically, but are decidedly not ABI compatible. ¯\_(ツ)_/¯

I don't think this is something that can be easily solved within the project (unless you made a long, mangled library name that somehow incorporated the versions of both itself and any dependencies that are exposed through its public APIs). This is the kind of problem better solved via a consistent packaging system. (Hmmm, somebody should write one of those for VFX studios...)

kdt3rd commented 3 years ago

so what's interesting is that the type layout is entirely consistent, In that it's only the namespace differences that make it incompatible, at least in this particular scenario. So one constructing a system where you might want to deal with this, you could change the imath and openexr namespaces (which can be done via cmake options) that are chosen to fix this. Is that a good idea? Perhaps not for other reasons. Although it is supported by the libraries. However, given then presumed simplicity / stability of imath, it might be worth considering changing the default namespace that is generated to not include the version number. People who continue to want the version in the namespace can configure that. Or invert the sense of the namespace aliases to (in the future? maybe?) support backward compatible versioning via namespace: i.e. Imath_3_1::vec2f is redirected to a imath_tight_packed::vec2f, or something, instead of Imath being aliased to Imath_3_1...

cary-ilm commented 3 years ago

As I understand it, the problem is with the "29", the soversion that implies the two builds are interchangeable. I see three options:

  1. Do nothing. After a flurry of activity, Imath is likely to remain stable as is for a while.
  2. Set the soversion variable through a formula that somehow embeds the Imath version, so openexr builds against distinct Imath versions have distinct soversions.
  3. Dispense with the entire notion soversion and "drop-in" .so interchangeability. Require that any application must be recompiled and relinked whenever building against a new release. This would be the case for any "header only" library, which Imath almost is.
meshula commented 3 years ago

Larry points out that one can't say OIIO version x is definitively version x, instead it's OIIO x + Imath y.

My read is that Imath's SO version would have to increment whenever the namespace does to mitigate the possibility of breaking OIIO xy.

I imagine OIIO doesn't expose OpenEXR types in its interfaces, so at least there's no OIIO xyz.

I think if we want to say Imath is a basic foundation, we need to do something along the lines of what Kimball proposes, which I might spin larger as -

A core C library which has the types we claim are foundational such as ImathV3f, and then modify the C++ Imath types to be constructable and punnable against ImathV3f. OIIO wouldn't expose the C++ types at all in its interfaces, just the C types. We promise the C types will not change until the end of time more or less, and finally OIIO x is simply OIIO x.

The idea would be that using the actual interesting features of Imath would be restricted to symbols that don't leak out of a consuming library. So the proposal would be

OIIO, and any similar library, such as OpenEXR, could use the fanciest bits internally, expose only the C types from their own interfaces, and be immune to Imath versioning.

lgritz commented 3 years ago

I guess the unstated second half of my point was that "I haven't heard any people running into this as a practical problem."