Krzysiek
Krzysiek

Reputation: 195

How do I link libraries with rpath in Xcode?

I can't find this information anywhere. I have some libraries installed in my system, so it works on my computer, but I want to distribute the libraries with my application. The problem that I see is that otool shows absolute paths to system libraries, so when I copy my binaries to other machine it can't find them even tho I have them in a directory that is added in "runpath search paths". I have one local library (located in project dir) and it is linked with @rpath prefix. Other system libraries are linked the same way but they have absolute paths as otool shows. How do I force them to be linked with @rpath prefix?

Upvotes: 1

Views: 1281

Answers (2)

Greenonline
Greenonline

Reputation: 1377

TL;DR

Using install_name_tool -change will certainly set the @rpath for the referenced frameworks/libraries. However, it doesn't change the names of the libraries themselves.

To do that you need to use install_name_tool -id.


Using a rough example of a project I'm working on currently, where QtGui.framework (amongst others, i.e. QtCore, etc.) is a bundled framework within an application bundle called serialplot.app.

Having first run install_name_tool -change to fix the relative paths for QtGui (and QtCore etc.) being called by serialplot application binary

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/MacOS/serialplot

... (omitted commands for clarity)
 
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/MacOS/serialplot

as well as install_name_tool -change to fix the relative path for QtCore which being called by QtGui itself

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

Now running otool -L on the application binary gives

serialplot.app/Contents/MacOS/serialplot:
    @rpath/qwt.framework/Versions/6/qwt (compatibility version 6.2.0, current version 6.2.0)
    @rpath/QtSvg.framework/Versions/5/QtSvg (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1671.10.106)
    /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 1.0.0)
    @rpath/QtSerialPort.framework/Versions/5/QtSerialPort (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.15.0, current version 5.15.2)

So everything looks fine, with @rpath being used for QtGui (as well as the other Qt frameworks).

However, running otool -L on the bundled QtGui, within the application bundle, shows

serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1671.10.106)
    /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 1.0.0)
    @rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1247.4.1)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1560.12.0)
    /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 50.1.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1560.12.0)
    /System/Library/Frameworks/CoreText.framework/Versions/A/CoreText (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

Note that (as you state) the absolute path (/usr/local/opt/qt@5/lib/), and not @rpath is used

$ otool -L serialplot.app/Contents/Frameworks/QtGui.framework/QtGui 
serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
...

Now run install_name_tool -id

$ install_name_tool -id @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

and the output of otool -L now gives you what you want

$ otool -L serialplot.app/Contents/Frameworks/QtGui.framework/QtGui 
serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    @rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
...

Yes, it is complex, and annoying, but perfectly scriptable with a little patience.

For more details on this particular example, see my blog on this project: Porting serialplot to OS X

Upvotes: 1

Krzysiek
Krzysiek

Reputation: 195

Well this partially answers my question: How to set dyld_library_path in Xcode

I tried to automate that, so when any new library is added then it would set things up properly, but I gave up (gosh, why does it have to be so complicated!?)

Upvotes: 1

Related Questions