modulemap的使用方法

modulemap的作用
 
modulemap 文件是用來解決 C,Object-C,C++ 代碼在 Swift 項目中集成的問題的。
在 Swift 項目中,如果需要使用 C,Object-C 或者 C++ 代碼,需要將相應的頭文件和源文件導入到項目中,並且需要手動管理它們之間的依賴關係。導致項目結構複雜,管理困難。
爲了解決這個問題,可以使用 modulemap 文件來定義模塊,將 C,Object-C 或者 C++ 代碼組合成一個模塊,然後在 Swift 項目中直接導入該模塊。
文檔中的說明:
As Bridging-Header can help us in App Target and App Test Target, not in static library or dynamic libraries to use the Objective C / C APIs into Swift classes, modulemap can help us here.
 
在Swift項目中使用Objective C / C APIs的方式
Swift使用Objective C / C源碼時:在App工程中OC文件可以通過放置在Bridging-Header文件中讓Swift其他文件引用。
Swift使用Objective C / C的靜態庫,動態庫時:在framework靜態庫,動態庫中OC文件可以通過給framework添加module.modulemap讓Swift通過“import xxx模塊”方式對文件進行引用的。

Module導入方式優點
 
傳統.h文件導入的問題
對於基於C語言而來的其他語言,在導入時,都是導入.h文件,開發者目測很難區分到底導入的是C,C++,還是OC
編譯性能問題
編譯器在預編譯階段碰到import xx.h後,會將xx文件複製,替換到xx.h這個位置。如果一個.h文件中包含了多個其他.h文件,其他.h文件中又相互包含時,則會出現相同的代碼多次被替換。
另外模塊多次導入時,還易出現宏定義替換不完全,錯誤替換的問題(如:當前文件有方法A,它包含的文件中存在了宏定義A,那改如果替換呢)
module導入方式
每個模塊都是一個完全隔離的個體。
當模塊第一次被import時,編譯器會根據modulemap把它裏面的模塊編譯成預編譯模塊(Precompiled Module)pcm文件,並將其在本地緩存,裏面包含了模塊的所有API信息。
當第二個模塊被import導入時,編譯器會直接找這個模塊被編譯後的緩存二進制文件。提升了編譯效率。


Module模塊的使用方式
普通導入方式:
#import <MyModule/MyModule-Swift.h>
模塊導入語法: 
@import MyModule;
Swift導入模塊的方式
import MyModule
使用模塊導入方式就需要framework下包含module.modulemap文件,modulemap指明瞭framework中的頭文件的邏輯結構和如何映射成模塊。
在使用 MyModule 模塊時,就可以直接導入MyModule模塊文件,而不需要手動逐個添加里面的子模塊。

Module模塊語法
//給Swift項目用的
framework module MyModule {
  umbrella header "MyModule.h"

  // headers.h 和 module.modulemap  必須在同一group下,否則需要配置 `header "/??/headers.h"`
  header "headers.h"

  requires objc
  export *  //將子模塊都導出到主模塊
  module * { export * } //將當前目錄下所有的頭文件(包括umbrella header中包含的每個頭文件和其他header "headers.h"頭文件)都導出成子模塊
}

//給OC項目用的,需要支持objc語言環境
module MyModule.Swift {
  header "MyModule-Swift.h"
  requires objc
}
module * { export * } :將當前目錄下所有的頭文件打包成一個模塊,
export * 表示:將其他模塊中的所有頭文件都導出到當前模塊中
export * 和 module * { export * } 同時使用表示將當前目錄下所有的頭文件打包成一個模塊,並將其他模塊中的所有頭文件也導出到當前模塊中。
header 命令:表示將指定的頭文件添加到當前模塊中。
umbrella header 命令:表示將指定的頭文件視爲一個 umbrella header,該頭文件中包含了其他多個頭文件的接口。這個頭文件中包含了其他多個頭文件的接口,因此可以使用 export * 命令將所有接口都導出到當前模塊中。
framework module XXXX 定義了一個 framework 語義的模塊
requires objc 說明:導入模塊的編譯單元要支持OC語言環境
header "headers.h" 說明:將頭文件aa.h映射爲模塊
 
模塊聲明
[framework] module module-id [extern_c] [system] {
    module-member
}
extern_c:表示moduel中的C代碼可以被C++使用,相當於添加了extern 'C'這個聲明。
 
常見Module目錄結構
Name.framework/
    Modules/module.modulemap    framework 的模塊映射
    Headers/                    包含了 framework 中的頭文件
    PrivateHeaders/             包含了 framework 中私有的頭文件
    Frameworks/                 包含嵌入的其它 framework
    Resources/                  包含額外的資源
    Name                        指向共享庫的符號鏈接
 
另外
Xcode創建的APP和庫默認都是支持Moduel導入的,如果不支持可以手動在在 Build Settings 中,Defines Module 的設置爲 YES,進行支持。


參考文章:
https://juejin.cn/post/7139724115157450765
https://zhuanlan.zhihu.com/p/602783297
https://www.jianshu.com/p/ce49d8f32f77


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章