modulemap的使用方法

使用,方法,mod · 浏览次数 : 132

小编点评

**Module 模块** 模块模块是一个包含多个头文件和源文件的目录,用于将多个 C、Object-C 或者 C++ 代码组合成一个模块。 **作用** * 改善项目结构 * 减少手动依赖关系 * 提升编译效率 **使用方法** 1. 在 Swift 项目中创建一个新的模块目录。 2. 在该目录中创建包含头文件和源文件的目录。 3. 在 module.modulemap 文件中定义模块的结构。 4. 在 Swift 项目中使用 `#import` 导入模块。 **示例** **module.modulemap** ``` module MyModule { umbrella header "MyModule.h" //其他模块头文件和源文件 } ``` **使用模块** ```swift //导入模块 import MyModule //使用模块成员 let moduleMember = MyModule.moduleMember ``` **优点** * 编译效率提高 * 减少代码维护 * 提升代码可维护性 **注意** * 模块需要在 Xcode 的 Build Settings 中设置支持模块导入。 * 模块的 header 文件需要在项目中包含所有涉及的头文件。 * 模块的源文件需要在模块的目录中。

正文

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


与modulemap的使用方法相似的内容: