简体   繁体   English

将2个静态库链接为1,用于iOS

[英]Linking 2 static libs into 1 for iOS

I have created two separate static libraries in Xcode for usage on iOS, A and B. A uses methods that are defined in B. 我在Xcode中创建了两个独立的静态库,用于iOS,A和B.A使用B中定义的方法。

When creating a new Xcode project where both A and B are needed, I can include them separately. 在创建需要A和B的新Xcode项目时,我可以单独包含它们。 However, for simplicity of integration I prefer to create a Universal Framework that contains both A and B. 但是,为了简化集成,我更喜欢创建一个包含A和B的通用框架。

Is it possible in Xcode to merge 2 static libraries into 1, without merging the code of the 2 libraries in 1 project. 是否有可能在Xcode中将2个静态库合并为1,而不在1个项目中合并2个库的代码。 In other words. 换一种说法。 Can I somehow link the compiled static library B into static library A when I am compiling/Linking static library A? 当我编译/链接静态库A时,我可以以某种方式将编译的静态库B链接到静态库A中吗?

If this is possible, how can I accomplish this? 如果可以的话,我该如何做到这一点?

I've just run some quick tests and it seems to be happening automatically. 我刚刚进行了一些快速测试,它似乎是自动发生的。 This is what I did: 这就是我做的:

  • I used DerivedData folder as a default build location for all 3 projects (this is default in XCode 4.2 which I use) 我使用DerivedData文件夹作为所有3个项目的默认构建位置(这在我使用的XCode 4.2中是默认的)
  • I changed Public Headers Folder Path to include/ProjectX where X is the name of the static library. 我将Public Headers Folder Path更改为include / ProjectX ,其中X是静态库的名称。 I did this step only for static libraries A and B, not for the project that will actually link them. 我只为静态库A和B执行此步骤,而不是实际链接它们的项目。 This step is to be able to import the headers like <LibX/Header.h> . 这一步是为了能够导入像<LibX/Header.h>这样的头文件。
  • I made library B direct dependency of the library A and linked A against B 我使库B直接依赖库A并将A链接到B.
  • I made library A direct dependency of the main project and linked main project against A 我使库A直接依赖于主项目并将主项目与A相关联

After this basic setup, I imported classes from B to A with something similar to <LibB/Header.h> and wrote some code that actually made use of B. Then, I imported A and B to the main project with <LibA/Header.h> and <LibB/Header.h> and wrote code that made use of A and B. Finally, I went to the DerivedData folder with the terminal and navigated to the location where A is built. 在这个基本设置之后,我将类从B导入到A,类似于<LibB/Header.h>并编写了一些实际使用B的代码。然后,我用<LibA/Header.h>将A和B导入到主项目中<LibA/Header.h><LibB/Header.h>并编写了使用A和B的代码。最后,我使用终端转到DerivedData文件夹并导航到构建A的位置。 I checked if LibA.a contains objects from LibB with: 我检查了LibA.a是否包含来自LibB的对象:

nm LibA.a

And yes, it contains objects from LibB. 是的,它包含来自LibB的对象。 So, to sum up, with this simple dependency setup you should be able to get what you asked for. 总而言之,通过这种简单的依赖设置,您应该能够得到您所要求的内容。

EDIT To make B direct dependency of A and link A against B do this: 编辑使B直接依赖A和链接A对B执行此操作:

Having A open in the XCode, go to Finder and drag&drop B project file into A. Then, choose the root element in A, go to Build Phases, expand Target Dependencies, press '+' button, choose B and confirm. 在XCode中打开A,转到Finder并将B项目文件拖放到A.然后,选择A中的根元素,转到Build Phases,展开Target Dependencies,按'+'按钮,选择B并确认。 then expand Link Binary With Libraries, press '+' button, choose Ba (or whatever the product name is) and confirm. 然后展开Link Binary With Libraries,按'+'按钮,选择Ba(或任何产品名称)并确认。

Important There is a bug in XCode that prevents you from properly dropping B project file into A workspace. 重要信息 XCode中存在一个错误,阻止您将B项目文件正确地放入A工作区。 Instead, you are left with B project file in A workspace, but you cannot expand B and do anything with it. 相反,您在A工作区中留下B项目文件,但您无法扩展B并对其执行任何操作。 To work around this problem, remove the faulty B project file reference from A, close A, close B if you have it open. 要解决此问题,请从A中删除有故障的B项目文件引用,关闭A,如果已打开则关闭B. Then reopen A and use Finder to navigate to B project file, then drag&drop B inside A workspace. 然后重新打开A并使用Finder导航到B项目文件,然后将B拖放到A工作区内。 If didn't work, repeat. 如果不起作用,请重复。

EDIT2 I case you don't have access to the sources of B (and possibly A), making this work is just a matter of copying the required headers in the proper place. EDIT2我的情况是你无法访问B的源(可能还有A),这使得这项工作只需要在适当的位置复制所需的标题。 Then in you main project, you don't make the A direct dependency, instead you link against static libA.a that you have. 然后在你的主项目中,你没有直接依赖,而是链接到你拥有的静态libA.a。 If A uses B, then the symbols from B are already in the libA.a. 如果A使用B,那么B中的符号已经在libA.a中。 You can check this with nm tool like I do above. 你可以像我上面的nm工具一样检查这个。 So we are down to exposing those symbols to the main application with B headers. 因此,我们将使用B头将这些符号暴露给主应用程序。 There are a couple of ways to do it, I remember that I simply copied the headers to the Copy Headers destination path of the library that is in the middle of the dependency chain. 有几种方法可以做到这一点,我记得我只是将标题复制到位于依赖关系链中间的库的Copy Headers目标路径。 After that, by linking against A and adding A headers to User Header Search Paths I was able to access B directly. 之后,通过链接A并将A标题添加到用户标题搜索路径,我能够直接访问B. What is the best way to do it for you depends on if you have access to the sources of A. If you have, there are two options to consider: 为您做这件事的最佳方式取决于您是否可以访问A的来源。如果有,有两种选择:

  • Add B headers to A (they will be automatically copied to the A headers destination). 将B标头添加到A(它们将自动复制到A标头目标)。 But I guess you don't want this solution. 但我想你不想要这个解决方案。
  • Add custom run script build phase to A target, which will grab the B headers and copy them to A headers destination. 将自定义运行脚本构建阶段添加到A目标,该目标将获取B头并将其复制到A头目标。

In both cases, you end up with LibA.a which holds compiled sources of A and B, and the headers folder which holds headers from A and B. You can then link your main project agains LibA.a and add the headers folder path to the User Headers Search Path in you main project, and you should be good to go. 在这两种情况下,最终都会得到包含A和B编译源的LibA.a,以及包含A和B标题的headers文件夹。然后,您可以再次链接主项目LibA.a并添加头文件夹路径到您主要项目中的用户标题搜索路径 ,您应该很高兴。

Important 重要

If, in your libraries, you have files that hold only category code in them, make sure to link this library with -force_load , or your category symbols will not be packed properly. 如果您的库中包含仅包含类别代码的文件,请确保使用-force_load链接此库,否则您的类别符号将无法正确打包。

I've done it with libtool, as per this answer . 根据这个答案 ,我已经用libtool完成了它。

To do so, in Xcode 5.0.2, I've added a script to A ( Editor -> Add Build Phase -> Add Run Script Build Phase ) that 为此,在Xcode 5.0.2中,我添加了一个脚本到A( Editor -> Add Build Phase -> Add Run Script Build Phase

  • figures out the architecture for which A is being built: 找出正在构建A的架构:

     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 创建B的精简版本,只构建体系结构

     lipo -thin ${LIPO_ARCH} ${FULLPATH_OF_B} -output ${FULLPATH_OF_THIN_B} 
  • joins A and B into a new A 将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} 
  • removes the temp files 删除临时文件

     rm ${FULLPATH_OF_THIN_A} rm ${FULLPATH_OF_THIN_B} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM