我们在构建Framework或者使用Cocoapods的时候应该都会接触到ModuleMap, 那它到底是个什么?有什么作用?本文基于Xcode 12完成。
直接使用module.modulemap
在XCode的build setting内,Packaging内有以下设置module map的选项
- Defines Module (DEFINES_MODULE) :如果设置为YES,会认为项目自定义自己的组件,允许项目通过组件的方式引入>2. Module Map File (MODULEMAP_FILE)用来管理LLVM的module map,定义编译器组件结构.如果defines module为YES的时候,如果Module Map File没填,会自动生成。
Bridging Header缺点:
- 把需要的东西全部赤裸裸的摆在了外面容易造成方法重名等问题
- 模块间的关系也变得不清不楚的
- 如果Swift项目是Framework则无法采用Bridging Header方式
modulemap好处:
- 语义上完整描述了一个框架的作用
- 提高编译时可扩展性,只编译或 include 一次。避免头文件多次引用,只解析一次头文件甚至不需要解析(类似预编译头文件)
- 减少碎片化,每个 module 只处理一次,环境的变化不会导致不一致
- 对工具友好,工具(语言编译器)可以获取更多关于 module 的信息,比如链接库,比如语言是 C++ 还是 C等等
modulemap编译
module中C和OC要分开编译, C++可以和C一起编译, C++也可以和OC一起编译。
当OC 和C 一起需要添加requires objc
module OCTest {
requires objc
header "OCTest.h"
export *
umbrella "Subs/OCSubs" // 单独把 Subs 中的 OC 文件, 单独列出来, 否则会编译失败
module * { export * }
}
由于Swift不能直接调用C++代码, 所以一般会导出C和OC文件。
Swift中不能直接调用C++代码,但是可以调用c代码, 通过void*生成c++对象, 通过c来调用C++
umbrella作用
https://stackoverflow.com/questions/31238761/what-is-an-umbrella-header
它是框架的“主”头文件,没有的时候需要这样写:
#import <UIKit/UIViewController.h>
#import <UIKit/UILabel.h>
#import <UIKit/UIButton.h>
#import <UIKit/UIDatePicker.h>
现在只需要#import <UIKit/UIKit.h>
, 另外umbrella + 目录, 可以递归导出子目录下的所有.h。
module * { export * } 和 export * 的区别
umbrella "Subs"
export *
import OtherFile.CTest
import OtherFile.OCTest
//
// CPlusSubs.hpp
// ModulemapDemo
//
// Created by SRS on 2020/11/2.
//
public var CPLUSSUBS: Int32 { get }
对比:
umbrella "Subs"
module * { export * }
import OtherFile.CPlusSubs
import OtherFile.CPlusSubs2
import OtherFile.CTest
import OtherFile.OCTest
可以发现module * { export * }
会直接把所有 .h 中的方法, 直接导入到当前的 module 中。 另外只有umbrella才可以使用module * { export * }
。
system和extern_c
system属性指定模块是系统模块。当重建系统的所有模块的头时,将认为该模块的所有标头被取消。这相当于将#pragma GCC system_header
放在每个模块的头中。属性的形式在下面的属性一节中描述。
extern_c属性指定模块包含可以在C ++中使用的C代码。 当构建此类模块供C ++代码使用时,该模块的所有标头都将被视为包含在隐式extern“ C”块中。
Swift Freamwork中使用module.modulemap
操作步骤就不详细写了,基于https://www.jianshu.com/p/b4f88651f069完成,主要讲下权限配置:
如果头文件在
Public
对应Freamwork中Headers;Private
对应Freamwork中PrivateHeaders;Project
里面 没有在Freamwork中看见,理论可以通过这个配置隐藏头文件。
注意framework module 中无法使用 umbrella
本实例Demo
参考:
https://zhuanlan.zhihu.com/p/51194169
https://www.jianshu.com/p/12a9565241e8
https://www.jianshu.com/p/ce49d8f32f77
https://www.jianshu.com/p/b4f88651f069
https://clang.llvm.org/docs/Modules.html#requires-declaration