Skip to content
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

Generate shared library version arguments on macOS #1451

Closed
ebassi opened this issue Mar 7, 2017 · 16 comments
Closed

Generate shared library version arguments on macOS #1451

ebassi opened this issue Mar 7, 2017 · 16 comments
Labels
bug gnome gstreamer help wanted OS:macos Issues specific to Apple Operating Systems like MacOS and iOS

Comments

@ebassi
Copy link
Contributor

ebassi commented Mar 7, 2017

See also: anholt/libepoxy#108.

On macOS libraries should be annotated with -compatibility_version and -current_version, which are used by the linker to determine the ABI of a shared library.

While the major number is set in the name of the library itself, e.g. libfoo.1.dylib, the minor version is set using -current_version 1.0, for a minor version of 1.0. A newer micro/patch version of libfoo would have a -current_version 1.1, and so on, and so forth.

The -compatibility_version argument allows the linker to load backward compatible libraries. Thus, if libfoo.1.dylib with current version of 1.1 is backward compatible with libfoo1.dylib with current version 1.0, it would set -compatibility_version 1.0.

Meson currently does not set any of these fields, which means they default both to 0. The macOS linker does not really like it when that happens, and flags libraries built with Meson as ABI-incompatible with the same library built with autotools.

Libtool uses the soversion as a way to generate those values, instead:

  • version_info = "{}:{}:{}".format(current, revision, age)
  • major = current - age
  • current_version = "{}.{}".format((current + 1), revision)
  • compatibility_version = current + 1

The major field is used to determine the major version in the dylib file.

@nirbheek
Copy link
Member

nirbheek commented Mar 7, 2017

PS: there is already an open PR about this: #1445

@nirbheek
Copy link
Member

nirbheek commented Mar 7, 2017

(transferring info found on anholt/libepoxy#108)

This is the code that libtool generates for setting compatibility and current versions:

	darwin)
	  # Like Linux, but with the current version available in
	  # verstring for coding it into the library header
	  func_arith $current - $age
	  major=.$func_arith_result
	  versuffix=$major.$age.$revision
	  # Darwin ld doesn't like 0 for these options...
	  func_arith $current + 1
	  minor_current=$func_arith_result
	  xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
          # On Darwin other compilers
          case $CC in
              nagfor*)
                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
                  ;;
              *)
                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
                  ;;
          esac
	  ;;

Besides libtool doing that, man ld on macos says:

     -compatibility_version number
                 Specifies the compatibility version number of the library.  When a library is loaded by dyld, the compatibility version is checked and if the program's version is greater that
                 the library's version, it is an error.  The format of number is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535, and .Y and .Z are optional
                 and if present must be non-negative numbers less than or equal to 255.  If the compatibility version number is not specified, it has a value of 0 and no checking is done when
                 the library is used.  This option is also called -dylib_compatibility_version for compatibility.

     -current_version number
                 Specifies the current version number of the library. The current version of the library can be obtained programmatically by the user of the library so it can determine exactly
                 which version of the library it is using.  The format of number is X[.Y[.Z]] where X must be a positive non-zero number less than or equal to 65535, and .Y and .Z are optional
                 and if present must be non-negative numbers less than or equal to 255.  If the version number is not specified, it has a value of 0.  This option is also called -dylib_cur-
                 rent_version for compatibility.

This is contradicted by Apple's developer documentation which say [0, 65535] for X, and [0, 255] for Y and Z in a version number X.Y.Z.

In an extra twist, cmake behaves in its own way. This is the list of libraries created by cmake for the osx library versions test:

libnoversion.dylib:
	@rpath/libnoversion.dylib (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libonlysoversion.5.dylib:
	@rpath/libonlysoversion.5.dylib (compatibility version 5.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libonlysoversion.dylib:
	@rpath/libonlysoversion.5.dylib (compatibility version 5.0.0, current version 0.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libonlyversion.1.4.5.dylib:
	@rpath/libonlyversion.1.4.5.dylib (compatibility version 0.0.0, current version 1.4.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libonlyversion.dylib:
	@rpath/libonlyversion.1.4.5.dylib (compatibility version 0.0.0, current version 1.4.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libsome.1.4.5.dylib:
	@rpath/libsome.5.dylib (compatibility version 5.0.0, current version 1.4.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libsome.5.dylib:
	@rpath/libsome.5.dylib (compatibility version 5.0.0, current version 1.4.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)
libsome.dylib:
	@rpath/libsome.5.dylib (compatibility version 5.0.0, current version 1.4.5)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.0.0)

It maps the SOVERSION to -compatibility_version and maps VERSION to -current_version (which seems wrong). It also doesn't do any n+1 trickery (which seems right).

The next question is, what does XCode do ;) I'm sure it doesn't use libtool so it should actually be the canonical source to find out what Apple wants us to do.

@tschoonj
Copy link
Contributor

tschoonj commented Mar 7, 2017

Based on the man ld description, it seems that setting -compatibility_version to 0 is definitely a bad idea, as it effectively disables compatibility checking.

The autotools n+1 trick was just a way to ensure that libtool versioning, which starts at 0:0:0 would work in a consistent way on all supported platforms. At the end of the day, the end user doesn't care about how the library versioning is implemented on a particular platform, only that it works properly according to the versioning rules set out by the used build system.

@nirbheek nirbheek added this to the 0.40.0 milestone Mar 9, 2017
@nirbheek nirbheek added bug gnome gstreamer OS:macos Issues specific to Apple Operating Systems like MacOS and iOS labels Mar 9, 2017
@nirbheek nirbheek modified the milestone: 0.40.0 Apr 22, 2017
@tschoonj
Copy link
Contributor

Any progress on this?

Thanks!

@nirbheek
Copy link
Member

I'll look into this tomorrow.

@tschoonj
Copy link
Contributor

tschoonj commented Aug 9, 2017

Did you have a chance to look into this already?

Thanks

@nirbheek
Copy link
Member

nirbheek commented Aug 9, 2017

Nope, soon after I said that I caught Dengue fever, and I'm still away from work. Can only look at this next week.

@tschoonj
Copy link
Contributor

tschoonj commented Aug 9, 2017

Sorry to hear that!

Hope you recover soon!

@tschoonj
Copy link
Contributor

Have you been able to address this issue? With GNOME 3.26 being released now, and a lot of packages being meson only at this point, it would be really great to see a fix for this.

I hope you recovered well from your dengue. I was in India myself for the past two weeks and have heard a lot of stories about people getting dengue and chikungunya!

@nirbheek
Copy link
Member

@tschoonj yes, I am better now, but I was away from work again for some other reason. I think I can look into this on Wednesday or Thursday. Thanks for reminding again, there's a lot of open issues and PRs and it's getting hard to keep track. 😄

@tschoonj
Copy link
Contributor

Glad to hear you're better. Thanks for looking into this. It's getting kind of urgent now ;-)

@jpakkane
Copy link
Member

I stole the behaviour for all of these things from CMake, because their backend is usually correct. This issue may be due to a) not doing the same thing as them or b) we did do the same thing but implementation drifted. We should check what they do currently and try to do the same if possible.

@tschoonj
Copy link
Contributor

I just rebuild a CMake project and saw that the generated Makefiles use both ``-compatibility_version and -current_version when executing the linker command, as I expected. Since meson/ninja builds do not, it does seem that this was skipped when copying behavior from CMake.

FWIW I would recommend to copy the behavior from libtool, in order to ensure a smooth transition on macOS for autotools based projects to meson/ninja, as otherwise one may have to provide different library versions for Linux and macOS if CMake does something different (which I think it does).

@jpakkane
Copy link
Member

We are hesitant to copy anything from libtool because on average everything it does is terrible, wrong and unmaintainable. Instead we should do the "platform native thing" which is what CMake mostly does as well.

@tschoonj
Copy link
Contributor

I can confirm that in this particular case, libtool does it right 😄

@nirbheek nirbheek added this to the meson-next milestone Sep 15, 2017
@tschoonj
Copy link
Contributor

Hi @nirbheek

Any progress here?

Thanks!

nirbheek added a commit that referenced this issue Aug 29, 2018
We now use the soversion to set compatibility_version and
current_version by default. This is the only sane thing we can do by
default because of the restrictions on the values that can be used for
compatibility and current version.

Users can override this value with the `darwin_versions:` kwarg, which
can be a single value or a two-element list of values. The first one
is the compatibility version and the second is the current version.

Fixes #3555
Fixes #1451
nirbheek added a commit that referenced this issue Aug 29, 2018
We now use the soversion to set compatibility_version and
current_version by default. This is the only sane thing we can do by
default because of the restrictions on the values that can be used for
compatibility and current version.

Users can override this value with the `darwin_versions:` kwarg, which
can be a single value or a two-element list of values. The first one
is the compatibility version and the second is the current version.

Fixes #3555
Fixes #1451
gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 29, 2018
With this, the compatibility version and current version values in macOS
and iOS dylibs will match the values set by Autotools.

See: mesonbuild/meson#1451
gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 29, 2018
With this, the compatibility version and current version values in macOS
and iOS dylibs will match the values set by Autotools.

See: mesonbuild/meson#1451
nirbheek added a commit that referenced this issue Aug 29, 2018
We now use the soversion to set compatibility_version and
current_version by default. This is the only sane thing we can do by
default because of the restrictions on the values that can be used for
compatibility and current version.

Users can override this value with the `darwin_versions:` kwarg, which
can be a single value or a two-element list of values. The first one
is the compatibility version and the second is the current version.

Fixes #3555
Fixes #1451
dcbaker pushed a commit to dcbaker/meson that referenced this issue Sep 4, 2018
We now use the soversion to set compatibility_version and
current_version by default. This is the only sane thing we can do by
default because of the restrictions on the values that can be used for
compatibility and current version.

Users can override this value with the `darwin_versions:` kwarg, which
can be a single value or a two-element list of values. The first one
is the compatibility version and the second is the current version.

Fixes mesonbuild#3555
Fixes mesonbuild#1451
gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Oct 22, 2018
With this, the compatibility version and current version values in macOS
and iOS dylibs will match the values set by Autotools.

See: mesonbuild/meson#1451
TingPing pushed a commit to TingPing/glib that referenced this issue Oct 25, 2018
With this, the compatibility version and current version values in macOS
and iOS dylibs will match the values set by Autotools.

See: mesonbuild/meson#1451
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug gnome gstreamer help wanted OS:macos Issues specific to Apple Operating Systems like MacOS and iOS
Projects
None yet
Development

No branches or pull requests

4 participants