Custom framework module map(.modulemap) and Defines Module(DEFINES_MODULE)
[Module and .modulemap]
Public file structure:
header_1
header_1_1
header_2
Mark all headers which should be exposed for consumer as public(header_1.h, header_2.h, header1_1.h). Headers
public section[About] or you get next error.
//For example in umbrella.h
Include of non-modular header inside framework module '<module_name>'
//or in upper .h file
'PBURLConnectionStub.h' file not found
modular headers
- .h
files which included into .modulemap
:
- .modulemap
umbrella
keyword from umbrella.h
- .modulemap
header
keyword.
Modular headers can import only modular headers
Create an umbrella file
- any .h
file (or autogenerated <product_name>.h
for Framework target). Let's call it Umbrella.h
Add root .h
files into umbrella file
(Umbrella.h
). All imports from this files will be added automatically
//Umbrella.h file
#import "header_1.h"
#import "header_2.h"
Use or create a custom .modulemap
file. You can call the .modulemap
file as you wish, after compiling it will be called module.modulemap
. Also I would not recommend you to call it as module.modulemap
because it can cause unpredictable changes of this file
module.modulemap
which is generated by default:
//the same for Objective-C and Swift framework
framework module SomeModule {
//umbrella header "<umbrella_name>.h"
umbrella header "Umbrella.h"
export *
module * { export * }
}
//unique for Swift framework
module SomeModule.Swift {
header "SomeModule-Swift.h"
requires objc
}
umbrella header
Expose all module headers
recursively. Generates next code
//.modulemap
framework module SomeModule {
//explicitly define all modular header
header "header_1.h"
header "header_2.h"
header "header_1_1.h"
}
//using
import SomeModule
header_1
header_2
header_1_1
multiple modules
.modulemap can contain multiple modules. One of them must have the same name as PRODUCT_MODULE_NAME
//.modulemap
framework module SomeModule
framework module SomeModule2
//using
import SomeModule
import SomeModule2
Submodule module
When you import Outer module you are able to use headers from sub module
//.modulemap
framework module SomeModule {
module Submodule1 {
header "header_1.h"
}
}
//using
import SomeModuleSwift.Submodule1
//or even
import SomeModuleSwift
//availability
header_1
explicit submodule explicit module
You are not able to use module name for submodule header(as you can do by default as shown in previous example)
//.modulemap
framework module SomeModule {
explicit module Submodule1 {
header "header_1.h"
}
}
//using
//import SomeModuleSwift //Error: Cannot find 'header_1' in scope
import SomeModuleSwift.Submodule1
//availability
header_1
Dependencies between explicit submodules export
//.modulemap
framework module SomeModule {
explicit module Submodule1 {
header "header_1.h"
export Submodule2
}
explicit module Submodule2 {
header "header_2.h"
}
}
//using
import SomeModuleObjC.Submodule1
//availability
header_1
header_2
Work with Umbrella
module *
works only with umbrella
, if not you get
Inferred submodules require a module with an umbrella
//.modulemap
framework module SomeModule {
umbrella header "Umbrella.h"
module * { export * }
export *
next code is generated
framework module SomeModule {
//module * { export * }
module header_1 {
header "header_1.h"
export header_2
export header_1_1
}
module header_2 {
header "header_2.h"
export header_1
export header_1_1
}
module header_1_1 {
header "header_1_1.h"
export header_1
export header_2
}
//export *
export header_1
export header_2
export header_1_1
}
//using one of them
import SomeModule.header_1
//or
import SomeModule.header_2
//or
import SomeModule.header_1_1
//or
SomeModule
//availability
header_1
header_2
header_1_1
When some file can not be found next error is occurred
Error: Cannot find 'header_name' in scope
To see the effect use explicit module
module *
- creates submodule for every modular header
inside umbrella
export *
- export all submodule into current sub/module
If we use module * { }
instead of module * { export * }
and import SomeModule.header_1
nothing changed we steal can use all modular headers
when import a single submodule. It is safety because parent module SomeModule
has an access to all submodules
import SomeModule.header_1
header_1
header_2
header_1_1
If we use explicit module * { }
instead of explicit module * { export * }
and import SomeModule.header_1
we get error
import SomeModule.header_1
header_1
//header_2 //Error: Cannot find 'header_2' in scope
Producer:
Defines Module(DEFINES_MODULE)
Build Settings -> Defines Module
If YES - Xcode generates .modulemap. If `MODULEMAP_FILE` is not specified Xcode try to generate it automatically
Module Map File(MODULEMAP_FILE)
Build Settings -> Module Map File
Path to custom `.modulemap` file
The result file `module.modulemap` will be generated and embedded into .framework
Consumer:
Import Paths(SWIFT_INCLUDE_PATHS)
Build Settings -> Import Paths
Path to custom `.modulemap` file
MyFramework_macOS.h
). I then changed the module name to "MyFramework", but I didn't change the header. I fixed the umbrella header issue by renaming the header toMyFramework.h
and updating the exports within it to match the new module name (MyFramework_macOSVersionNumber
toMyFrameworkVersionNumber
, etc.). – Dempster