Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get Xcode to link and debug an app with Boost Filesystem?

TL;DR

Objective-C app linked with static library that dynamic links Boost Filesystem. App can be run from output directory using Terminal, but trying to run from Xcode debugger or Finder gives error dyld: Library not loaded: libboost_filesystem.dylib <snip> Reason: image not found.

Problem

In my Xcode project I have a structure that looks like this:

MainProject (Objective-C)
 - static_lib_that_uses_filesystem (C++)

To get everything to link, I added libboost_system and libboost_filesystem dylibs to the "Link Binary with Libraries" build phase in MainProject.

When I try to run the app from either Xcode or Finder I get:

sharedlibrary apply-load-rules all
warning: Unable to read symbols for libboost_filesystem.dylib (file not found).
warning: Unable to read symbols from "libboost_filesystem.dylib" (not yet mapped into memory).
warning: Unable to read symbols for libboost_system.dylib (file not found).
warning: Unable to read symbols from "libboost_system.dylib" (not yet mapped into memory).
[Switching to process 43957 thread 0x0]
dyld: Library not loaded: libboost_filesystem.dylib
  Referenced from: /Users/ssteele/Library/Developer/Xcode/DerivedData/MainProject-dqrhyuarllykslftblocjdzxlran/Build/Products/Debug/MainProject.app/Contents/MacOS/MainProject
  Reason: image not found

I added a build stage to copy the dylibs to the Frameworks directory in the bundle, this doesn't help. I changed this to copy them to the Executables directory which also didn't help.

Having them in the Executables directory does allow me to run the app from Terminal.

How can I get the app to find the dylibs when run from Finder/Xcode?

Background Info

I'm using Xcode 4.2 on Lion and currently targeting Lion only. I built my shared libraries for filesystem like this:

./b2 threading=multi macosx-version=10.7 --with-filesystem stage

This creates libboost_system.dylib, libboost_filesystem.dylib, and also .a equivalents in the stage/lib directory, I'm referencing them in the project directly from there.

like image 814
Simon Steele Avatar asked Jan 17 '12 22:01

Simon Steele


2 Answers

Dynamic libs (dylibs) on OSX bake in the path that they should be loaded from. For example...

/usr/lib/some_awesome.dylib.

When you link to a dylib, the linker embeds this path in your executable as the place to look for it at runtime. This is fine and easy with installed libs, but for relative path linking it's more complicated.

When you build the boost libs, they just get their names embedded rather than a full or relative path (i.e. libboost_system.dylib rather than /usr/lib/libboost_filesystem.dylib). You should be able to change this with the dll-path option, but that seems broken currently.

To fix your problem you either need to get the correct path relative to your application embedded (e.g. @executable_path/libwhatever.dylib) into the dylibs somehow, which would probably require the bjam dll-path option to work, or instead you can fix your executable to look in a different location.

To do this, use something like the following as a script step in your build:

install_name_tool -change libboost_filesystem.dylib @executable_path/libboost_filesystem.dylib$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH

Note that if you have multiple dylibs that reference each other with broken paths, you'll need to fix the paths between them too, e.g.

install_name_tool -change libboost_system.dylib @executable_path/libboost_system.dylib$BUILT_PRODUCTS_DIR/$EXECUTABLE_FOLDER_PATH/libboost_filesystem.dylib

The following is a good article on this: Creating working dylibs

like image 65
Martin Peck Avatar answered Nov 15 '22 13:11

Martin Peck


The issue is that boost needs to be installed e.g. b2 ..... install. This copies the libraries and headers into /usr/local/lib and /usr/local/include.

OSX dynamic libraries only run from the directory that they are built for.

You can change the install directory by using the -prefix argument to boost build. However the libraries would still need to be in the same directory for all users.

There should be a way of building boost as a framework and/or embedding @executable_path in the library.

An alternative is to use boost's static libraries - build the static only or delete the dynamic ones, Xcode looks for dynamic before static. If using static then the path to the libraries does not matter at run time as all the code is now in the executable.

like image 30
mmmmmm Avatar answered Nov 15 '22 12:11

mmmmmm