17

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.

Community
  • 1
  • 1
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589

3 Answers3

13

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
  • 15,899
  • 4
  • 61
  • 65
  • 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 Sep 27 '09 at 03:53
  • 1
    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 Sep 27 '09 at 04:03
  • If you're not using Xcode, your best bet may be to use Autotools and friends. – Chris Lutz Sep 27 '09 at 04:03
  • Does anyone know how to add `@executable_path/../Frameworks` to Runtime Search Paths with CMake? I can't find a clear explanation. – winduptoy Mar 22 '16 at 20:19
7

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
  • 205,541
  • 37
  • 345
  • 415
  • 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 Sep 27 '09 at 23:51
  • 2
    4. using option 2. above, place the frameworks inside your .app bundle (.dmg file) and change paths executable needs with install_name_tool. Here are some examples how install_name_tool is used: http://qt-project.org/doc/qt-4.8/deployment-mac.html. Dietrich, could you incorporate this into your answer please? – Milan Babuškov Mar 05 '15 at 08:50
  • @MilanBabuškov: It looks like this is already incorporated into the answer below. I see no need to duplicate information. – Dietrich Epp Mar 05 '15 at 08:53
  • @DietrichEpp, yes, but it does not explain how to do that, i.e. what is the exact command. Besides, it's only a comment, no need to nitpick. – Milan Babuškov Apr 06 '15 at 17:37
  • It wasn't a nitpick. You asked me to do something, I said no, and I explained why. – Dietrich Epp Apr 06 '15 at 17:39
  • @Szabolcs: This is an unrelated question. Try raising the question in a MacPorts forum. – Dietrich Epp Sep 07 '15 at 20:28
  • @DietrichEpp, I create a Plug In based on a given template by the host program. My Plug In depends on Dynamic Library. I want to embed the files of the Dynamic Library in the Plug In. How can I do it? Thank You. – Royi Oct 28 '16 at 19:15
  • @Royi: See nall's answer for how to put dynamic libraries in a bundle. – Dietrich Epp Oct 28 '16 at 19:26
3

Statically link the libraries.

wildwobby
  • 69
  • 2
  • 8
    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 Sep 27 '09 at 05:35