modulemap

作者: JerrySi | 来源:发表于2020-11-10 22:10 被阅读0次

    我们在构建Framework或者使用Cocoapods的时候应该都会接触到ModuleMap, 那它到底是个什么?有什么作用?本文基于Xcode 12完成。

    直接使用module.modulemap

    在XCode的build setting内,Packaging内有以下设置module map的选项

    1. Defines Module (DEFINES_MODULE) :如果设置为YES,会认为项目自定义自己的组件,允许项目通过组件的方式引入>2. Module Map File (MODULEMAP_FILE)用来管理LLVM的module map,定义编译器组件结构.如果defines module为YES的时候,如果Module Map File没填,会自动生成。
    Bridging Header缺点:
    1. 把需要的东西全部赤裸裸的摆在了外面容易造成方法重名等问题
    2. 模块间的关系也变得不清不楚的
    3. 如果Swift项目是Framework则无法采用Bridging Header方式
    modulemap好处:
    1. 语义上完整描述了一个框架的作用
    2. 提高编译时可扩展性,只编译或 include 一次。避免头文件多次引用,只解析一次头文件甚至不需要解析(类似预编译头文件)
    3. 减少碎片化,每个 module 只处理一次,环境的变化不会导致不一致
    4. 对工具友好,工具(语言编译器)可以获取更多关于 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完成,主要讲下权限配置:

    image.png
    如果头文件在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

    相关文章

      网友评论

        本文标题:modulemap

        本文链接:https://www.haomeiwen.com/subject/ykkjbktx.html