What is export * in module.modulemap file inside each framework?
Asked Answered
D

2

14

I have created a framework named Communication. Inside the framework's container, there is a module.modulemap file which has the following contents:

framework module Communication {
    umbrella header "Communication.h"

    export *
    module * { export * }
}

I can understand that the module declares an umbrella header to expose it to the containing application/target.

What is the meaning of other two lines of code?

export *
module * { export * }

What are these lines exporting?

Denison answered 31/10, 2017 at 12:56 Comment(2)
Check this doc on LLVM modules too.Peripheral
Both of the links are helpful. ThanksDenison
N
4

Objective-C Module Map(.modulemap) for Objective-C and Swift

Objective-C language exposes API through .modulemap for Objective-C and Swift languages

[ObjC Module]

[Custom .modulemap]

It is about LLVM Modules and Module Map Language. Modulemap exposes C header files for external binaries. It is a bridge between module and headers. Modulemap helps to convert #include, #import -> @import because it has a mapping between module name and headers inside. Also modulemap helps to create standalone additional modules and submodules. Modulemap can contains a lot of modules(only one has to have the same name as product name) and a lot of submodules

//Objective-C exposes API through .modulemap for Objective-C and Swift

.h.m uses .h.m = Objective-C consumer, Objective-C producer = .modulemap
.swift uses .h.m = Swift consumer, Objective-C producer = .modulemap

Framework which includes .modulemap is called Modular Framework. Path:

module_name.framework/Modules/module_name.modulemap

Setup

  • When you create a library[Example] you should create and setup it manually
  • When you create a framework[Example] it is setup automatically

Even if you create Swift framework Xcode automatically creates modulemap

[Mixing Objective-C and Swift in the same Application]

Nic answered 6/12, 2019 at 12:59 Comment(2)
This does not answer what export means.Serpent
@ray, stackoverflow.com/questions/30704268/…Nic
Q
2

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.
Quoit answered 6/10, 2023 at 20:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.