How to distribute a Mac OS X with dependent libraries?
Asked Answered
C

3

18

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.

Cambrai answered 27/9, 2009 at 2:54 Comment(0)
A
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.

Autacoid answered 27/9, 2009 at 4:10 Comment(8)
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.Cambrai
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: qt-project.org/doc/qt-4.8/deployment-mac.html. Dietrich, could you incorporate this into your answer please?Explosion
@MilanBabuškov: It looks like this is already incorporated into the answer below. I see no need to duplicate information.Autacoid
@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.Explosion
It wasn't a nitpick. You asked me to do something, I said no, and I explained why.Autacoid
@Szabolcs: This is an unrelated question. Try raising the question in a MacPorts forum.Autacoid
@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.Perky
@Royi: See nall's answer for how to put dynamic libraries in a bundle.Autacoid
A
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.

Albino answered 27/9, 2009 at 3:40 Comment(4)
I'm not using Xcode (no .app bundle), just plain old gcc and make. I'm also using OS X 10.4; according to developer.apple.com/mac/library/documentation/DeveloperTools/… , runpath search paths are only supported on 10.5 and up.Cambrai
I believe that @executable_path will work even on 10.4 (@loader_path and @rpath won't). You might also read this: blog.onesadcookie.com/2008/01/installname-magic.htmlAlbino
If you're not using Xcode, your best bet may be to use Autotools and friends.Burgoyne
Does anyone know how to add @executable_path/../Frameworks to Runtime Search Paths with CMake? I can't find a clear explanation.Iiette
A
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.

Autacoid answered 27/9, 2009 at 4:10 Comment(8)
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.Cambrai
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: qt-project.org/doc/qt-4.8/deployment-mac.html. Dietrich, could you incorporate this into your answer please?Explosion
@MilanBabuškov: It looks like this is already incorporated into the answer below. I see no need to duplicate information.Autacoid
@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.Explosion
It wasn't a nitpick. You asked me to do something, I said no, and I explained why.Autacoid
@Szabolcs: This is an unrelated question. Try raising the question in a MacPorts forum.Autacoid
@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.Perky
@Royi: See nall's answer for how to put dynamic libraries in a bundle.Autacoid
O
3

Statically link the libraries.

Obscene answered 27/9, 2009 at 3:17 Comment(1)
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.Foreground

© 2022 - 2024 — McMap. All rights reserved.