【问题标题】:Linking 2 static libs into 1 for iOS将 2 个静态库链接到 1 个用于 iOS
【发布时间】:2012-03-02 09:42:36
【问题描述】:

我在 Xcode 中创建了两个独立的静态库,用于 iOS,A 和 B。A 使用 B 中定义的方法。

在创建需要 A 和 B 的新 Xcode 项目时,我可以分别包含它们。但是,为了简化集成,我更喜欢创建一个包含 A 和 B 的通用框架。

是否可以在 Xcode 中将 2 个静态库合并为 1 个,而无需将 2 个库的代码合并到 1 个项目中。换句话说。在编译/链接静态库 A 时,我可以以某种方式将编译后的静态库 B 链接到静态库 A 中吗?

如果可以的话,我该怎么做?

【问题讨论】:

标签: ios xcode


【解决方案1】:

我刚刚运行了一些快速测试,它似乎是自动发生的。这就是我所做的:

  • 我使用 DerivedData 文件夹作为所有 3 个项目的默认构建位置(这是我使用的 XCode 4.2 中的默认设置)
  • 我将 Public Headers 文件夹路径 更改为 include/ProjectX,其中 X 是静态库的名称。我只为静态库 A 和 B 执行此步骤,而不是为实际链接它们的项目执行此步骤。这一步是为了能够导入<LibX/Header.h>之类的标头。
  • 我使库 B 直接依赖于库 A,并将 A 链接到 B
  • 我将库A直接依赖于主项目并将主项目链接到A

在这个基本设置之后,我使用类似于 <LibB/Header.h> 的东西将类从 B 导入到 A 并编写了一些实际使用 B 的代码。然后,我使用 <LibA/Header.h> 和 @ 将 A 和 B 导入到主项目中987654324@ 并编写了使用 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。然后重新打开 A 并使用 Finder 导航到 B 项目文件,然后将 B 拖放到 A 工作区中。如果不起作用,请重复。

EDIT2 如果您无法访问 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 标头目标。

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

重要

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

【讨论】:

  • Lawicko,感谢您的回复。我留下的一个问题是,当您编写“我使库 B 直接依赖于库 A 并将 A 与 B 链接”时,您如何创建依赖关系?
  • Lawicko,在我关闭所有项目后它可以工作 :-) 但是,我对解决方案并不完全满意,因为当我将 B 项目文件拖放到 A 项目中时,源代码对于 B 暴露于项目 A (我可以在左侧展开项目 B 并在那里查看所有项目代码。我不确定是否可以以某种方式解决(我宁愿将静态库 B 拖放到项目中并当我编译 A 时,强制 Xcode 将 B 合并到静态库 A 中。我会接受答案,因为我学到了一些关于 xcode 的新知识,感谢你 :-)
  • 是的,这个拖放部分在后面很痛苦。我很高兴你成功了!
  • 浏览 A 时可以看到 lib B 的事实并不意味着来自 B 的文件现在是 A 的一部分。它们不是。这个直接依赖技巧只告诉 XCode 在编译 A 之前重新编译 B。但是,我知道你指的是什么。如果您无法访问 B 的来源怎么办?然后你只想链接到静态 libB.a 并添加标题。我过去使用 Reachability 库成功地做到了这一点,给我一些时间,我会告诉你如何做到这一点。
  • 当您无权访问库资源时,请查看我编辑的答案。
【解决方案2】:

根据this answer,我已经使用 libtool 完成了。

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

  • 找出正在构建 A 的架构:

    LIPO_ARCH=$(lipo -info ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME} | awk 'END{ print $NF }')
    
  • 创建 B 的精简版本,仅构建架构

    lipo -thin ${LIPO_ARCH} ${FULLPATH_OF_B} -output ${FULLPATH_OF_THIN_B}
    
  • 将 A 和 B 连接成一个新的 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}
    
  • 删除临时文件

    rm ${FULLPATH_OF_THIN_A}
    rm ${FULLPATH_OF_THIN_B}
    

【讨论】:

    猜你喜欢
    • 2019-03-09
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 2021-06-13
    相关资源
    最近更新 更多