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++ 使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 開發的過程當中,導入第三方庫(framework/.a)或者下載使用別人的demo會經常會遇到一些關于庫的導入的問...
    lhg_serven閱讀 3,859評論 0 8
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,145評論 1 32
  • Distutils可以用來在Python環境中構建和安裝額外的模塊。新的模塊可以是純Python的,也可以...
    MiracleJQ閱讀 3,158評論 0 1
  • 頭文件引用一般都會隨著項目規模變大而可讀性變差。當大部分精力花費在業務上往往容易忽視頭文件的使用和規范。整理下常見...
    Mr_GaoYu閱讀 12,390評論 5 14
  • 陳總深夜來電、留言:搞掂了。 東海校長清晨留言,白天來電,關心進展。 主管后勤的楊老師多處求索,惦記品質。 津津老...
    尚生耕本閱讀 599評論 0 2