A macOS static linking mystery

I'm trying to diagnose strange GHC linking behavior which, as far as I can tell, only occurs on macOS. I feel a bit out of my league debugging this, so I'm hoping someone knows what is causing this. When building the Haskell libffi library [1], it will link pass -lffi to GHC. Typically, most installations of libffi will include both a static library (libffi.a) and a shared library (libffi.{so,dylib,dll}). My impression is that when the linker finds both, it will default to the shared library. This is definitely the case on Linux and Windows, at least. An exception to this rule is macOS, however. On macOS, building libffi always appears to default to linking against the static version of libffi, even when a dynamic version is also available. To reproduce this phenomenon, check out libffi [1] and run the following commands: $ brew install libffi # If it is not already installed $ cabal build ctime $ otool -L $(cabal list-bin ctime) The output reveals that the compiled executable does not dynamically link against libffi.dylib: $ otool -L $(cabal list-bin ctime) /Users/rscott/Documents/Hacking/Haskell/libffi/dist-newstyle/build/x86_64-osx/ghc-8.10.7/libffi-examples-0.1/x/ctime/build/ctime/ctime: /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1) /usr/lib/libcharset.1.dylib (compatibility version 2.0.0, current version 2.0.0) This is exceedingly strange, since my Hombrew installation does in fact provide libffi.dylib: $ ls -alh ~/Software/homebrew/Cellar/libffi/3.4.2/lib/ total 232 drwxr-xr-x 6 rscott 1340850540 192B Aug 7 09:38 . drwxr-xr-x 11 rscott 1340850540 352B Aug 7 08:51 .. -rw-r--r-- 1 rscott 1340850540 70K Aug 7 08:51 libffi.8.dylib -r--r--r-- 1 rscott 1340850540 41K Jun 28 2021 libffi.a lrwxr-xr-x 1 rscott 1340850540 14B Jun 28 2021 libffi.dylib -> libffi.8.dylib drwxr-xr-x 3 rscott 1340850540 96B Aug 7 08:51 pkgconfig What's more, this only seems to happen when building the libffi library in particular. If I try building another library that has a C extra-libraries dependency, such as HsOpenSSL, then I can find its dynamic dependencies (libssl.dylib and libcrypto.dylib) using otool: $ otool -L dist-newstyle/build/x86_64-osx/ghc-8.10.7/HsOpenSSL-0.11.7.2/build/test-dsa/test-dsa dist-newstyle/build/x86_64-osx/ghc-8.10.7/HsOpenSSL-0.11.7.2/build/test-dsa/test-dsa: /usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib (compatibility version 1.1.0, current version 1.1.0) /usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib (compatibility version 1.1.0, current version 1.1.0) /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1) /usr/lib/libcharset.1.dylib (compatibility version 2.0.0, current version 2.0.0) I'm at a bit of a loss trying to figure out why this only happens for libffi, and only on macOS. To make things even stranger, this only seems to happen when using GHC. If I try to compile a simple libffi C program using -lffi, for instance, then otool finds libffi.dylib. Is there something about GHC's linking behavior that would cause this? Ryan S. ----- [1] https://github.com/remiturk/libffi

On Mon, Aug 08, 2022 at 07:29:38AM -0400, Ryan Scott wrote:
An exception to this rule is macOS, however. On macOS, building libffi always appears to default to linking against the static version of libffi, even when a dynamic version is also available. To reproduce this phenomenon, check out libffi [1] and run the following commands:
$ brew install libffi # If it is not already installed $ cabal build ctime $ otool -L $(cabal list-bin ctime)
What is the output of $ pkg-config --libs libffi on this system? If "cabal" passes any additional flags to "pkg-config" use those as well. On my MacOS laptop I get: $ /usr/local/bin/pkg-config --libs libffi -lffi which does not use the "brew"-installed libffi. Not surprising, since /usr/local/lib/pkgconfig/ has no symlink to the "libffi.pc" file.
This is exceedingly strange, since my Hombrew installation does in fact provide libffi.dylib:
$ ls -alh ~/Software/homebrew/Cellar/libffi/3.4.2/lib/ [...] drwxr-xr-x 3 rscott 1340850540 96B Aug 7 08:51 pkgconfig
For "pkg-config" to find the HomeBrew "libffi", there would need to be a "libffi.pc" symlink to the one in the "pkgconfig" directory. Perhaps there are additional steps to perform in HomeBrew to activate this "libffi" as a default target for "pkg-config". -- Viktor.

On Mon, Aug 08, 2022 at 09:59:48AM -0400, Viktor Dukhovni wrote:
On my MacOS laptop I get:
$ /usr/local/bin/pkg-config --libs libffi -lffi
which does not use the "brew"-installed libffi. Not surprising, since /usr/local/lib/pkgconfig/ has no symlink to the "libffi.pc" file.
When updating "libffi" HomeBrew reports: ==> libffi libffi is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble. For compilers to find libffi you may need to set: export LDFLAGS="-L/usr/local/opt/libffi/lib" export CPPFLAGS="-I/usr/local/opt/libffi/include" If the MacOS libffi works, it is probably safer to use it rather than the HomeBrew version. -- Viktor.

ahh, pkgconfig is what i was overlooking!
agreed with viktor, using the system provided one is definitely safer
On Mon, Aug 8, 2022 at 10:46 AM Viktor Dukhovni
On Mon, Aug 08, 2022 at 09:59:48AM -0400, Viktor Dukhovni wrote:
On my MacOS laptop I get:
$ /usr/local/bin/pkg-config --libs libffi -lffi
which does not use the "brew"-installed libffi. Not surprising, since /usr/local/lib/pkgconfig/ has no symlink to the "libffi.pc" file.
When updating "libffi" HomeBrew reports:
==> libffi libffi is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble.
For compilers to find libffi you may need to set: export LDFLAGS="-L/usr/local/opt/libffi/lib" export CPPFLAGS="-I/usr/local/opt/libffi/include"
If the MacOS libffi works, it is probably safer to use it rather than the HomeBrew version.
-- Viktor. _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
participants (3)
-
Carter Schonwald
-
Ryan Scott
-
Viktor Dukhovni