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.