Search code examples
xcodemacoslinkerdylib

Linker setting for distributed dylib


I'm struggling with the right options in XCode to include a dylib in my app. I do have a dylib in /usr/local/lib which I do need for my app. As long as I set this path in Lib Search Paths

enter image description here

everything works fine. But of course I want to distribute the dylib with my app which is why I added it to a copy phase:

enter image description here

This indeed copies the dylib into the Frameworks folder in the app. But running on the target system, the app does not find the dylib. It even does not find it in /usr/local/lib. Rather it croaks:

Dyld Error Message:

Library not loaded: @rpath/libopencv_imgproc.3.2.dylib

So, which option needs to be set?

Edit I put together a sample project here. It contains 3 zips: one project, one with the headers to be placed in /usr/local/include and one with the dylibs to be placed in /usr/local/lib. Once the app is compiled it should be able to run anywhere. The dylib is copied into the app, but when run on a clean machine it still looks in /usr/local/lib for the dylib.

I tried (too) many ways to get this to work, so I'm currently completely mixed up.


Solution

  • In my earlier comment as mentioned the name of the dylib in the error message differs (3.2 vs. 3.2.0) from that of the one you are actually using. Since the dylib is already built and you are including it this way in your project that's an indicator an existing rpath or id already exists.

    Using otool:

    $ otool -l libopencv_core.3.2.0.dylib
    ...
     Load command 3
              cmd LC_ID_DYLIB
          cmdsize 56
             name @rpath/libopencv_core.3.2.dylib (offset 24)
       time stamp 1 Wed Dec 31 17:00:01 1969
          current version 3.2.0
    compatibility version 3.2.0
    ...
     Load command 16
              cmd LC_RPATH
          cmdsize 32
             path /usr/local/lib (offset 12)
    

    Two things can be observed here; the first being the LC_ID_DYLIB which confirms the discrepancy, and secondly, the LC_RPATH (rpath) which is present is set to indicate the library location is /usr/local/lib. Since you are including the lib with your app it should be updated.

    Update the library (the one included in your app):

    $ install_name_tool -id @rpath/libopencv_core.3.2.0.dylib libopencv_core.3.2.0.dylib
    

    Updates the LC_ID_DYLIB.

    $ install_name_tool -add_rpath "@executable/../Frameworks" libopencv_core.3.2.0.dylib
    

    Adds the correct LC_RPATH.

    $ install_name_tool -delete_rpath "/usr/local/lib" libopencv_core.3.2.0.dylib
    

    Removes the rpath /usr/local/lib from the library. To verify run otool -l again:

    ...
     Load command 3
              cmd LC_ID_DYLIB
          cmdsize 64
             name @rpath/libopencv_core.3.2.0.dylib (offset 24)
       time stamp 1 Wed Dec 31 17:00:01 1969
          current version 3.2.0
    compatibility version 3.2.0
    ...
     Load command 17
              cmd LC_RPATH
          cmdsize 40
             path @executable/../Frameworks (offset 12)
    

    Now you should be able to include the dylib in a standalone app and it's path should be set correctly; the updated dylib is here. After updating the library the app opens without issue.

    Notes: In your question you are importing libopencv_core3.2.0.dylib, although the error states libopencv_imgproc.3.2.dylib, but I assume it's another dylib which suffers a similar issue, so this can certainly be applied to others. The rpath you had originally set in Xcode was correct

    enter image description here

    although since libraries allow multiple rpaths to exist and /usr/local/bin already is present it's using that location first, in addition to the wrong name.