在macOS上。so和.dylib有什么区别?

.dylib是macOS上的动态库扩展名,但我从来都不清楚什么时候不能/不应该使用传统的unix .so共享对象。

我有一些问题:

  • 在概念层面上,.so和.dylib之间的主要区别是什么?
  • 什么时候我可以/应该使用其中一种而不是另一种?
  • 编译技巧&提示(例如,gcc -shared -fPIC的替换,因为它在osx上不起作用)
142352 次浏览

Mac OS X用于可执行文件和库的Mach-O对象文件格式区分了共享库动态加载模块。使用otool -hv some_file查看some_file的文件类型。

Mach-O共享库的文件类型为MH_DYLIB,扩展名为.dylib。它们可以被链接到通常的静态链接器标志,例如libfoo.dylib的-lfoo。它们可以通过将-dynamiclib标志传递给编译器来创建。(-fPIC是默认值,不需要指定。)

可加载模块在Mach-O语言中称为“包”。它们的文件类型为MH_BUNDLE。它们可以携带任何扩展;Apple推荐扩展名.bundle,但大多数移植软件出于兼容性考虑使用.so。通常,你会为插件使用扩展应用程序的包;在这种情况下,bundle将链接到应用程序二进制文件,以访问应用程序导出的API。它们可以通过将-bundle标志传递给编译器来创建。

dylibs和bundle都可以使用dl api(例如dlopendlclose)动态加载。不可能像链接共享库一样链接包。然而,也有可能一个bundle链接到真正的共享库;这些将在bundle加载时自动加载。

从历史上看,这种差异更为显著。在Mac OS X 10.0中,没有动态加载库的方法。10.1引入了一组dyld api(例如NSCreateObjectFileImageFromFileNSLinkModule)来加载和卸载捆绑包,但它们不适用于dylibs。在10.3中添加了与捆绑包一起工作的dlopen兼容性库;在10.4中,dlopen被重写为dyld的原生部分,并增加了对加载(但不卸载)dylibs的支持。最后,10.5添加了对dylibs使用dlclose的支持,并弃用了dyld api。

在ELF系统如Linux上,两者都使用相同的文件格式;任何一段共享代码都可以用作库和动态加载。

最后,请注意,在Mac OS X中,“包”可以引用具有标准化结构的目录,该结构包含可执行代码和该代码使用的资源。有一些概念上的重叠(特别是与“可加载包”,如插件,通常包含Mach-O包形式的可执行代码),但它们不应该与上面讨论的Mach-O包混淆。

额外的引用:

.so文件不是共享库的UNIX文件扩展名。

它只是碰巧是一个常见的问题。

检查行3b ArnaudRecipes sharedlib页面

基本上,.dylib是用来指示共享库的mac文件扩展名。

在mac os x上,.dylib和.so的区别在于它们是如何编译的。对于.so文件使用-shared,对于.dylib文件使用-dynamiclib。.so和. DYLIB都可以作为动态库文件互换,它们的类型都是DYLIB或BUNDLE。下面是不同文件的读数显示这一点。

libtriangle.dylib:
Mach header
magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00       DYLIB    17       1368   NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS






libtriangle.so:
Mach header
magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00       DYLIB    17       1256   NOUNDEFS DYLDLINK TWOLEVEL NO_REEXPORTED_DYLIBS


triangle.so:
Mach header
magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64  X86_64        ALL  0x00      BUNDLE    16       1696   NOUNDEFS DYLDLINK TWOLEVEL

这两个在Mac OS X上是等价的原因是为了向后兼容其他编译为.so文件类型的UNIX操作系统程序。

编译注意事项:无论编译的是.so文件还是.dylib文件,都需要在链接步骤中将正确的路径插入到动态库中。可以通过向链接命令添加-install_name和文件路径来实现这一点。如果你不这样做,你会遇到在这篇文章中看到的问题:Mac动态库疯狂(可能只支持Fortran)

我在OSX上用cmake构建简单代码时观察到:

cmake ... -DBUILD_SHARED_LIBS=OFF ...

创建所以文件

cmake ... -DBUILD_SHARED_LIBS=ON ...

创建.dynlib文件。

也许这对任何人都有帮助。