Linking to a .dylib


#1

I’m working on OS X.

I’m trying to make a project that uses libusb.

So I have /Proj/libusb/{libusb-1.0.0.dylib, libusb.h} and in my /Proj/Source/usb.cpp I have #include "../libusb/libusb.h"

In Projucer -> Config -> XCode -> external libraries to link I’ve set usb-1.0.0

And in the debug and release subsections -> extra library search paths I have added …/…/libusb/

It builds okay but when I run it, I get:

dyld: Library not loaded: @rpath/libusb-1.0.0.dylib

Referenced from: /Proj/Builds/MacOSX/build/Debug/Proj.app/Contents/MacOS/Proj
Reason: image not found

It turns out a .dylib stores where it thinks it is located, this is a giant headache:

http://osiris.laya.com/coding/dylib_linking.html

and …

Following advice:
Other Linker Flags:
For the .dylib:
-install_name @rpath/libusb-1.0.0.dylib
For the app:
-rpath @executable_path

Now apparently if I can get the .dylib into the same folder as the target binary, I should be good to go.

Can I do this from Projucer?

Also, this entire solution path feels horrible. Do I have any other options?

I’ve been told that one option would be to compile libusb as a static library, but I don’t know how much work that would be.

π


#2

You can also use rpaths when linking shared libraries. I found this post very useful in explaining how they work.


#3

Thanks Fabian, I had forgotten that link.

I’m still struggling with what to do. I’ll try and outline the possible solution paths as I see them:

  1. continue with .dylib – somehow I need to get Projucer to insert the .dylib in the same folder as the target binary.

  2. maybe I should get Xcode to compile libusb as a framework, I notice an “Extra Frameworks” box i n ProJucer’s build pane.

  3. maybe I should try to compile libusb as a static (.a) library, this I think would be less headache to work with, but I don’t know how much work this requires on libusb.

  4. maybe I should somehow include the libusb source code into my project so that it compiles at same time. Problem here is libusb source tree isn’t set up for this, you need to run some configure script to generate a config.hfile. I see ProJucer allows running of an arbitrary script during the build process, I would have to do some per-platform fiddling to get it working on different OS.

EDIT:
I’ve got (1) working:

  • Open the libusb XCode project
  • in Build Settings -> Extra Linker Flags -> -install_name @rpath/libusb-1.0.0.dylib
  • Product -> Scheme -> Edit Scheme -> Run -> Info -> Build Configuration -> Release
  • locate the newly built libusb-1.0.0.dylib – for me: Finder -> SHIFT+CMD+G -> ~/Library/Developer/Xcode/DerivedData -> …
  • Copy it into /myJUCEproj/libusb/ say
  • also copy libusb.h from the libusb source-tree to the same location
  • ProJucer -> Files -> R-Click on project -> Add Existing Files -> add the .dylib
  • L-Click on project -> check XCode Resource on the .dylib
  • ProJucer -> Config -> Extra Linker Flags -> -rpath @executable_path/../Resources/

π

PS EDIT: I’ve just been told .dylib-s belong in /Frameworks not /Resources – so what should I do to do this correctly as per convention?

If I use:

  • ProJucer -> Config -> Extra Linker Flags -> -rpath @executable_path/../Frameworks/

…instead, that is still no good because I can’t see any way to get my .dylib copying into Contents/Frameworks

Or does the Frameworks box in ProJucer’s Config pane do everything automatically? Like if I put a path to a .dylib here, is it going to correctly copy it into the appropriate target folder and tell the compiler how to find it using the above -rpath?

And what of the .h? I suppose I would put that in my source tree… or does that also belong in frameworks?


#4

In Xcode->build phases->copy libraries
Change Destination to Frameworks
and add the lib there


#5

Would it be possible to have something for this use case in the Projucer ?

Thanks !


#6

Bump
(padding for characters limit)


#7

Okay - so here’s what I’m trying. This seems painfully complicated but…

  • Build my dylib i want to bundle (libcurl in this case)… I’m building libcurl and putting it in the folder ./SDKs/libcurl.4.dylib relative to my Projucer project.
  • install_name_tool -id "@rpath/libcurl.4.dylib" libcurl.4.dylib
  • Setting the specific library version in the link with libraries list in projucer to libcurl.4 so I don’t have to faff around with symlinks
  • Setting the library path in Projucer to ../../SDKs so that it finds the correct library at compile time (and appears to then save the path, set with install_name_tool) for run time.
  • Add something like this to the post-build script section:

where $CODESIGNING_FOLDER_PATH is .app bundle

cp -rf "../../SDKs/libcurl.4.dylib" "$CODESIGNING_FOLDER_PATH/Contents/MacOS"

Wouldn’t it be super-sweet if the Projucer did all but the first step for me … :wink:


#8

Okay, and just to finish documenting this process. You can use otool like this to check it’s worked correctly:

jim@snoopy ~/Code/myapp/Builds/MacOSX/build/Debug/myapp.app/Contents/MacOS (master)
 $ otool -L myapp
myapp:
	@loader_path/libcurl.4.dylib (compatibility version 9.0.0, current version 9.0.0)
	/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate (compatibility version 1.0.0, current version 4.0.0)