Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to distribute a Mac OS X with dependent libraries?

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.

like image 241
Adam Rosenfield Avatar asked Sep 27 '09 02:09

Adam Rosenfield


People also ask

What is Dylib Mac OS X?

Macintosh library that contains declarations and functions referenced by a Mac OS X application; loaded dynamically by various programs when needed, which allows for efficient use of memory; may be referenced by open applications or by Apple Xcode during software development.

How do I distribute an app on Mac?

To distribute macOS apps without the App Store, you need to sign the app with a Developer ID certificate. Apps and other software packages need to be notarized to verify they're malware-free. You can use Xcode to notarize apps.

How do you create a bundle on Mac?

The simplest solution is: create once an Xcode project without changing anything (i.e. keep the simple one-window app that Xcode creates for you), build it, and copy the bundle it created for you. Then, edit the files (notably the Info.

What is @rpath Mac?

@rpath stands for Runpath Search Path. In the Xcode, it's set with LD_RUNPATH_SEARCH_PATH setting. In ld command tool it's set with -rpath parameter when linking. So it's a search path for the linker. Runtime Search Path instructs the dynamic linker to search a list of paths in order, to locate the dynamic library.


2 Answers

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.

like image 145
nall Avatar answered Oct 01 '22 22:10

nall


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.

like image 23
Dietrich Epp Avatar answered Oct 01 '22 22:10

Dietrich Epp