Search code examples
cmacosdlopen

OSX: Unable to resolve dependency using dlopen()


I have a library libni on OSX I'm trying to open using dlopen(), and it can't seem to resolve the dependencies to another dlopen()'d library.

Lets not get into why you shouldn't use dlopen(); suffice to say, I have to use it in this circumstance.

Anyway, so this is otool -L on libni.dylib:

lib/libni.dylib:
  libni.dylib (compatibility version 0.0.0, current version 0.0.0)
  libn.dylib (compatibility version 0.0.0, current version 0.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
  libzlib.dylib (compatibility version 0.0.0, current version 0.0.0)
  libpng.dylib (compatibility version 0.0.0, current version 0.0.0)
  liblua.dylib (compatibility version 0.0.0, current version 0.0.0)
  libSDL2.0.dylib (compatibility version 0.0.0, current version 2.0.0)
  libstb.dylib (compatibility version 0.0.0, current version 0.0.0)
  libax.dylib (compatibility version 0.0.0, current version 0.0.0)
  libsqlite3.dylib (compatibility version 0.0.0, current version 0.0.0)
  libfreetype.dylib (compatibility version 0.0.0, current version 0.0.0)
  /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
  /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
  /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
  /System/Library/Frameworks/ForceFeedback.framework/Versions/A/ForceFeedback (compatibility version 1.0.0, current version 1.0.2)
  /System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 155.0.0)
  /System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
  /System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit (compatibility version 1.0.0, current version 1.0.0)

and this is on libn, zlib and png:

libn.dylib:
  libn.dylib (compatibility version 0.0.0, current version 0.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

libpng.dylib:
  libpng.dylib (compatibility version 0.0.0, current version 0.0.0)
  libzlib.dylib (compatibility version 0.0.0, current version 0.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

libzlib.dylib:
  libzlib.dylib (compatibility version 0.0.0, current version 0.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

Now I use dlopen() to open all the dynamic libraries in my 'lib' dir, in order, using:

/** Open a dynamic library file */
void *Type__(open) (char *path) {
  void *impl = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
  if (impl == NULL) {
    char *err = dlerror();
    N_LOG(N_LOG_DEBUG, "Failed to open: %s", err);
  }
  else {
    N_LOG(N_LOG_DEBUG, "Happy open: %s", path);
    rtn = nPosixLinker__Lib(path, impl);
  }
  return rtn;
}

...and get errors/messages like this:

Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libzlib.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libstb.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libsqlite3.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libSDL2.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libn.dylib
Failed to open: dlopen(/Users/doug/projects/libni/build/tests/IImageLoader/lib/libpng.dylib, 10): Library not loaded: libzlib.dylib
  Referenced from: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libpng.dylib
  Reason: image not found
Failed to open: dlopen(/Users/doug/projects/libni/build/tests/IImageLoader/lib/libni.dylib, 10): Library not loaded: libn.dylib
  Referenced from: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libni.dylib
  Reason: image not found
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/liblua.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libfreetype.dylib
Happy open: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libax.dylib
Failed to open: dlopen(/Users/doug/projects/libni/build/tests/IImageLoader/lib/libtest-ni-IImageLoader__.dylib, 10): Library not loaded: libni.dylib
  Referenced from: /Users/doug/projects/libni/build/tests/IImageLoader/lib/libtest-ni-IImageLoader__.dylib
  Reason: image not found

So there's definitely something weird going on here. zlib is opened before libpng, but libpng can't resolve the reference. libn is opened before libni, but libni can't resolve the reference.

It's like my RTLD_GLOBAL is being ignored by dlopen(), or the dependency (eg. libn) isn't finding the loaded library (blah/libn.dylib) because the paths are different...

In fact, I cant seem to make dlopen() open a library which has a dependency at all so I figure I must be doing something wrong.

Any suggestions?

On BSD and linux this all just works; it's definitely an issue strictly related to the way OSX is handling these libraries.


Solution

  • Looks like this is a duplicate of this, but I totally didn't find it until after I already figured out the solution, so I'm going to leave both the question and this link here for now.

    Sort answer: Build the library using -install_name @rpath/lib