Skip to content

When linking C libraries, "embedded/lib" libraries don't always link properly #1269

@fdr

Description

@fdr

Crystal depends upon linking a number of libraries in the embedded/lib directory.

However, system libraries included via the Link() annotation may depend on -L/usr/lib, which can contain conflicting libraries. This error is happening on Linux when -L/usr/lib is passed (via -Lpg_config --libdir``) for the Postgres Driver. The result is obscure errors involving missing symbols while linking.

A solution that seems to work only on Linux is to use the colonized form (-l:) of the linker flag to avoid resolving libary path directives when linking Crystal-internal libraries, for example:

@[Link(ldflags: "-lpq -l:/opt/crystal/embedded/lib/libatomic_ops.a -l:/opt/crystal/embedded/lib/libatomic_ops_gpl.a -l:/opt/crystal/embedded/lib/libcord.a -l:/opt/crystal/embedded/lib/libevent.a -l:/opt/crystal/embedded/lib/libevent_core.a -l:/opt/crystal/embedded/lib/libevent_extra.a -l:/opt/crystal/embedded/lib/libevent_openssl.a -l:/opt/crystal/embedded/lib/libevent_pthreads.a -l:/opt/crystal/embedded/lib/libgc.a -l:/opt/crystal/embedded/lib/libpcl.a -l:/opt/crystal/embedded/lib/libpcre.a -l:/opt/crystal/embedded/lib/libpcrecpp.a -l:/opt/crystal/embedded/lib/libpcreposix.a -l:/opt/crystal/embedded/lib/libunwind.a -l:/opt/crystal/embedded/lib/libunwind-coredump.a -l:/opt/crystal/embedded/lib/libunwind-generic.a -l:/opt/crystal/embedded/lib/libunwind-ptrace.a -l:/opt/crystal/embedded/lib/libunwind-setjmp.a -l:/opt/crystal/embedded/lib/libunwind-x86_64.a")]

@will reproduced this on Heroku, and the Trusty EC2 image on AWS after installing libpq-dev, so, regretfully, it is difficult to use libpq in common situations, though we suspect this applies to any C library with transitive dependencies.

Notably, Crystal will append -levent -lrt -lpcl -lpcre -lm -lgc -lpthread -lunwind to the call to cc, so there is a limited opportunity play with various orders in intermixing -L and -l flags. We did try a number of orders of -L and -l without success.

We first suspected libary path precedence orders played an important role in this because installing a new libpcl into /usr/lib worked, without having to add those -l: expressions to ldflags.

One might think one could include the library of choice, e.g. "libpq", with -l:/usr/lib/libpq.a, except libpq optionally supports a number of authentication methods that is determined by the operating system. For example, on Debian, it supports GSSAPI and uses a libary to do so, so having /usr/lib in the library path is necessary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:bugA bug in the code. Does not apply to documentation, specs, etc.topic:compiler

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions