1. 程式人生 > >iOS armv7, armv7s, arm64區別與應用32位、64位配置

iOS armv7, armv7s, arm64區別與應用32位、64位配置

轉載註明出處:https://www.jianshu.com/p/567d3b730608

iOS armv7, armv7s, arm64區別與應用32位、64位配置

歷程

  1. 2015年2月1日不允許不支援arm64的應用的提交;
  2. iOS10釋出後,如果你的應用中使用到了32位的類、庫,沒有相應支援64位機型的庫,則首次啟動後會彈窗式提示:“ xxx可能使iPhone變慢...”;
  3. iOS10.3公測版釋出:封殺32位應用;
  4. 蘋果系統(iOS7/iOS8-iOS9),32位的framework和64位的framework是共存的,所以如果所有的應用都是64位的話,系統就自動不載入32位的framework,這樣可以少佔用資源,另外對執行的速度是有好處的,也就是說,你會感覺手機執行的快了一點。應用在相容64位系統後,記憶體的佔用肯定會變多一點,不過效能也有相應的提升。

下面瞭解下64與32位的區別:

資料型別的變化:

  1. 在32位的年代,使用的是IPL32的規範,到了64位之後,改成了LP64規範。
  2. 資料型別裡面,NSInteger在32位時等同於int,在64位時等同於long,而這個資料結構使用很廣,很多不規範的時候會直接和int替換使用,在32位是毫無問題,但在64位時,這就是隱患了。CGFloat也有同樣的問題
  3. 如果使用了偏移量來訪問struct的項,那麼需要認真仔細的檢查,其餘的還算好,當然如果你用了malloc,那麼也請檢查一下分配的記憶體大小,建議是多使用sizeof來幫助計算。
  4. 方法呼叫上的變化:在64位系統在執行時呼叫函式和32位系統是不同的。主要的區別在於傳遞具有可變引數個數的函式的引數時,我們來看下面的程式碼:
    int fixedFunction(int a, int b);  
    int variadicFunction(int a, ...); 
       int main  
    {  
    int value2 = fixedFunction(5,5);  
    int value1 = variadicFunction(5,5);  
    }
    
    第一個函式是固定傳入2個引數,第二個函式是引數個數不定的,在使用中,也
    傳入了2個引數。在32位系統下,這兩個函式的引數傳遞是非常類似的,在64
    位系統下,這兩者就是截然不同了。
  5. 專案中使用的第三方庫肯定需要支援64位系統,否則還是白搭。大家需要檢查自己使用的第三方的庫,看是否支援64位的版本。蘋果系統中(iOS7/iOS8-iOS9),32位的framework和64位的framework是共存的,所以如果所有的應用都是64位的話,系統就自動不載入32位的framework,這樣可以少佔用資源,另外對執行的速度是有好處的,也就是說,你會感覺手機執行的快了一點。應用在相容64位系統後,記憶體的佔用肯定會變多一點,不過效能也有相應的提升。

增加應用對64位的支援:

一、配置前確認工作:

如果你不能確定庫是否支援了arm64,可以在cmd模式下用file命令來檢查一下庫檔案:

$lipo -info /Users/xxx/NHPushStreamSDK/FFmpeg-iOS/lib/libavcodec.a
//指令說明:lipo -info 靜態庫(動態庫)檔案完整路徑

armv7,armv7s和arm64,i386,x86_64這些都代表什麼?

  • armv7|armv7s|arm64都是ARM處理器的指令集
  • i386|x86_64 是Mac處理器的指令集
     

瞭解ARM

__Arm處理器,因為其低功耗和小尺寸而聞名,幾乎所有的手機處理器都基於arm,其在嵌入式系統中的應用非常廣泛,它的效能在同等功耗產品中也很出色。

Armv6、armv7、armv7s、arm64都是arm處理器的指令集,所有指令集原則上都是向下相容的,如iPhone4S的CPU預設指令集為armv7指令集,但它同時也相容armv6指令集,只是使用armv6指令集時無法充分發揮其效能,即無法使用armv7指令集中的新特性,同理,iPhone5的處理器標配armv7s指令集,同時也支援armv7指令集,只是無法進行相關的效能優化,從而導致程式的執行效率沒那麼高。
 

這些指令集在哪些裝置中有用到呢?

arm64 armv7s armv7
iPhone6s iPhone5 iPhone4
iphone6s plus iPhone5C iPhone4S
iphone6 iPad4(iPad with Retina Display) iPad
iphone6 plus   iPad2
iphone5s   iPad3(The New iPad)
iPad Air   iPad mini
iPad mini2 (iPad mini with Retina Display)   iPod Touch 3G
    iPod Touch4

i386是針對intel通用微處理器32位處理器
x86_64是針對x86架構的64位處理器

模擬器32位處理器測試需要i386架構,
模擬器64位處理器測試需要x86_64架構,
真機32位處理器需要armv7,或者armv7s架構,
真機64位處理器需要arm64架構。

Xcode Build Setting中指令集相關選項釋義

  1. Architectures
    指定工程被編譯成可支援哪些指令集型別,而支援的指令集越多,就會編譯出包含多個指令集程式碼的資料包,對應生成二進位制包就越大,也就是ipa包會變大(Space-separated list of identifiers. Specifies the architectures (ABIs, processor models) to which the binary is targeted. When this build setting specifies more than one architecture, the generated binary may contain object code for each of the specified architectures. )。

  2. Valid Architectures
    限制可能被支援的指令集的範圍,也就是Xcode編譯出來的二進位制包型別最終從這些型別產生,而編譯出哪種指令集的包,將由Architectures與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.)。

  3. Build Active Architecture Only
    指定是否只對當前連線裝置所支援的指令集編譯
    當其值設定為YES,這個屬性設定為yes,是為了debug的時候編譯速度更快,它只編譯當前的architecture版本,而設定為no時,會編譯所有的版本。 所以,一般debug的時候可以選擇設定為yes,release的時候要改為no,以適應不同裝置。


     

二、工程配置,增加64位的支援

note:在Xcode6.1.1及以上 Valid Architectures 設定裡, 預設為 Standard architectures(armv7,arm64),如果你想改的話,自己在other中更改。

  • 使用 standard architectures (including 64-bit)(armv7,arm64) 引數,則打的包裡面有32位、64位兩份程式碼,在iPhone5s( iPhone5s的cpu是64位的 )下,會首選執行64位程式碼包, 其餘的iPhone( 其餘iPhone都是32位的,iPhone5c也是32位 ),只能執行32位包,但是包含兩種架構的程式碼包,只有執行在ios6,ios7系統上。 這也就是說,這種打包方式,對手機幾乎沒要求,但是對系統有要求,即ios6以上。
  • 使用 standard architectures (armv7,armv7s) 引數, 則打的包裡只有32位程式碼, iPhone5s的cpu是64位,但是可以相容32位程式碼,即可以執行32位程式碼。但是這會降低iPhone5s的效能。 其餘的iPhone對32位程式碼包更沒問題, 而32位程式碼包,對系統也幾乎也沒什麼限制。
  • 要發揮iPhone5s及以上的64位機型效能,就要包含64位包,那麼系統最低要求為ios6。 如果要相容ios5以及更低的系統,只能打32位的包,系統都能通用,但是會喪失iPhone5s的效能。
     

Valid Architectures與Architectures指令集交集表:

Valid Architectures設定 Architectures設定 生成二進位制包支援的指令集(取交集)
armv7, armv7s, arm64 armv7s armv7s
armv7, armv7s armv7s,arm64 armv7s
armv7, armv7s, arm64 armv6, armv7s, arm64 armv7s, arm64
armv6, armv7, armv7s armv6, armv7s, arm64 armv6, armv7s
armv7, arm64 ,armv7s armv7, arm64 ,armv7s armv7, arm64 ,armv7s
armv7, armv7s, arm64 armv7,armv7s armv7s, armv7
  1. 比如 Valid Architectures設定的支援arm指令集版本有:armv7/armv7s/arm64,對應的Architectures設定的支援arm指令集版本有:armv7s,這時Xcode只會生成一個armv7s指令集的二進位制包。
  2. xcode預設的設定:
    Architectures : Strandard architectures - $(ARCHS_STANDARD) //相當於arm64 armv7s armv7
    Valid Architectures : arm64 armv7s armv7
  3. 如果你對ipa安裝包大小有要求,可以減少安裝包的指令集的數量,這樣就可以儘可能的減少包的大小。

自定設定

 

系統預設設定

 

製作靜態庫.a是指令集選擇

現在迴歸到正題,如何製作一個“沒有問題”的.a靜態庫,通過以上資訊瞭解到,當我們做App的時候,為了追求高效率,並且減小包的大小,Build Active Architecture Only設定成YES,Architectures按Xcode預設配置就可以,因為arm64向前相容。但製作.a靜態庫就不同了,因為要保證相容性,包括不同iOS裝置以及模擬器執行不出錯,所以結合當前行業情況,要做到最大的相容性。
ValidArchitectures設定為:armv7|armv7s|arm64|i386|x86_64
Architectures設定不變(或根據你需要): armv7|arm64
然後分別選擇iOS裝置和模擬器進行編譯,最後找到相關的.a進行合包:

  • 合併兩個不同構架的庫檔案
$ lipo -create /Users/xxxxxx/lib/libv7.a  /Users/xxxxxx/lib/lib64.a  -output /Users/xxxxxx/lib/lib.a
//指令說明: lipo -create 庫檔案1一完整路徑  庫檔案2完整路徑  -output 輸出的檔名路徑
  • 從某個庫檔案中提起出指定構架的庫檔案
Desktop$ lipo -thin arm64 debugserver -output debugserver2
//指令說明:lipo -thin 對應構架指令 對應檔案 -output 輸出的檔名路徑

使用lipo -create 真機庫.a的路徑 模擬器庫.a的的路徑 -output 合成庫的名字.a ,這樣就製作了一個通用的靜態庫.a。
製作動態、靜態庫詳情可以參考【連結】

 

其它注意點:

  1. 因此如果一些程式中使用的靜態庫不支援armv7s,而你的工程支援armv7s時,就會出現“xxxx does not contain a(n) armv7s slice:xxxxx for architecture armv7s"的編譯錯誤,想要解決這個問題,有兩個方法:
    1. 如果是開源的,能夠找到原始碼,則可以用原始碼重新打一個支援armv7s的libaray, 或者在工程中直接使用原始碼,而不是靜態庫。
    2. 如果不是開源的,要麼就坐等第三方庫的支援,要麼就暫時讓你的工程不支援armv7s。
  2. 此外,模擬器並不執行arm程式碼,軟體會被編譯成x86可以執行的指令。所以生成靜態庫時都是會先生成兩個.a,一個是i386的用於在模擬器執行,另一個是在真實裝置上執行的,然後再用命令將兩個.a合併成一個。
  3. 需要注意的是iOS模擬器沒有執行arm指令集,編譯執行的是x86指令集,所以,只有在iOS裝置上,才會執行裝置對應的arm指令集。
  4. 連線的手機指令集匹配是由高到低(arm64 > armv7s > armv7)依次匹配的。

部份資源連結