2020-7-12 更新:為什么在 swift framework 中使用了自定義module.modulemap, build 出來的 framework 會報(bào) Missing required module
受 @Ulquiorra_04 的提醒硝桩,開始測試并寫了這篇文章《Swift Framework 自定義 Module》,介紹了如何實(shí)現(xiàn)在 swift framework 中使用自定義 module匣缘。
Swift
中最簡單最優(yōu)雅的引用 oc
和 c
方式澄成。
首先建一個(gè) group
, 就是你要 import
的亭敢,如圖文件名叫 OtherFile
滚婉,所以在哪里要使用這個(gè)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
注意, 同時(shí)存在 oc
和 c
文件 需要分開處理, 需要把 oc 文件單獨(dú)加上 requires objc
, 所以建議使用 umbrella
, 并且把 c
和 oc
分開多個(gè) 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" // 單獨(dú)把 Subs 中的 oc 文件, 單獨(dú)列出來, 否則會編譯失敗
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"
}
}
同時(shí)需要配置如圖
import paths
通過語義就是 可以 import
的远剩,即 import OtherFile
。可以直接拖拽
group
直接到目錄下, 需要配置 $SRCROOT/
, 絕對路徑骇窍。之后就可以在這個(gè)文件夾下放你隨便的
c
瓜晤, oc
文件,舒服的使用腹纳。
umbrella.h文件
什么是umbrella header?
umbrella + 目錄
, 可以遞歸導(dǎo)出子目錄下的所有.h
module OtherFile {
header "headers.h"
export *
// 倒入 Subs 文件夾下所有的.h
umbrella "Subs"
module * { export * }
}
代碼實(shí)例
三個(gè)方法分別對應(yīng)不同目錄下的文件
run()
subRun()
subSubRun()
// 打印
// run
// sub run
// sub sub run
所以, 我們可以通過 umbrella
更簡單的實(shí)現(xiàn)導(dǎo)出, 只需要把文件都放到子目錄下, 并導(dǎo)出就可以了, 同時(shí)支持 c
和 oc
.
module * { export * } 和 export * 的區(qū)別
如下兩個(gè) modules
分別用 module * { export * }
和 export *
來實(shí)現(xiàn)的
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
編譯產(chǎn)生:
import OtherFile.CFile
import OtherFile.Sub
import OtherFile.SubSubs
import OtherFile.Test
上面的 module
使用 module * { export * }
產(chǎn)生了四個(gè)子 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
編譯產(chǎn)生:
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 *
產(chǎn)生了2個(gè)子 module
和兩個(gè)方法, 這兩個(gè)方法分別屬于 Subsubs.h
和 Sub.h
你會發(fā)現(xiàn), 使用
umbrella "Subs"
module * { export * }
進(jìn)行導(dǎo)出, 把 subs 文件夾下所有的 .h
文件單獨(dú)生成了一個(gè) subModule
(子 module)
使用
umbrella "Subs"
export *
進(jìn)行導(dǎo)出, 會直接把所有 .h
中的方法, 直接導(dǎo)入到當(dāng)前的 module
中, 所以在使用的時(shí)候, 可以跟進(jìn)需求來使用.
參數(shù) system 和 的介紹
// 參數(shù)使用
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.
關(guān)于 import 的使用 sub modules
以上面產(chǎn)生四個(gè)sub modules
為例, 當(dāng)我在代碼中直接 import OtherFile.Test
, 按照正常邏輯是, 只導(dǎo)入了 Test
這個(gè)子模塊, 所以我可以使用這個(gè)子模塊的代碼, 但不是這樣的, 即使你只導(dǎo)入了這個(gè)子模塊, 其他的子模塊的代碼依舊可以訪問到, 這個(gè)可能是 swift 5.0
說的Modules
不穩(wěn)定的地方?
那么怎么實(shí)現(xiàn)只導(dǎo)入部分代碼來進(jìn)行使用?
可以通過 import class OtherFile.Test.Test
來導(dǎo)入 Test 這個(gè)類,
同時(shí)這里還可以簡寫為 import class OtherFile.Test
, 這樣會從模塊 OtherFile
和它的子模塊中需找到 Test
這個(gè)類, 并且導(dǎo)入.
當(dāng)你使用import class OtherFile.Test.TestSubSub
來導(dǎo)入 TestSubSub
這個(gè)類的時(shí)候, 發(fā)現(xiàn)竟然依然可以導(dǎo)入, TestSubSub
類明明在 TestSubSub
模塊下, 但OtherFile.Test.TestSubSub
依舊可以導(dǎo)入, 這也是 swift 5.0
說的Modules
不穩(wěn)定的地方?
反正就是可以導(dǎo)入單個(gè) typealias, struct, class, enum, protocol, var, func
, 導(dǎo)入的方式只需要替換上面 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++ 使用