Swift 关于 module.modulemap 使用

2020-7-12 更新:为什么在 swift framework 中使用了自定义module.modulemap, build 出来的 framework 会报 Missing required module
@Ulquiorra_04 的提醒,开始测试并写了这篇文章《Swift Framework 自定义 Module》,介绍了如何实现在 swift framework 中使用自定义 module。

Swift 中最简单最优雅的引用 occ 方式。
首先建一个 group, 就是你要 import 的,如图文件名叫 OtherFile,所以在哪里要使用这个module的文件,就直接 import OtherFile

// like this
import UIKit
import OtherFile

class ViewController: UIViewController {
    override func viewDidLoad() {
        ...
    }
}

module.modulemap 文件

// module.modulemap 文件
module OtherFile {
    // headers.h 和 module.modulemap  必须在同一group下,否则需要配置 `header "/??/headers.h"`
    header "headers.h"
    export *
}

headers.h文件

//  headers.h文件
// 在 headers.h 中引用需要暴露的文件

// for c++
#include "file.h"
// for c
#include "file_c.h"

//#ifdef __OBJC__
// for oc
#import "Test.h"
#import "Test2.h"
//#endif

注意, 同时存在 occ 文件 需要分开处理, 需要把 oc 文件单独加上 requires objc, 所以建议使用 umbrella, 并且把 coc 分开多个 module.
requires 列表

module OtherFile {
    // c file
    header "file.h"
    header "filea.h"
    header "filebbb.h"
    
    export *
    umbrella "Subs"
    module * { export * }
    
    // oc file
    module Test {
        requires objc
        header "Test3.h"
        header "Test2.h"
        header "Test.h"
        export *
        
        export *
        umbrella "Subs/OCSubs" // 单独把 Subs 中的 oc 文件, 单独列出来, 否则会编译失败
        module * { export * }
    }
}

The std module can be extended to also include C++ and C++11 headers using a requires-declaration:

module std {
   // C standard library...

   module vector {
     requires cplusplus
     header "vector"
   }

   module type_traits {
     requires cplusplus11
     header "type_traits"
   }
 }

同时需要配置如图


import paths 通过语义就是 可以 import 的,即 import OtherFile
可以直接拖拽 group 直接到目录下, 需要配置 $SRCROOT/, 绝对路径。
之后就可以在这个文件夹下放你随便的 coc 文件,舒服的使用。

umbrella.h文件
什么是umbrella header?

倒入子目录.h

umbrella + 目录, 可以递归导出子目录下的所有.h

module OtherFile {
    header "headers.h"
    export *
    // 倒入 Subs 文件夹下所有的.h
    umbrella "Subs"
    module * { export * }
}

代码实例
三个方法分别对应不同目录下的文件

run()
subRun()
subSubRun()

// 打印
// run
// sub run
// sub sub run

所以, 我们可以通过 umbrella 更简单的实现导出, 只需要把文件都放到子目录下, 并导出就可以了, 同时支持 coc.

module * { export * } 和 export * 的区别

如下两个 modules 分别用 module * { export * }export * 来实现的

module OtherFile {
    // c file
    module CFile {
        header "file.h"
        header "filea.h"
        header "filebbb.h"
        export *
    }
    
    umbrella "Subs"
    module * { export * }
    
    // oc file
    module Test {
        requires objc
        header "Test3.h"
        header "Test2.h"
        header "Test.h"
        export *
        
        umbrella "Subs/OCSubs"
        module * { export * }
    }
}

上面 OtherFile module 编译产生:

import OtherFile.CFile
import OtherFile.Sub
import OtherFile.SubSubs
import OtherFile.Test

上面的 module 使用 module * { export * } 产生了四个子 module

module OtherFile {
    // c file
    module CFile {
        header "file.h"
        header "filea.h"
        header "filebbb.h"
        export *
    }
    
    // subs 文件夹
    umbrella "Subs"
    export * 
    
    // oc file
    module Test {
        requires objc
        header "Test3.h"
        header "Test2.h"
        header "Test.h"
        export *
        
        umbrella "Subs/OCSubs"
        module * { export * }
    }
}

上面 OtherFile module 编译产生:

import OtherFile.CFile
import OtherFile.Test

//
//  Subsubs.h
//  ModuleTest
//
//  Created by Yan Hu on 2019/10/14.
//  Copyright © 2019 yan. All rights reserved.
//

public func subSubRun()
//
//  Sub.h
//  ModuleTest
//
//  Created by Yan Hu on 2019/10/14.
//  Copyright © 2019 yan. All rights reserved.
//

public func subRun()

上面的 module 使用 export * 产生了2个子 module 和两个方法, 这两个方法分别属于 Subsubs.hSub.h

目录关系

你会发现, 使用

umbrella "Subs"
module * { export * }

进行导出, 把 subs 文件夹下所有的 .h 文件单独生成了一个 subModule (子 module)
使用

umbrella "Subs"
export *

进行导出, 会直接把所有 .h 中的方法, 直接导入到当前的 module 中, 所以在使用的时候, 可以跟进需求来使用.

参数 system 和 的介绍
// 参数使用
module OtherFile [system] [extern_c] {

}

The system attribute specifies that the module is a system module. When a system module is rebuilt, all of the module’s headers will be considered system headers, which suppresses warnings. This is equivalent to placing #pragma GCC system_header in each of the module’s headers. The form of attributes is described in the section Attributes, below.

The extern_c attribute specifies that the module contains C code that can be used from within C++. When such a module is built for use in C++ code, all of the module’s headers will be treated as if they were contained within an implicit extern "C" block. An import for a module with this attribute can appear within an extern "C" block. No other restrictions are lifted, however: the module currently cannot be imported within an extern "C" block in a namespace.

关于 import 的使用 sub modules

以上面产生四个sub modules 为例, 当我在代码中直接 import OtherFile.Test, 按照正常逻辑是, 只导入了 Test 这个子模块, 所以我可以使用这个子模块的代码, 但不是这样的, 即使你只导入了这个子模块, 其他的子模块的代码依旧可以访问到, 这个可能是 swift 5.0 说的Modules 不稳定的地方?

那么怎么实现只导入部分代码来进行使用?
可以通过 import class OtherFile.Test.Test 来导入 Test 这个类,
同时这里还可以简写为 import class OtherFile.Test, 这样会从模块 OtherFile 和它的子模块中需找到 Test 这个类, 并且导入.
当你使用import class OtherFile.Test.TestSubSub 来导入 TestSubSub 这个类的时候, 发现竟然依然可以导入, TestSubSub类明明在 TestSubSub 模块下, 但OtherFile.Test.TestSubSub依旧可以导入, 这也是 swift 5.0 说的Modules 不稳定的地方?

反正就是可以导入单个 typealias, struct, class, enum, protocol, var, func, 导入的方式只需要替换上面 import class OtherFile.Test.Test 中的 class 就可以了.

使用就是:
import struct SomeModule.WantToImportStruct
import class SomeModule.WantToImportClass
import enum SomeModule.WantToImportEnum
...

源码: 文中源码, 包含 c++ 使用方法
reference: https://clang.llvm.org/docs/Modules.html#includes-as-imports
reference: sub modules 的使用
reference: c++ 使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 开发的过程当中,导入第三方库(framework/.a)或者下载使用别人的demo会经常会遇到一些关于库的导入的问...
    lhg_serven阅读 3,773评论 0 8
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,065评论 1 32
  • Distutils可以用来在Python环境中构建和安装额外的模块。新的模块可以是纯Python的,也可以...
    MiracleJQ阅读 3,028评论 0 1
  • 头文件引用一般都会随着项目规模变大而可读性变差。当大部分精力花费在业务上往往容易忽视头文件的使用和规范。整理下常见...
    Mr_GaoYu阅读 12,237评论 5 14
  • 陈总深夜来电、留言:搞掂了。 东海校长清晨留言,白天来电,关心进展。 主管后勤的杨老师多处求索,惦记品质。 津津老...
    尚生耕本阅读 569评论 0 2