iOS 中的import

一、從iOS中#import 、@import、#include說(shuō)起

  • #include就是將目標(biāo).h文件中的內(nèi)容拷貝到當(dāng)前文件中,并替換掉這句#include。這樣做可能會(huì)因?yàn)橹貜?fù)引用帶來(lái)編譯錯(cuò)誤,比如B和C都引用了A,D又同時(shí)引用了B和C,這樣D引用了A兩次。

  • 為了解決這個(gè)問(wèn)題,OC加入了#import,使得頭文件只被引用一次。其原理是通過(guò)下面方式來(lái)實(shí)現(xiàn)的。

#ifndef xxx
#define xxx
  • 問(wèn)題來(lái)了:當(dāng)引用關(guān)系很復(fù)雜時(shí),編譯引用所占的代碼量就會(huì)大幅上升,因?yàn)楸灰玫念^文件在引用的地方都被拷貝了一次。

  • 為了解決這個(gè)問(wèn)題,C語(yǔ)言引入了預(yù)編譯頭文件(PreCompiled Header

  • 問(wèn)題又來(lái)了。。。理論上說(shuō),想要提高編譯速度,可以把所有頭文件引用都放到pch文件中。但是這樣面臨的問(wèn)題是在工程中隨處都能訪問(wèn)可能不該訪問(wèn)的東西,這樣的結(jié)果顯然不是很理想的。

  • 于是蘋(píng)果創(chuàng)造了Modules來(lái)解決這個(gè)問(wèn)題,而使用的方式就是@import
    Modules會(huì)在實(shí)際編譯時(shí)加入了一個(gè)用來(lái)存放已編譯添加過(guò)的Modules列表。首先在Modules列表內(nèi)查找,如果在編譯的文件中引用到某個(gè)Module,則直接使用;如果沒(méi)有,則把引用的頭文件編譯后加入到這個(gè)表中。這樣被引用到的Modules只會(huì)被編譯一次,也避免了在工程中隨處都能訪問(wèn)可能不該訪問(wèn)的東西。
    #import 、@import、#include的區(qū)別

二、import""還是import<>

  • import""雙引號(hào)用于本地的頭文件,需要指定相對(duì)路徑;
  • import<>尖括號(hào)是全局的引用,其路徑由編譯器提供,如引用系統(tǒng)的庫(kù)。
    http://www.itdecent.cn/p/3fafcb0dc37f

三、Modules是什么?

@import WebKit.WebKitLegacy; //in Objective-C
import WebKit.WebKitLegacy   //in Swift

可以看到Objective-CSwift 都非常好地支持了 Modules import,你可以非常清晰地引入 API 聲明。

當(dāng)你使用Modules 引入時(shí),預(yù)處理器并不會(huì)像 “#include”那樣使用 M*N 量級(jí)的重復(fù)拷貝粘貼。而是巧妙地通過(guò)一個(gè)列表來(lái)存放已經(jīng)編譯處理過(guò)的 Modules 列表,而聲明的引入會(huì)首先在這個(gè)表內(nèi)查找,如果沒(méi)有找到會(huì)去編譯添加進(jìn)來(lái)。所以 Modules 的引入只會(huì)被處理一次,可以解決前面提到的引用泛濫問(wèn)題。

modulesheaders 通過(guò)一個(gè) map 來(lái)進(jìn)行一種關(guān)系映射,這個(gè) map 文件就叫做 modulemap. 這個(gè)文件從語(yǔ)義上描述了你的函數(shù)庫(kù)物理結(jié)構(gòu)。

那么實(shí)際在編譯過(guò)程中Modules 到底代表著什么呢?其實(shí) Modules 是一種預(yù)編譯技術(shù),當(dāng)一個(gè)模塊被導(dǎo)入時(shí),編譯器在處理它時(shí)會(huì)生成一個(gè)新的子進(jìn)程(非 fork),這個(gè)子進(jìn)程擁有干凈的context來(lái)編譯這個(gè) module(這樣就不會(huì)產(chǎn)生命名空間沖突等干擾),然后 module 的編譯結(jié)果會(huì)被持久化到這個(gè)模塊的二進(jìn)制緩存中,那么下次引用編譯的時(shí)候就會(huì)非??臁?modules由頭文件映射而成,所以當(dāng)這些頭文件改動(dòng)時(shí),module 還會(huì)自動(dòng)重新編譯刷新緩存,不需要我們主動(dòng)干預(yù)。

四、Modules 和 Swift

如果僅僅只是為了提升頭文件預(yù)處理速度還沒(méi)必要這么大費(fèi)周章地搞 Modules 這個(gè)東西,我的猜測(cè)是 Swift 這個(gè)項(xiàng)目開(kāi)始設(shè)計(jì)時(shí)便考慮了和 C/C++/ObjC 的交互問(wèn)題,使用 Modules 便可以方便橋接了。

SwiftModules和 我們上面講的稍微有點(diǎn)不一樣,它并不存在 modulemap 這個(gè)東西,而是直接編譯生成的一個(gè).swiftmodule文件。Apple 官方對(duì)于 Swift 的模塊系統(tǒng)也有一點(diǎn)解釋,就是說(shuō) Xcode 中的每一個(gè) target 都對(duì)應(yīng)著一個(gè) Swift Module。

我們前面提到 modulemap最終預(yù)編譯后產(chǎn)生的是一個(gè)二進(jìn)制的緩存,Swift Modules 也一樣,.swiftmodule 文件里面存放的就是一些序列化后的 AST (可能還有些 SIL)。因?yàn)?Swift 并沒(méi)有頭文件引入機(jī)制,所以SwiftC/C++/ObjC交互時(shí),通過(guò)這種 Modules機(jī)制,從二進(jìn)制層面上交互會(huì)非常便捷. 最終進(jìn)行編譯鏈接便能確定互相調(diào)用函數(shù)或?qū)ο蟮南鄬?duì)或絕對(duì)地址和內(nèi)存布局了。

LLVM的 Modules

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容