What Are the Differences Between .So and .Dylib on Macos

What are the differences between .so and .dylib on macOS?

The Mach-O object file format used by Mac OS X for executables and libraries distinguishes between shared libraries and dynamically loaded modules. Use otool -hv some_file to see the filetype of some_file.

Mach-O shared libraries have the file type MH_DYLIB and carry the extension .dylib. They can be linked against with the usual static linker flags, e.g. -lfoo for libfoo.dylib. They can be created by passing the -dynamiclib flag to the compiler. (-fPIC is the default and needn't be specified.)

Loadable modules are called "bundles" in Mach-O speak. They have the file type MH_BUNDLE. They can carry any extension; the extension .bundle is recommended by Apple, but most ported software uses .so for the sake of compatibility. Typically, you'll use bundles for plug-ins that extend an application; in such situations, the bundle will link against the application binary to gain access to the application’s exported API. They can be created by passing the -bundle flag to the compiler.

Both dylibs and bundles can be dynamically loaded using the dl APIs (e.g. dlopen, dlclose). It is not possible to link against bundles as if they were shared libraries. However, it is possible that a bundle is linked against real shared libraries; those will be loaded automatically when the bundle is loaded.

Historically, the differences were more significant. In Mac OS X 10.0, there was no way to dynamically load libraries. A set of dyld APIs (e.g. NSCreateObjectFileImageFromFile, NSLinkModule) were introduced with 10.1 to load and unload bundles, but they didn't work for dylibs. A dlopen compatibility library that worked with bundles was added in 10.3; in 10.4, dlopen was rewritten to be a native part of dyld and added support for loading (but not unloading) dylibs. Finally, 10.5 added support for using dlclose with dylibs and deprecated the dyld APIs.

On ELF systems like Linux, both use the same file format; any piece of shared code can be used as a library and for dynamic loading.

Finally, be aware that in Mac OS X, "bundle" can also refer to directories with a standardized structure that holds executable code and the resources used by that code. There is some conceptual overlap (particularly with "loadable bundles" like plugins, which generally contain executable code in the form of a Mach-O bundle), but they shouldn't be confused with Mach-O bundles discussed above.

Additional references:

  • Fink Porting Guide, the basis for this answer (though pretty out of date, as it was written for Mac OS X 10.3).
  • ld(1) and dlopen(3)
  • Dynamic Library Programming Topics
  • Mach-O Programming Topics

macOS: What's the correct place to install a dylib on a user's system?

The Mac is a bit of a strange beast when it comes to file system locations, and it's going to get more difficult after macOS 10.15 (Catalina) ships, due to the primary boot file system being read-only.

Depending on the purpose of accessing the library, there are some appropriate places to put it.

In your Application bundle

If you have an Application that is being installed globally in the /Applications folder (most Applications are on the Mac, but sometimes users put them in strange places), then you could use the Application's own folder for storage of the library and it would be available to any code that can read in that folder. There are a number of problems with this, though: the user can move the Application, permissions may be wrong, and you have to be careful in any code that uses the Apple Hardened Runtime because it requires special flags to load code signed by anyone other than the signatory on the Application loading the library. The advantage is that deleting the Application also deletes your library, so you don't need to write an uninstaller. This technique is used by software like VMWare Fusion (if you need to run command-line code or similar) and

/Library/Application Support or /Library/Frameworks

If you need the library to be persistent and guaranteed to be in one clearly-defined location, then having the User approve your installation into /Library/Application Support/<your application> or into /Library/Frameworks is likely your best bet.

/usr/local/lib

As you've already noticed, /usr/local/lib can be problematic, especially since the popular Homebrew package manager generally sets the /usr/local/lib to be owned by the user installing files with brew so that it can be modified without needing to sudo.

With that said, though, you can install in /usr/local/lib, with the proviso that you may need to escalate privileges in order to perform the installation. Once the installation is done, the directory is usually set to be readable by any other user on the system.

Recommendation

As a long-time Mac user, I prefer when Applications keep themselves contained (codewise) to their Application bundle, and thus would encourage using that mechanism. The downside of the user not installing in /Applications can be mitigated by having the Application itself check when it runs to make sure that it's in the right place, and if not, prompt the user to move it (or do the moving after asking for a privilege elevation). This also removes the need for an installer/uninstaller program.

If that's not acceptable for some reason, then the /Library/Frameworks or /Library/Application Support/<your application> would be your next best bet. They're much less likely to create a problem than /usr/local/lib.

What is the difference between .dylib and .a lib in ios?

Static Library(.a)

Static libraries allow an application to load code into its address space at compile time.This results in a larger size on disk and slower launch times. Because the library's code is added directly to the linked target's binary, it means that to update any code in the library, the linked target would also have to be rebuilt.
Sample Image
Dynamic Library(.dylib)

Dynamic libraries allow an application to load code into its address space when it’s actually needed at run time. Because the code isn't statically linked into the executable binary, there are some benefits from loading at runtime. Mainly, the libraries can be updated with new features or bug-fixes without having to recompile and relink executable. In addition, being loaded at runtime means that individual code libraries can have their own initializers and clean up after their own tasks before being unloaded from memory

Sample Image

What's the meaning of dylib files?

I found that:

One Mach-O feature that hits many people by surprise is the strict
distinction between shared libraries and dynamically loadable modules.
On ELF systems both are the same; any piece of shared code can be used
as a library and for dynamic loading. Use otool -hv some_file to see
the filetype of some_file.

Mach-O shared libraries have the file type MH_DYLIB and carry the
extension .dylib. They can be linked against with the usual static
linker flags, e.g. -lfoo for libfoo.dylib. However, they can not be
loaded as a module. (Side note: Shared libraries can be loaded
dynamically through an API. However, that API is different from the
API for bundles and the semantics make it useless for an dlopen()
emulation. Most notably, shared libraries can not be unloaded.) [This
is no longer true—you can use dlopen() with both dylibs and bundles.
However, dylibs still can't be unloaded.]

Loadable modules are called "bundles" in Mach-O speak. They have the
file type MH_BUNDLE. Since no component involved cares about it, they
can carry any extension. The extension .bundle is recommended by
Apple, but most ported software uses .so for the sake of
compatibility. Bundles can be dynamically loaded and unloaded via dyld
APIs, and there is a wrapper that emulates dlopen() on top of that
API. [dlopen is now the preferred API.] It is not possible to link
against bundles as if they were shared libraries. However, it is
possible that a bundle is linked against real shared libraries; those
will be loaded automatically when the bundle is loaded.

To compile a normal shared library on OS X, you should use -dynamiclib
and the extension .dylib. -fPIC is the default.

What are the g++ flags to build a true .so/MH_BUNDLE shared library on mac osx (not a dylib)?

If you want to build a bundle use -bundle instead of -dynamiclib when you're making the file.

The most obvious difference between bundles and dylibs is that you can link to a dylib at compile time.

e.g. g++ -o testfile testcode.c -lmylib will link to libmylib.dylib, while if you attempt to link a bundle you get:

ld: can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB) file 'test.bundle' for architecture x86_64

This is the biggest difference - you can't link a bundle dynamically, but instead have to dlopen or use the Object File Image Functions. I'd steer away from the OS X only functions - they are deprecated, and you can get all the functionality you need from the dl* functions instead.

As to building each, I'll give an example:

object file test.o, making a dylib:

g++ -dynamiclib -o test.dylib test.o

making a bundle:

g++ -bundle -o test.bundle test.o

linking a bundle at run-time & getting a symbol:

void *v = dlopen("test.bundle", RTLD_LOCAL);
// declare func_ptr as a pointer to a fn taking void, returning an int
int (*func_ptr)(void);
func_ptr = (int (*)(void))dlsym(v, "symbol");

linking a bundle using old routines (seriously, don't do this):

#include <mach-o/dyld.h>

int rc;
NSObjectFileImage img;
NSModule handle;
NSSymbol sym;

rc = NSCreateObjectFileImageFromFile("test.bundle", &img);
if (rc != NSObjectFileImageSuccess) {
fprintf(stderr, "Could not load libanswer.bundle.\n");
exit(-1);
}

/* Get a handle for the bundle. */
handle = NSLinkModule(img, "test.bundle", FALSE);

/* Look up the get_answer function. */
sym = NSLookupSymbolInModule(handle, "_get_answer");
if (sym == NULL)
{
fprintf(stderr, "Could not find symbol: _get_answer.\n");
exit(-2);
}

int (*func_ptr)(void);
func_ptr = NSAddressOfSymbol(sym);

if you're compiling with clang, then you'll get a bunch of warnings like:

warning: 'NSCreateObjectFileImageFromFile' is deprecated: first deprecated in OS X 10.5

i.e. please don't use these functions.



Related Topics



Leave a reply



Submit