Showing posts with label Open Source Software. Show all posts
Showing posts with label Open Source Software. Show all posts

Apr 11, 2011

Building 3rd party stuff for linking inside your .app wrapper / bundle

I posted this in response to a discussion thread on the Homebrew mailing list and thought I would post it to my blog for SEO and for myself when I need to look into this more at a later date. - sean

I spent a little time trying to figure relative linking out with [Home]brew as apposed to linking a hardcoded '/use/local/...'. I have not spent much time at this yet, but when building libraries with Xcode for including in my OS X App bundle's '@executable_path' is used instead of a full hard system path. You can get info about your compiled libraries and dependencies with 'otool -L':
$ otool -L libboost_filesystem-mt.dylib libboost_filesystem-mt.dylib:
    @executable_path/../Frameworks/libboost_filesystem-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
    @executable_path/../Frameworks/libboost_system-mt.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.4.0)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
You can change your dylib's dependency path's with 'install_name_tool'. Given a binary 'MyBinary':
$ otool -L MyBinary MyBinary:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
    /usr/local/lib/myLib.dylib (compatibility version 1.0.0, current version 1.0.0) 
$ install_name_tool -change /usr/local/lib/myLib.dylib @executable_path/../Frameworks/myLib.dylib MyBinary
Whenever we recompile however we'll need to re-run install_name_tool. It turns out the root issue is how myLib.dylib was built... To fix this update the Makefile that generated myLib.dylib, and change it, adding the -install_name flag to the libtool line which might then look something like this:
libtool -dynamic -flat_namespace -install_name @executable_path/../Frameworks/myLib.dylib \ -lSystem -compatibility_version 1.0 -current_version 1.0.0 \ -o myLib.dylib -undefined suppress $(OBJS)
I'm still interested in a fairly generic way to shoehorn this into common configure scripts, but I haven't looked into it much at this point; it's just on my to-do list. I don't have an easily available comprehensive list of all the options I used, but these might assist others a bit:
CFLAGS="-arch x86_64 -arch i386" [-arch ppc] <- If you are building for PPC (or even can)
LDFLAGS="-arch x86_64 -arch i386" [-arch ppc]
building for backwards compatibility to an older SDK:
CFLAGS="-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch x86_64 -arch i386"
You may need to add this flag to configure (when building fat binaries):
./configure --disable-dependency-tracking
You can also use the 'file' command or 'lipo -info' to check if 'fat' or 'slim' and or what architectures it's build for:
$ file libboost_filesystem-mt.dylib     libboost_filesystem-mt.dylib: Mach-O universal binary with 2 architectures
    libboost_filesystem-mt.dylib (for architecture x86_64): Mach-O 64-bit executable x86_64
    libboost_filesystem-mt.dylib (for architecture i386): Mach-O executable i386
[ update 2011.04.11 @ 19:15 PT ]
Some more related info I found... "@rpath" may be better than "@executable_path"
http://www.dribin.org/dave/blog/archives/2009/11/15/rpath/