Xcode中Architecturs配置及问题

Xcode 5.1升级后因ARM64和CocoaPods的原因,痛了一天,终于解决了问题,同时也记录下这次的学习成果。

ARMv6/ ARMv7 / ARMv7s & ARM64

在了解Architecture之前,先来认识这几个名字:ARMv7, ARMv7s, ARM64是ARM CPU的不同指令集,就像CPU内潜入的软件版本。其在iPhone处理器型号为A4, A8…

芯片对应指令集和机型 图版

ARM 芯片 ARM 指令集 iPhone 机型
ARM 1176JZ ARMv6 iPhone, iPhone 3G
A3 ARMv7 iPhone 3GS
A4 ARMv7 iPhone 4
A5 ARMv7 iPhone 4S
A6 ARMv7s iPhone 5, iPhone 5C
A7 ARM64 iPhone 5S
A8 ARM64 iPhone 6, iPhone 6s



指令是向下兼容的,如iPhone5s A7支持ARM64, 但它同时兼容ARMv7s,只是如果程序使用ARMv7s指令进行编译,可能无法充分发挥它的64位特性。

Architectures

Architecture是指该程序编译时的目标设备(就是ARM指令集,如ARMv7,ARMv7s, ARM64…),编译期会为不同的指令集(设备)生成专有的安装包。不同设备上会执行该设备对应的指令集,如iPhone5S会优执行ARM64(如果有)

在Target的Architectures设置项内,可以手工分别添加以上的这几个值,从而新增或删除特性指令集。为了更方便的使用指令组合,Xcode中定义了一些变量,然而这些变量在不同的Xcode版本下又有着不同的值。

  • $(ARCHS_STANDARD)
    这个为Xcode中Architecture的默认值,
    • Xcode 5中,该值为ARMv7, ARMv7s
    • Xcode 5.1时,强制加入了对ARM64的编译,于是该值为ARMv7, ARMv7s, ARM64
    • Xcode 6后,更新为 ARMv7, ARM64
  • $(ARCHS_STANDARD_32_BIT)
    • Xcode 5和5.1中都为ARMv7, ARMv7s
    • 旧一点的版本中应该对应的就只有ARMv7
  • $(ARCHS_STANDARD_INCLUDING_64_BIT)
    • Xcode 5和5.1中都为ARMv7, ARMv7s, ARM64
    • Xcode 6后,强制ARM64,所以这个项几乎不用了。

如果程序中设置的Architecture为ARMv7,当使用iPhone 5真机debug时,就会出现“xxxx does not contain a(n) ARMv7s slice:xxxxx for architecture ARMv7s”的编译错误,想要解决这个问题,在Architecture中加上ARMv7s即可。这种情况更常见于第三方开源库上。

Valid Architectures

官方文档说明:

Space-separated list of identifiers. Specifies the architectures for which the binary may be built. During the build, this list is intersected with the value of ARCHS build setting; the resulting list specifies the architectures the binary can run on. If the resulting architecture list is empty, the target generates no binary.

该编译项指定可能支持的指令集,该列表和Architectures列表的交集,将是Xcode最终生成二进制包所支持的指令集。

比如,你的Valid Architectures设置的支持ARM指令集版本有:ARMv7/ARMv7s/ARM64,对应的Architectures设置的支持ARM指令集版本有:ARMv7s,这时Xcode只会生成一个ARMv7s指令集的二进制包。

设为NO后,编译出的.a文件,就包含所设置的多个指令集了:

1
2
$ lipo -info libPods.a
Architectures in the fat file: libPods.a are: ARMv7 ARM64

Active Architecture

Architectures下有一个Bool型的配置项,叫作Build Active Architecture Only

  • YES,表示会针对目标设备进行编译,只会编译对应指令集的包,此时的安装包比较小,但只针对于该指令集设备;
  • NO,编译器会整合两个指令集到一起,生成的安装包比较大,但是能在不同的设备上安装运行。

一般都是Debug时 “Build Active Architecture Only” 选择YES,用当前的架构看代码逻辑是否有问题;而在Release时选择NO,来适配不同的设备。

此外,模拟器并不运行ARM代码,软件会被编译成x86可以运行的指令。所以生成静态库时都是会先生成两个.a,一个是i386的用于在模拟器运行,另一个是在真实设备上运行的,然后再用命令将两个.a进行合并成。

Policy

Apple在2015年2月起,强制所 App必须支持ARM64,否则会收到 Missing 64-bit support 的Error。在Xcode6中,将Architectures修改为Standard architectures,Valid Architectures支持ARMv7 ARMv7s ARM64

Xcode 6中默认不再生成ARMv7s,也就是iPhone 5和5C将以旧的ARMv7的指令集来运行。会减小包的大小,运行时也不会产生问题。Xcode 6 drops ARMv7s cn

Xcode 5.1,增加上了对ARM64的支持,但很多很三方库没有进行更新,就导致会产生编译错误。这个解决办法就是删掉Architecture中ARM64,然后分别加上ARMv7, ARMv7s,或者使用$(ARCHS_STANDARD_32_BIT)。clean后重新build就可以了。等第三方库都支持ARM64后,再把该值改回来即可。

开启ARM64支持后,就不能对iOS 5.1.1之前版本进行开发,要强制将deployment target 设置为5.1.1或之后。

Xcode 4.5中移除了对ARM6的支持,如果想开发对ARM6支持的应用,就要保持用老的Xcode了。

查看.a库支持的指令集

可以通过该lipo命令查看.a库所支持的指令集。More

1
2
3
4
5
6
~/Library/Developer/Xcode/DerivedData/xxxx/Build/Products/Debug-iphoneos
$ lipo -info *.a
Architectures in the fat file: libPods-AFNetworking.a are: ARMv7 ARMv7s
Architectures in the fat file: libPods.a are: ARMv7 ARMv7s

CocoaPods与Architecture

CocoaPods中所生成Pod项目时,会根据当前Project中的配置来为Pod包的Target Architecture配置。结束后,会有下面的文字提示。

[!] Found multiple values (‘ARMv7’, ‘ARMv7s’) for the architectures (‘ARCHS’) build setting for the ‘Pods’ target definition. Using the first.

也就是所如果有多个配置的话,它只会统一的给所有的包target设置为第一个(举例,在Origin Projectg下配置的Architecture为ARMv7 & ARMv7s 两个项时,pod生成的项目的所有target中都只默认添加ARMv7一个项)。

对于Xcode 5.1中64位的Error,用$(ARCHS_STANDARD_32_BIT)代替系统默认的$(ARCHS_STANDARD)可以避免这样的问题。

也可以在Podfile中加入以下代码来设置Pod项目。

1
2
3
4
5
6
7
8
# Remove 64-bit build architecture from Pods targets
post_install do |installer|
installer.project.targets.each do |target|
target.build_configurations.each do |configuration|
target.build_settings(configuration.name)['ARCHS'] = '$(ARCHS_STANDARD_32_BIT)'
end
end
end

Automatically Select Architecture

REF::