[MacPorts] #62426: libc++: using a newer libc++ to build software on older macos systems

MacPorts noreply at macports.org
Wed Sep 21 10:23:33 UTC 2022

#62426: libc++: using a newer libc++ to build software on older macos systems
  Reporter:  kencu                   |      Owner:  kencu
      Type:  enhancement             |     Status:  closed
  Priority:  Normal                  |  Milestone:
 Component:  ports                   |    Version:
Resolution:  fixed                   |   Keywords:
      Port:  libcxx macports-libcxx  |

Comment (by RJVB):

 Well, not exactly; in my scenario executable A is linked against
 $prefix/lib/libc++.dylib (not newlibc++.dylib). If these were frameworks
 then dyld might indeed use the bundle ID or some similar metadata to
 recognise two libraries as identical (except for version), REGARDLESS of
 their filename.

 The whole idea behind shared libraries that I know of is that the dynamic
 loader (dyld on Darwin) will consider each linked library but only load it
 if it resolves as-yet-unresolved symbols. And even then it will only load
 the symbols that were not yet resolved.

 On Darwin with its compatibility_version and current_version metadata
 embedded in the dylibs the linker could also decide to prioritise multiple
 copies by version - this I don't know.

 As far as I can see this is really no different than forcing the loader to
 use a different library by using DYLD_INSERT_LIBRARIES (or LD_PRELOAD on
 Linux). You must be familiar with libraries that override `malloc()` and
 family; that's the same principle even if this involves an add-on library.
 Jemalloc for instance (`port:jemalloc`) can be used 2 ways: either you
 link your executable with it, or you insert/preload/inject it.

 There is one scenario where the above could go wrong. If dyld first
 encounters a shared library that depends on /usr/lib/libc++ (or indeed if
 the executable itself depends on that), the scenario painted above may be
 reversed, and then code built with newer libc++ headers (in some other
 dependency) would be executed against the older libc++ binary
 I *think* there are 2 protections against that:
 - setting the current_version info (in which case at worst dyld will print
 an error and abort execution)
 - setting DYLD_INSERT_LIBRARIES=$prefix/lib/libc++.dylib

 That latter suggestion might also be interesting to try in known cases
 where having a newer libc++ causes problems.

 I do realise that there would be a number of practical issues to sort out
 if MacPorts were ever to provide libc++.dylib (and I do mean not just
 libc++.1.dylib!) directly in $prefix/lib. A priori you'd want to rebuild
 every installed port.
 Or relink. This is a bit thinking ahead, but I know "base" has at least
 one mechanism to alter installed files (renaming conflicting files). The
 rev-upgrade scanner can be used to find all binaries that depend on
 /usr/lib/libc++.1.dylib, which can then be modified to depend on
 $prefix/lib/libc++.1.dylib . Advanced magic, but it should work.

 A last consideration: on Linux a lot of this would be automatic, provided
 $prefix/lib corresponds to one of the standard (or configured/customised!)
 library search paths, because it (mostly) lacks the possibility to
 hardcode absolute library paths in binaries.

Ticket URL: <https://trac.macports.org/ticket/62426#comment:52>
MacPorts <https://www.macports.org/>
Ports system for macOS

More information about the macports-tickets mailing list