一、從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-C 和 Swift 都非常好地支持了 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)題。
modules 和 headers 通過(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 便可以方便橋接了。
Swift 的 Modules和 我們上面講的稍微有點(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ī)制,所以Swift 和 C/C++/ObjC交互時(shí),通過(guò)這種 Modules機(jī)制,從二進(jìn)制層面上交互會(huì)非常便捷. 最終進(jìn)行編譯鏈接便能確定互相調(diào)用函數(shù)或?qū)ο蟮南鄬?duì)或絕對(duì)地址和內(nèi)存布局了。