unload dynamic library needs two dlclose() calls?

MacOS

Question or issue on macOS:

I have a dynamic library which I load using dlopen() and then unload using dlclose();

If I dont include any objective c code dlopen() needs one dlclose() call which is expected behavior. But when I include any objective c code to target, I have problem that I need to do two dlclose() calls to the loaded library in order to unload.

Is this something expected behavior? How can I fix it?

How to solve this problem?

I realize that you are using dlopen, not CFBundle or NSBundle. Nevertheless, the Code Loading Programming Topics manual says this:


In Cocoa applications, you should not use CFBundle routines to load and unload executable code, because CFBundle does not natively support the Objective-C runtime. NSBundle correctly loads Objective-C symbols into the runtime system, but there is no way to unload Cocoa bundles once loaded due to a runtime limitation.

and this:


Because of a limitation in the Objective-C runtime system, NSBundle cannot unload executable code.

This makes me suspect that when you load your library, it registers itself with the Objective-C runtime, and the runtime calls dlopen on the library again (or somehow increases the library’s reference count).

I searched the Objective-C runtime source code and found this:

// dylibs are not allowed to unload
// ...except those with image_info and nothing else (5359412)
if (result->mhdr->filetype == MH_DYLIB  &&  _hasObjcContents(result)) {
    dlopen(result->os.dl_info.dli_fname, RTLD_NOLOAD);
}

So yes, the Objective-C runtime is calling dlopen on your library specifically to prevent it from being unloaded. If you cheat and call dlclose twice, you should expect bad things to happen.

Hope this helps!