转:http://blog.csdn.net/jason20ming/article/details/7487139
今天看了一天关于Static Library以及Static Frame的相关资料,先记下来,以免忘了。
跟大多数操作系统相同,Mac OS X及iOS上均支持静态链接库和动态链接库(这样说可能有点不恰当,但是都是这个意思附近的了)
在Xcode 4.3中如果是新建一个Mac OS X的项目,可以看见“Framework & Library”内有各种各样的Library及Framework的模板,当然,这些都可以是静态链接或者动态链接的。
但是如果新建的是iOS的项目,在“Framework & Library”内的模板就少得可怜,就只有一个“Cocoa Touch Static Library”,顾名思义就是一个静态链接库模板。
静态链接库用起来的颇为麻烦,libxml2就是一个例子,首先要加入linker内让linker找到符号,然后还需要配置Header让compiler可以找到这些符号的定义。基于这种不人性化操作,苹果在自己的平台上推出了一种新的引用方式,那就是Framework。
Framework其实就是将Header及Library打包在一起方便使用,在苹果的官方文档,Framework还可以嵌套打包,其称为Umbrella Framework,不过其不建议普通用户这样做而已。我们平常使用的QuartzCore、UIKit、CoreFoundation等均打包为Framework。
可惜的是,因为没有模板,所以不能简单地创建一个Framework,但是一个开源的模板项目可以帮到我们:iOS-Universal-Framework。
这个模板分开两块:Fake Static Framework 和 Real Static Framework,安装及使用方法在github上的项目有详细教程(其实很简单,运行一个脚本就OK)。
看到名字开始会很疑惑,这东西还能有Fake和Real的?
原来,苹果出于某种原因的考虑,在Xcode上禁用了iOS项目引入非官方Framework的功能,所以这里的Framework分成了两种。
Fake的是通过一个bundle模拟Framework,这个不需要对Xcode进行任何改动,只需要添加一个项目模板即可,但是使用这个模板并且开启ARC时候会出现问题,这个后面会说道。
Real的生成出来的product就是一个真真正正的Framework,但是由于Xcode不支持在iOS上使用自定义Framework,所以需要向Xcode内加入两个xcspec文件以启用支持。
将两个模板都安装完成后,可以看见iOS中的“Framework & Library”多出了两个Framework的模板。看看名字,里面均有一个“Static”,这表示生成的Framework都是静态的,因为苹果是禁止开发者向iOS内添加动态库的,这样就可以保证所有应用的依赖均来源于苹果内部,降低开发难度也可以保证应用不会因为缺少依赖库而Crash。所以,无论Static Framework或者Static Library,最终所有的符号均会被内联到程序中,跟直接在项目内编写代码是一样的。
既然生成的二进制都是一样的,为什么还要提取一个库出来呢?虽然iOS上二进制是不可共享的,但是代码是可以共享的,可以将经常使用的组件提出成一个公共库,再供给程序使用,这样可以有效减低程序内的代码量。(说离题了。。。)
下面说说 Static Library、Fake Static Framework、Real Static Framework 使用需要注意的事项以及其优劣,特别是在Deployment Target 在 iOS 5.0以下时候容易出现的问题。
Static Library:
简单的静态链接库,其使用Libtool生成静态链接库文件,不会因为开启iOS 4.0以下版本的ARC而强制将libarclite链接至静态链接库;但是,其使用较为麻烦,不方便发布。
Static Library在生成的静态库时候会加上一个参数-arch_only armv7(使用模拟器时是:-arch_only i386),即使这个库只可用于模拟器或者真实设备,现在貌似暂时没有办法设置其同时支持armv7和i386。
Fake Static Framework:
这个不是一个真正的Framework,实际类型是Core Foundation Bundle,所以叫做Fake Framework。
因为其生成的目标是CFBundle,所以Xcode使用Ld命令生成目标静态库,这样在工程内的Link Binary with Libraries不能有系统的Framework和Library,一旦引入系统的库,Ld命令会将引入库的所有符号内联到当前工程中,当其它工程引用这个静态库的时候就会出现Duplicate symbol define的错误!
基于这个原因,在Deployment Target低于5.0而且开启ARC的时候可能会出现Duplicate symbol define: objc_retainObject()的错误,出现这个错误的原因如下:
1. Fake Static Framework使用Ld命令生成库,而不是使用Libtool生成库,当Framework工程的Deployment Target低于5.0而且开启ARC的时候编译器会向程序写入内存管理方面的代码,而Ld命令会将libarclite库内对应的函数(如objc_retainObject())的定义加入到当前的静态库中。
2. 在引用Framework的工程中,如果Deployment Target低于5.0而且开启ARC,同1道理,Ld命令会向项目内引入libarclite库并将定义加入当前项目,但是由于在引入的Framework中已经包含有相关符号,所以会出现Duplicate symbol define。
解决方案如下:在Fake Static Framework生成的时候将Deployment Target改为5.0或更高,在编写代码的时候将其改回对应版本(因为5.0以下的不支持weak关键字,改回低版本有利于IDE的提示);或者将引用Framework的工程的Deployment Target改为5.0或更高,但是这样则会失去对低版本的支持。
Real Static Framework:
这个是一个真正的Framework,其生成的文件实际类型就是Framework。其内部包含的静态库是由Libtool生成的,所以不存在ARC的问题,而且可以在Link Binary with Libraries中加入系统的Framework,其只会在生成的库中加入对应Framework或Library的引用,而不会将定义也加入其中。
但是,由于苹果的限制,Xcode不支持Real Static Framework直接引用,需要加入两个xcspec文件才可以使用,但是使用这个方式的Framework会将不会存在上述两个静态库的n问题,是现时来说最方便的库。