What helped me get my head around the export
and module
keywords in modulemap
files was to play around with them. I found the Clang > Modules documentation difficult to understand. I'll summarise some of the experiments that I ran1 to give you a feel for what the export
and module
keywords mean in practice. I found the behaviour of the modulemap
file to be different in Objective-C and Swift code so I'll cover both separately.
Let's assume your Communication.h
header file consists of the following two imports:
#import <Communication/Class1.h>
#import <Communication/Class2.h>
Assume also that Class1.h
defines a single class named Class1
and Class2.h
defines a single class named Class2
.
Importing modules in Objective-C classes
Let's assume, to start with, that your modulemap
file is defined minimally as follows:
framework module Communication {
umbrella header "Communication.h"
}
In the Objective-C classes of your targets which link in the Communication
framework, you can import the Communication
module and you can call on the classes imported via the Communication.h
umbrella header file, as follows:
@import Communication;
+ (void)someMethodThatDependsOnTheCommunicationModule {
[Class1 someOperation];
[Class2 someOperation];
}
What you can't do right now is import the Communication.Class1
sub-module. To make that possible, you need to change your modulemap
file to the following:
framework module Communication {
umbrella header "Communication.h"
module Class1 {
header "Class1.h"
}
}
You can now import the Communication.Class1
sub-module and call on Class1
, as follows:
@import Communication.Class1;
+ (void)someMethodThatDependsOnTheCommunicationModule {
[Class1 someOperation];
}
Of course, you still can't import the Communication.Class2
sub-module. To make that possible, you can either add a Class2
module declaration in the modulemap
file like we did for Class1
or use a wildcard2. Here's how you would do it with the wildcard:
framework module Communication {
umbrella header "Communication.h"
module * {}
}
With this change, you can now import the Communication.Class1
and Communication.Class2
sub-modules and you can call on their classes, as follows:
@import Communication.Class1;
@import Communication.Class2;
+ (void)someMethodThatDependsOnTheCommunicationModule {
[Class1 someOperation];
[Class2 someOperation];
}
I tried my best to find a use for the export
keyword in the context of modules that will be imported into Objective-C code but I was unable to.
Importing modules in Swift classes
Let's assume, to start with, that your modulemap
file is defined minimally as follows:
framework module Communication {
umbrella header "Communication.h"
}
In the Swift classes of your targets which link in the Communication
framework, you can import the Communication
module and you can call on the classes imported via the Communication.h
umbrella header file, as follows:
import Communication
func someFunctionThatDependsOnTheCommunicationModule {
Class1.someOperation()
Class2.someOperation()
}
What you can't do right now is import the Communication.Class1
sub-module. To make that possible, you need to change your modulemap
file to the following:
framework module Communication {
umbrella header "Communication.h"
module Class1 {}
}
You can now import the Communication.Class1
sub-module and call on Class1
, as follows:
import Communication.Class1
func someFunctionThatDependsOnTheCommunicationModule {
Class1.someOperation()
}
Contrary to what I experienced with Objective-C3, I found that I was still able to call on Class2
despite importing Communication.Class1
only.
If you still want to import Communication.Class2
in isolation4, you can either add a Class2
module declaration in the modulemap
file like we did for Class1
or use a wildcard2. Here's how you would do it with the wildcard:
framework module Communication {
umbrella header "Communication.h"
module * {}
}
I tried my best to find a use for the export
keyword in the context of modules that will be imported into Swift code but I was unable to.
1I ran these experiments in Xcode 13.4.1. If you experience different behaviour in a later version of Xcode, let me know and I will re-run my experiments and update my answer.
2The wildcard will define a module for every class that's defined by the headers imported in the umbrella header file.
3And contrary to what I expected.
4Despite it being quite pointless as explained in the previous paragraph.