Working with Dynamic Libraries in Xcode

Here’s just a little tidbit that I ran across recently where Xcode, which normally does a good job covering all the bases, fell short just a bit.

When you’re working with dynamic libraries in just about any environment, especially Linux and MacOS, there is a two-way street when it comes to a program or another library finding the dynamic library it needs to load. First there is the library itself which has, embedded in it, the path where it can be found. Normally this is just a string like “@rpath/libFoo.dylib” (or “@rpath/libFoo.so” if on Linux) which means it can pretty much live anywhere. That’s because “@rpath” is a magic value that means, in essence, “where ever you happen to find me at runtime.” This “install path” value can also be an absolute directory path like, “/usr/local/lib/libFoo.dylib”, which means that this library can only exist in one place – /usr/local/lib.

Now this might seem silly at first but it actually solves some very important issues that revolve around library versioning, system security, and a few others. This is because when you have a program (or another dynamic library) link against a library (during linking not compiling), that value actually gets copied from the dynamic library to your program or library so that the system’s dynamic linker knows where to find it. So if the dynamic library “libFoo.dylib” had it’s install path set as “/usr/local/lib/libFoo.dylib” then when your program starts up and asks the operating system’s dynamic library loader to load “libFoo.dylib” the loader knows where to look for it – /usr/local/lib!

But what about if “libFoo.dylib” has its install path set to “@rpath/libFoo.dylib”? Well, two things. One the dynamic library loader has a set list of places where it will look for dynamic libraries. Some of the usually suspects are “/lib”, “/slib”, “/usr/lib”, “/usr/local/lib”, etc. On Linux you can also give it other places to look by putting them in a text file (one path per line) inside the folder “/etc/ld.so.conf.d/”. Go look at the files in that folder to get the idea.

But the first place the dynamic loader will look to know where to find libraries is in your executable itself. That’s because the linker will add to the “rpath” list any path you want it to look in. So if you passed the option “-rpath /opt/foo/bar/lib” to the linker when you linked your program then the dynamic loader will first look in “/opt/foo/bar/lib” before it looks in any of the other places.

So where am I going with this? I had written a handy utility library to use with my other projects and had built and installed it in “lib/” in my home folder. But after successfully compiling and linking against this new library the programs complained that they couldn’t load the library and then crashed. So after scratching my head for a while it finally dawned on me that while Xcode correctly added “~/lib” to the linker’s search path it didn’t, in fact, instruct the linker to add “~/lib” to the final product’s runtime search path. A definite oversight. So the solution was to go into the projects settings and tell Xcode to add it to the “rpath” as shown below.

After that, everything worked the way it was supposed to!

Leave a Reply