Search code examples
macoshaskellghcstatic-linkingdynamic-linking

What determines linking behaviour for GHC on OS X?


I'm observing different linking behaviour between two machines when compiling a binary.

Each has the same GHC (7.8.3), same code, same flags (-Wall -O2), same libgmp (installed by Homebrew on each):

machine-one$ otool -L my-binary
my-binary:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)

machine-two$ otool -L my-binary
my-binary:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
        /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
        /usr/local/lib/libgmp.10.dylib (compatibility version 13.0.0, current version 13.0.0)

I can't for the life of me figure out why libgmp is linked dynamically on the second machine.

In terms of differences I've been able to recognize: GHC has been installed via the binary distribution for OS X on the first machine and Homebrew on the second. For C compilers, we have:

machine-one$ cc --version
Apple LLVM version 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix

machine-two$ cc --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix

What typically determines the linking behaviour, and how can I enforce one linking method or the other?

EDIT: I've observed the same behaviour happening with zlib on yet another machine, so it's not a GMP-specific issue.

EDIT: I've plucked ghc --info from each of the machines, here they are for machine one and machine two. And here's the diff between the two as well.

EDIT: I've reinstalled ghc on machine two via the distribution binary, and sure enough libgmp is not dynamically linked when I recompile my binary. So it seems like this is related to installing GHC via Homebrew.

Still quite interested in what's going on exactly.


Solution

  • The crucial difference is that machine #2 has /usr/local/lib in the linker path, and is using brew's linker (/usr/local/Library/ENV/4.3/ld). ghc still uses an external linker, even if it isn't using the C backend for code generation, so you can combine Haskell code with code written in other languages (crucial for Haskell's many FFI bindings to third-party libraries). So you should really be asking the brew people why things get linked differently. It's not actually a ghc issue.