Static linking and linker search paths

Duncan Coutts duncan.coutts at
Tue Dec 22 02:20:48 EST 2009


Conor's problems on OSX with libiconv reminds me of something I've been
thinking about for a little while.

So the problem is that the semantics of static linking does not at all
match what we really want. We can easily accidentally "interpose" a
wrong library in place of the one we wanted.

In the iconv case people have hit recently we've got this situation:

contains references to _iconv_open, _iconv, _iconv_close



When the code for libHSbase was built, it was against the header files
for the standard system version of iconv on OSX. Thus it is intended
that we link against the system version of iconv.

No suppose by default that the system is set up such that only the
system iconv is found by default. So I am assuming there is no
LD_LIBRARY_PATH or similar set. Then when we link something then we
correctly resolve the references in base to the system iconv lib.

When we call gcc to link we're doing something like:

-L${ghclibdir} -lHSbase- -liconv

Now suppose we build some FFI package (libHSfoo-1.0.a) that provides a
binding to a C lib installed via macports (libfoo.a). When we link a
program that depends indirectly on this FFI package then the gcc linker
line is like:

-L${ghclibdir} -L/opt/local/lib
-lHSfoo-1.0.a -lfoo -lHSbase- -liconv

and now it all breaks.

We're asking the linker to look in /opt/local/lib first for *all the
remaining libraries* and that includes iconv, so we pick up the wrong
iconv. Our intention was just to look for -lfoo using /opt/local/lib,
but we cannot express that to the linker.

The problem is that our notion of library dependencies is hierarchical
but for the system linker it is linear. We know that package foo-1.0
needs the C library libfoo.a and that it should be found by looking
in /opt/local/lib. But we end up asking the linker to look there first
for all other libs too, including for the -liconv needed by the base
package. The registration for the base package never
mentioned /opt/local/lib of course.

What we'd really like to say is something like:

link HSfoo-1.0.a
push search path /opt/local/lib
link foo
pop search path

If we think we know enough about the behaviour of the system linker and
its search path then we could do just:

-lHSfoo-1.0.a /opt/local/lib/libfoo.a -lHSbase- -liconv

that is, specify the .a file exactly by fully resolved path and not add
anything to the linker search path. (Actually we'd do it for the
libHS*.a ones too since we know precisely where they live)

The possible danger is that how we search for the library and how the
system linker searches for it might not match exactly and we could end
up sowing confusion.

Worth thinking about anyway.

Note that some of this is different for shared libs.


More information about the Glasgow-haskell-users mailing list