Cocoapods: Private headers should be exposed in a *.private.modulemap

Created on 13 Dec 2015  Â·  10Comments  Â·  Source: CocoaPods/CocoaPods

For references in this issue, you can look at ZSWTaggedString (branch zac-swift-modulemap) to see what I'm talking about.

In my project, the generated .modulemap looks like so:

framework module ZSWTaggedString {
  umbrella header "ZSWTaggedString-umbrella.h"

  export *
  module * { export * }

  private header "ZSWStringParser.h"
  private header "ZSWStringParserTag.h"
  private header "ZSWTaggedStringAttribute.h"
}

However, these private headers are inaccessible in the Swift version of my framework. As far as I can tell, I'm doing things correctly here, but this is an area of Xcode/clang that has so little documentation I could vomit.

Apple's documentation suggests that I should create a ZSWTaggedString.private.modulemap for this situation (where I want to expose some private headers internal to my framework), and Xcode has a build setting MODULEMAP_PRIVATE_FILE to do so.

I can assign a value to this flag using a pod xcconfig like ${PODS_ROOT}/ZSWTaggedString/ZSWTaggedString.private.modulemap, but the directory it's referencing won't exist because it's not copied in for a development pod. Secondarily, this seems fragile as CocoaPods has changed directory structures in unexpected ways in the past.

I think, like providing my own spec.module_map which is copied into my Target Support Files directory, I should be able to provide a private_module_map which has the same behavior.

Alternatively, a *.private.modulemap could be generated automatically much like the normal modulemap, containing all references to the private headers I've defined in my podspec.

moderate discussion

Most helpful comment

I do not believe it is possible to expose private .h files to Swift inside a framework.

I ended up using a custom modulemap with a module called "Private" in the hopes consumers wouldn't use it. See here: https://github.com/zacwest/ZSWTaggedString/blob/master/ZSWTaggedString/Classes/ZSWTaggedString.modulemap

All 10 comments

Seems reasonable to me, although the private header bit should be gone now since it broke things ¯_(ツ)_/¯

I'd be open to a PR adding this functionality, but its not going to be a high priority for the time being.

I've given this a few (quite a few, actually) more hours of work, and I've drawn a few conclusions:

  1. The private map file seems to only be for in-project consumers of the framework, not internal to the framework.
  2. There is no way to expose private headers to Swift inside a framework via the .modulemap

I don't think there's anything Cocoapods can do to improve this situation, so I'm closing this issue.

Thanks for taking the time to investigate, @zacwest !

Has any progress been done in that?
We currently are hitting this problem.

@segiddins Did you get anywhere with this?

We have an framework which is written in Obj-C we are now adding in some private swift files into the framework which need to import some of the existing private Obj-C files. Currently the only way we are able to do this is by making the Obj-C files public.

@bencallis you can use a custom module map -- reading through the issue, it seems the conclusion was there's nothing for CocoaPods to do here?

@segiddins do you have any instructions on how to do this?

To be a bit clearer. We have FileA, FileB, FileC all inside the same framework.

FileA is in ObjC and a public file in the framework.
FileB is in ObjC and a private file in the framework.

FileC is in Swift and is a private file in the framework. FileC can access FileA but not FileB.

Making FileB public solves the issue but is not ideal.

I do not believe it is possible to expose private .h files to Swift inside a framework.

I ended up using a custom modulemap with a module called "Private" in the hopes consumers wouldn't use it. See here: https://github.com/zacwest/ZSWTaggedString/blob/master/ZSWTaggedString/Classes/ZSWTaggedString.modulemap

@zacwest sounds like a good solution. Will look into trying this :) Thanks.

@zacwest I am also trying to share private ObjectiveC files to my Swift framework and trying to hide them from outer world: https://stackoverflow.com/questions/56769304/extending-a-public-class-for-partial-public-access-in-swift

I tried your solution and it did not work. Here is how my modulemap looks like:

framework module MySDK {

    umbrella header "MySDK-umbrella.h"
    export *
    module * { export * }

    explicit module Private {
        header "CardDetails.h"
    }
}

Please take a look at my stackoverflow question.

Was this page helpful?
0 / 5 - 0 ratings