Forcing the Mac OS X linker to choose a static libraryEdit

I am currently working on a Ruby extension written in C which uses an ANTLR-generated parser and must therefore link against the C target runtime library.

By default, when you build and install the C target runtime the following items are installed:

  • /usr/local/lib/libantlr3c.dylib
  • /usr/local/lib/libantlr3c.la
  • /usr/local/lib/libantlr3c.a

It appears that the Mac OS X linker is hard-wired to search dynamic libraries before static ones, so when build my Ruby extension I found that the dynamic library was used. The linker invocation (as generated by mkmf was as follows:

cc -dynamic -bundle -undefined suppress -flat_namespace  -L"/usr/local/lib" \
  -o walrus_parser.bundle walrus_parser.o WalrusLexer.o WalrusParser.o  \
  -lantlr3c  -lpthread -ldl -lobjc

And otool (otool -L walrus_parser.bundle) indicates that the followed shared libraries were used:

walrus_parser.bundle:
        /usr/local/lib/libantlr3c.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 88.5.1)
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)

Note that you cannot pass a file extension to the -l switch (-lantlr3c.a) to force the static library to be used. One way to force the static library to be used is to simply remove the dynamic version. A less destructive way is recommended here.

Basically, the idea is:

  1. Create symlink libname_s.a which points to the static lib libname.a.
  2. Tell the compiler to link against libname_s (ie. -lname_s).
  3. Depending on where you create the symlink, may be necessary to add a -L switch so linker knows where to find it (for example, if you don’t have the administrator privileges necessary to write to /usr/local/ or don’t wish to modify that directory).