views:

466

answers:

3

I have a program (specifically my entry for the SO DevDays Countdown app challenge) which relies on several dynamic libraries, namely libSDL, libSDL_ttf, and others. I have these libraries installed under /opt/local/lib via MacPorts, and many people won't have these installed (and some might have them installed, but not at that location).

How do I distribute my program so that people without these libraries installed can run it out-of-the-box? Obviously I'll have to distribute the various .dylib files, but doing this is insufficient. The dynamic loader still looks for the libraries installed at the locations I have them installed at. Is there a way to tell the dynamic loader to look in the current directory of the executable, like what Windows does with DLLs? People shouldn't have to modify any environment variables (e.g. DYLD_LIBRARY_PATH), since again I want this to work out-of-the-box.

+1  A: 

Statically link the libraries.

wildwobby
So much for code reuse.
Chris Lutz
Statically linked libraries count as "code reuse", since the library code still only has to be written/tested/debugged once, no matter how many applications end up using it. While it's true that multiple copies of the compiled code may end up on the user's disk, that's not as big a problem as it used to be now that hard drives are so large.
Jeremy Friesner
+2  A: 

The basic approach to this is to ship them in the .app bundle. You'll then modify the location the linker looks for shared libraries to include this.

The steps are:

  1. Create a new copy files build phase to your target that copies those files into the Frameworks directory of the .app bundle.

  2. Edit the build configuration setting "Runpath Search Paths" to include @executable_path/../Frameworks

If you build your executable with these changes and then look, you should find that the dylibs exist in the Foo.app/Contents/Framework directory and running otool -L Foo.app/Contents/MacOS/Foo should yield and entry prefixed by @rpath for those dylibs.

From this Cocoabuilder post:

In general, @loader_path is preferred over @executable_path, as it
allows embedded frameworks to work in both an executable and a bundle,
plugin, or sub-framework. The only downside is that @loader_path
requires 10.4 or newer. If you're on 10.5 or newer, @rpath is even
better than @loader_path.

nall
I'm not using Xcode (no .app bundle), just plain old gcc and make. I'm also using OS X 10.4; according to http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html , runpath search paths are only supported on 10.5 and up.
Adam Rosenfield
I believe that @executable_path will work even on 10.4 (@loader_path and @rpath won't). You might also read this: http://blog.onesadcookie.com/2008/01/installname-magic.html
nall
If you're not using Xcode, your best bet may be to use Autotools and friends.
Chris Lutz
+2  A: 

As you mentioned you're not using Xcode, so it's a bit difficult. Here are options in my order of preference:

  1. Switch to Xcode. Use frameworks. The SDL libraries are available as frameworks already, and I've seen more than a couple commercial games with a libsdl.framework inside the app bundle.

  2. Use frameworks, but keep your Makefiles. Download the framework versions of your SDL libraries (or build them yourself), and link with them with the -framework linker flag. Distribute the frameworks with your app or don't, and tell your users to put them in either ~/Library/Frameworks or in /Library/Frameworks. I wouldn't bother with an installer for this.

  3. Statically link against SDL. In the Makefile, you'll have to list the path of the static libraries rather than use the -l flag, e.g., you run "ld blah blah /opt/local/lib/libsdl.a". There is no way that I know to tell -l to prefer static over shared libraries, and believe me, I've looked.

Dietrich Epp
After thinking about it, I think I'm just going to go with static linking for distribution. If I'm going to distribute the dynamic libraries anyways, that defeats several of the purposes of using them, so I might as well avoid the pain of dealing with the dynamic loader.
Adam Rosenfield