28

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

我需要做一些魔术来获取 libpng 导出符号吗?

“Link Binary With Libraries”是否静态构建阶段链接?

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


我想我已经弄清楚了:

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

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

  • “Link Binary With Libraries”构建阶段可以很好地处理动态库,并且DYLD_FALLBACK_LIBRARY_PATH环境变量对于.dylib从应用程序包加载 s 是必需的。

4

4 回答 4

55

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 之间的差异。有大量的手册页(我在 10.4.11 ppc 中计算了 7679 + 1358 + 228 + 226 行),但没有太多示例,或者具有“告诉我你在做什么”模式的程序。

(理解最重要的是给自己做一个简化的OVERVIEW:画一些图,跑一些小例子,给别人解释)。

背景:苹果 OverviewOfDynamicLibraries维基百科 Dynamic_library


第一步,创建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

第 3 步,运行 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 ,它是 mac 上的 glibtool,以及SCons。)

于 2009-02-05T13:54:13.373 回答
7

您可能需要确保您构建的动态库具有导出的符号文件,其中列出了应从库中导出的内容。它只是要导出的符号的平面列表,每行一个。

此外,当您的动态库被构建时,它会在其中嵌入一个安装名称,默认情况下,它是构建它的路径。随后,任何链接到它的东西都会首先在指定的路径中查找它,然后才搜索手册页DYLD_FALLBACK_LIBRARY_PATH中描述的一组(小)默认路径。dyld(1)

如果你打算把这个库放在你的可执行文件旁边,你应该调整它的安装名称来引用它。只需在 Google 上搜索“安装名称”就可以找到大量相关信息。

于 2008-10-12T03:00:34.077 回答
7

不幸的是,根据我的经验,Apple 的文档已经过时、冗余并且缺少很多您通常需要的常见信息。

我在我的网站上写了很多关于这个的东西,我必须让 FMOD(声音 API)与我们在 uni 开发的跨平台游戏一起工作。这是一个奇怪的过程,我很惊讶苹果没有在他们的开发者文档中添加更多信息。

不幸的是,像微软一样“邪恶”,他们实际上在用文档照顾他们的开发人员方面做得更好(这来自苹果的传道者)。

我认为基本上,你没有做的是在你编译了你的 .app Bundle 之后。然后,您需要在可执行二进制文件 /MyApp.app/contents/MacOS/MyApp 上运行命令,以更改可执行文件查找其库文件的位置。您必须创建一个可以运行脚本的新构建阶段。这个过程我就不再解释了,这里我已经深入做过了:

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

希望这可以帮助。

于 2008-11-23T01:33:34.513 回答
4

您知道 Apple 参考页面Dynamic Library Programming Topics吗?它应该涵盖您需要的大部分内容。请注意,有一个在程序启动时无条件加载的共享库和按需加载的动态加载库(bundles,IIRC),两者在 MacOS X 上与 Linux 或 Solaris 上的等效库有些不同。

于 2008-10-12T02:21:24.720 回答