将两个静态库链接为一个iOS库

6
我已经在Xcode中创建了两个独立的静态库,A和B,用于iOS。 A使用在B中定义的方法。
当创建一个需要同时使用A和B的新的Xcode项目时,我可以单独包含它们。然而,为了简化集成,我更喜欢创建一个包含A和B的通用框架。
在Xcode中,是否有可能将2个静态库合并成1个,而不将2个库的代码合并到1个项目中?换句话说,我能否在编译/链接静态库A时将编译好的静态库B链接到静态库A中?
如果这是可能的,我该如何实现?

与https://dev59.com/MGsz5IYBdhLWcg3wADS6相关。 - Bruce
还涉及到https://dev59.com/jHjZa4cB1Zd3GeqPaBxo。 - xverges
2个回答

5
我刚进行了一些快速的测试,似乎这是自动发生的。以下是我的步骤:
  • 我将DerivedData文件夹作为所有三个项目的默认构建位置(这是我使用的XCode 4.2的默认设置)。
  • 我将Public Headers Folder Path更改为include/ProjectX,其中X是静态库的名称。我只对静态库A和B执行此步骤,而不对实际链接它们的项目执行此步骤。此步骤是为了能够像<LibX/Header.h>这样导入头文件。
  • 我使库B成为库A的直接依赖项,并将A与B链接。
  • 我使库A成为主项目的直接依赖项,并将主项目与A链接。
完成这些基本设置后,我使用类似于<LibB/Header.h>的方式从B导入类到A,并编写了一些实际使用B的代码。然后,我使用<LibA/Header.h><LibB/Header.h>将A和B导入到主项目中,并编写了使用A和B的代码。最后,我通过终端进入了DerivedData文件夹,并导航到构建A的位置。我使用以下命令检查LibA.a文件是否包含来自LibB的对象:
nm LibA.a

是的,它包含来自LibB的对象。因此,总结一下,通过这个简单的依赖设置,您应该能够得到您所要求的。

编辑 要使B成为A的直接依赖项并将A链接到B,请执行以下操作:

在XCode中打开A,转到Finder并将B项目文件拖放到A中。然后,在A中选择根元素,转到Build Phases,展开Target Dependencies,按“+”按钮,选择B并确认。然后展开Link Binary With Libraries,按“+”按钮,选择B.a(或任何产品名称)并确认。

重要提示 XCode中存在一个错误,会导致您无法正确地将B项目文件拖放到A工作区。相反,您将在A工作区中留下B项目文件,但是您无法扩展B并对其进行任何操作。要解决此问题,请从A中删除有问题的B项目文件引用,关闭A,如果您已经打开B,则关闭B。然后重新打开A,并使用Finder导航到B项目文件,然后将B拖放到A工作区内。如果不起作用,请重复上述步骤。

编辑2 如果您没有访问B(可能还包括A)的源代码,则使之工作只是将所需的标头复制到正确的位置。然后在主项目中,您不会将A作为直接依赖项,而是链接到您拥有的静态libA.a。如果A使用B,则来自B的符号已经在libA.a中了。您可以使用nm工具检查此情况,就像我以上所做的那样。因此,我们只需要使用B标头将这些符号公开给主应用程序。有几种方法可以实现这一点,我记得我只是将标头复制到依赖链中间的库的Copy Headers目标路径中。之后,通过链接A并将A标头添加到User Header Search Paths中,我就能够直接访问B了。最适合您的方法取决于您是否可以访问A的源代码。如果您有,有两个选项可供考虑:

  • 将B标头添加到A(它们将自动复制到A标头目标中)。但我猜您不想要这个解决方案。
  • 为A目标添加自定义运行脚本构建阶段,该阶段将获取B标头并将其复制到A标头目标中。

在这两种情况下,您最终都会得到LibA.a,其中包含了A和B的编译源代码,以及包含A和B标头的标头文件夹。然后,您可以将您的主项目链接到LibA.a,并将标头文件夹路径添加到User Headers Search Path中,然后您应该就可以开始了。

重要提示

如果在您的库中有仅包含类别代码的文件,请确保使用-force_load链接此库,否则您的类别符号将无法正确打包。


Lawicko,感谢您的回复。我还有一个问题,就是当您写下“我将库B作为库A的直接依赖项,并将A与B链接”时,您是如何创建这种依赖关系的? - Alexander van Elsas
Lawicko,我关闭了所有项目后它就可以工作了 :-) 但是我对这个解决方案并不完全满意,因为当我将B项目文件拖放到A项目中时,B的源代码会暴露给A项目(我可以在左侧展开B项目并查看所有项目代码)。我不确定是否可以通过某种方式解决这个问题(我更愿意只将静态库B拖放到项目中,并在编译A时强制Xcode将B合并到静态库A中)。不过,我还是接受了你的答案,因为我通过你学到了一些新的关于Xcode的知识 :-) - Alexander van Elsas
是的,这个拖放部分真是让人头疼。我很高兴你做到了! - lawicko
你可以在浏览A时看到lib B,但这并不意味着B的文件现在是A的一部分。它们不是。这种直接依赖关系只是告诉XCode在编译A之前重新编译B。然而,我知道你指的是什么。如果你没有访问B的源代码怎么办?那么你只需要链接到静态库B.a并添加头文件。我以前用Reachability库做过这个,给我一些时间,我会告诉你如何做到这一点。 - lawicko
请看我编辑后的答案,当您无法访问库源代码时使用。 - lawicko

3

我已经用libtool完成了它,按照这个答案的建议。

为此,在Xcode 5.0.2中,我向A添加了一个脚本(Editor -> Add Build Phase -> Add Run Script Build Phase),其中包括:

  • figures out the architecture for which A is being built:

    LIPO_ARCH=$(lipo -info ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME} | awk 'END{ print $NF }')
    
  • creates a thin version of B, with only the architecture being built

    lipo -thin ${LIPO_ARCH} ${FULLPATH_OF_B} -output ${FULLPATH_OF_THIN_B}
    
  • joins A and B into a new A

    mv ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME} ${FULLPATH_OF_THIN_A}
    libtool -static -o ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME} ${FULLPATH_OF_THIN_A} ${FULLPATH_OF_THIN_B}
    
  • removes the temp files

    rm ${FULLPATH_OF_THIN_A}
    rm ${FULLPATH_OF_THIN_B}
    

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