Fresh eyes this morning and I was able to debug this a bit more: in my Xcode scheme options, I set Console to Use Terminal, which let me then see the full command line invocation Xcode uses to launch the app, which I was able to copy-paste to my own terminal and confirm the problem persists, so it's because of how Xcode is running my app. Process of elimination found the culprit. Xcode sets the env var (among others)
DYLD_LIBRARY_PATH=$SYMROOT:$OBJROOT:/usr/lib/system/introspection
My plugin feature.dylib gets built into $OBJROOT and then copied into my app's expected plugin folder $PLUGINROOT along with its library dependency libexternal.so. When I call dlopen to load the plugin, I use the absolute path: dlopen("$PLUGINROOT/feature.dylib", 0). I use DYLD_PRINT_LIBRARIES=1 to see what dlopen actually loads. When I run MyApp.app without setting DYLD_LIBRARY_PATH, I see that dlopen opens $PLUGINROOT/feature.dylib as I expected. However, when I run MyApp.app with the DYLD_LIBRARY_PATH used by Xcode, I can see that dlopen opens $OBJROOT/feature.dylib. So that explains why running from within Xcode causes the plugin load to fail, because libexternal.so does not exist in $OBJROOT.
This seems like a bug! Right? I'm providing an absolute path to dlopen and it's using a different path based on the env var!
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags: