如何在Xcode中创建动态库(dylib)?

30

我正在Xcode中构建一些命令行工具(纯C,无Cocoa)。我希望它们都使用我的定制版libpng,并通过在所有可执行文件之间共享一个库的副本来节省空间(我不介意将.dylib与它们一起重新分发)。

我需要做一些神奇的操作才能获取libpng导出符号吗?

“链接二进制文件与库”构建阶段是否静态链接?

Apple的文档提到使用dlopen在运行时加载库,但我如何使Xcode创建可执行文件而不会抱怨缺少符号?


我想我已经解决了:

  • libpng没有正确链接,因为我构建了32/64位可执行文件和32位库。库和可执行文件的构建设置必须匹配。

  • libpng的config.h需要有大量的定义,比如#define FEATURE_XXX_SUPPORTED

  • “链接二进制文件与库”构建阶段可以很好地处理动态库,对于从应用程序包加载.dylib,需要使用DYLD_FALLBACK_LIBRARY_PATH环境变量。


我想建议使用mach-o标签,但我不认为值得删除任何现有的标签来支持它。 - ephemient
4个回答

56

在Mac OS X上进行动态链接,一个简单的示例

步骤:

  1. 创建一个包含mymod.o的库libmylib.dylib
  2. 编译并链接一个调用它的“callmymod”
  3. 使用DYLD_LIBRARY_PATH和DYLD_PRINT_LIBRARIES从callmymod中调用mymod

问题:你“只是”想创建一个供其他模块使用的库。 然而有一大堆程序 - gcc、ld、MacOSX libtool、dyld - 有无数个选项,有些已经腐烂了,而且MacOSX和Linux之间也存在差异。 有大量的man页(我在10.4.11 ppc中数了7679+1358+228+226行), 但是没有太多的示例或者可以让你“告诉我你在做什么”的程序。

(理解最重要的事情是为自己制作一个简化的概述: 画些图,运行一些小的示例,向别人解释)。

背景:苹果关于动态库的概述维基百科动态库


步骤1,创建libmylib.dylib库--

mymod.c:
    #include <stdio.h>
    void mymod( int x )
    {
        printf( "mymod: %d\n", x );
    }
gcc -c mymod.c  # -> mymod.o
gcc -dynamiclib -current_version 1.0  mymod.o  -o libmylib.dylib
    # calls libtool with many options -- see man libtool
    # -compatibility_version is used by dyld, see also cmpdylib

file libmylib.dylib  # Mach-O dynamically linked shared library ppc
otool -L libmylib.dylib  # versions, refs /usr/lib/libgcc_s.1.dylib

第二步,编译并链接 callmymod --

callmymod.c:
    extern void mymod( int x );
    int main( int argc, char** argv )
    {
        mymod( 42 );
    }
gcc -c callmymod.c
gcc -v callmymod.o ./libmylib.dylib -o callmymod
    # == gcc callmymod.o -dynamic -L. -lmylib
otool -L callmymod  # refs libmylib.dylib
nm -gpv callmymod  # U undef _mymod: just a reference, not mymod itself

第三步,运行callmymod以链接到libmylib.dylib库--

export DYLD_PRINT_LIBRARIES=1  # see what dyld does, for ALL programs
./callmymod
    dyld: loaded: libmylib.dylib ...
    mymod: 42

mv libmylib.dylib /tmp
export DYLD_LIBRARY_PATH=/tmp  # dir:dir:...
./callmymod
    dyld: loaded: /tmp/libmylib.dylib ...
    mymod: 42

unset DYLD_PRINT_LIBRARIES
unset DYLD_LIBRARY_PATH

这就是一个小例子的结束,希望它有助于理解这些步骤。
(如果您需要经常执行此操作,请查看GNU Libtool,在Macs上为glibtool, 以及SCons。)


不错。如果您已经有了.o文件,但是有9个文件在3个文件夹中,但都属于同一个“框架”...这是否需要调用lipo,还是其他方法?顺便说一下,我正在尝试让libg7221成为一个“共享”“库”。 - Alex Gray
@alex gray,不知道,抱歉;请将其作为一个新问题提出? - denis

7
很不幸,根据我的经验,苹果的文档已经过时、冗余,并且缺失了许多通常需要的常见信息。
我在我的网站上写了一些东西,其中我必须让FMOD(声音API)与我们在大学开发的跨平台游戏配合使用。这是一个奇怪的过程,我很惊讶苹果没有在他们的开发者文档中添加更多信息。
很不幸,“邪恶”的微软实际上在文档方面为他们的开发人员做得更好(这是来自苹果福音传道者的话)。
我认为基本上,你没有做的是在编译了 .app 捆绑包之后。然后,您需要在可执行二进制文件 /MyApp.app/contents/MacOS/MyApp 上运行一个命令,以更改可执行文件查找其库文件的位置。您必须创建一个新的构建阶段,可以运行脚本。我不会再次解释这个过程,我已经在这里详细介绍过:

http://brockwoolf.com/blog/how-to-use-dynamic-libraries-in-xcode-31-using-fmod

希望这能帮到你。

2
@wintermute:一条不必要的评论。我相信这个网站上的每个用户都听过一百万遍。 - Brock Woolf
1
链接失效。已存档 https://web-beta.archive.org/web/20100620075647/http://brockwoolf.com:80/blog/how-to-use-dynamic-libraries-in-xcode-31-using-fmod - original_username

7
您可能需要确保您构建的动态库具有一个导出符号文件,该文件列出了应从库中导出的内容。这只是一个扁平的符号列表,每行一个,以进行导出。
此外,当您构建动态库时,它会嵌入一个“安装名称”,默认情况下是构建路径。随后,任何链接到它的内容都将首先在指定路径上查找,然后仅在dyld(1) man page中描述的一组默认路径下搜索(小)集合下的DYLD_FALLBACK_LIBRARY_PATH
如果您要将此库放在可执行文件旁边,则应调整其安装名称以引用该文件。只需通过Google搜索“安装名称”即可找到大量有关如何执行此操作的信息。

如果我只有一个简单的纯C函数,并且想将其公开为动态库,该怎么办(在Windows上使用Visual Studio很容易)? - Royi

4
你是否了解苹果参考页面 动态库编程主题?它应该涵盖大部分你需要的内容。请注意,在程序启动时会加载一些共享库,而在需要时会加载一些动态加载库(捆绑包,如果我没记错),而在MacOS X上,这两者与Linux或Solaris上的等效物略有不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接