22

I'm using this answer to create a module map to create a module for CommonCrypto so I can use it in a framework.

Doing this however means that any projects that I use this framework in have access to CommonCrypto with import CommonCrypto - and even worse, declaring CommonCrypto in another framework and importing this into the project results in Redefinition of module 'CommonCrypto' errors.

I.e. the following setup:

MainProject |--> import FrameworkA - module map for CommonCrypto |--> import FrameworkB - module map for CommonCrypto 

Is there a way to create a module map but have it private to that Framework its created/used in? (Much like the internal access attribute in Swift for a Framework). The llvm Clang docs show a private attribute but I can't work out where to put this in my module map, and it might not even be for this purpose! There's also an export attribute but again I'm not entirely sure how to use this...!

This is my module map I'm using for CommonCrypto - the $(SDKROOT) gets swapped out in a build phase to the correct location (for iphoneos or iphonesimulator SDKs):

module CommonCrypto [system] [extern_c] { umbrella header "$(SDKROOT)/usr/include/CommonCrypto/CommonCrypto.h" export * } 

This works fine (except you can't "go to definition" but I don't mind that) for use in FrameworkA / FrameworkB.

3
  • Hi, any updated on this? I have the same exact setup for libz :( Commented Feb 2, 2016 at 17:41
  • 1
    Rich, could you please provide your build phase script that replaces $(SKROOT)? Thanks! Commented Feb 15, 2016 at 10:02
  • 1
    @appleitung: Script is here: gist.github.com/rhodgkins/5eecee8bcbdb6021fc798247132e9fa7 and then set it up like this: postimg.org/image/fj7j9nsqp in a project. Don't forget to add the directory $(PROJECT_DIR)/$(TARGET_NAME)/ExternalFrameworks/ to the *Framework Search Paths build setting as well. Then all module maps should sit in the input directory folder - with the folder name containing the modulemap being the name. Commented Apr 12, 2016 at 9:32

2 Answers 2

8

Disclaimer: I have not tried this for CommonCrypto but it works for my case with libz

A possible solution to this is to create a module.private.modulemap as described in the Clang documentation

So for example in FrameworkA you can write a module.modulemap file for FrameworkA like so:

module FrameworkACommon { } 

Then you would create a module.private.modulemap file like so

explicit FrameworkACommon.Crypto [system] [extern_c] { header "/Applications/Xcode6-Beta5.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.0.sdk/usr/include/CommonCrypto/CommonCrypto.h" link "CommonCrypto" export * } 

Then repeat for FrameworkB.

Now CommonCrypto is a private module in both FrameworkA and FrameworkB and the names won't clash.

Sign up to request clarification or add additional context in comments.

10 Comments

Nice! Thanks for sharing - I shall try it!
@tmpz I get lot of 'use of undeclared type ...'. Have you faced this ?
You're probably getting undeclared type because your module is not exporting any headers. The export * will export headers to FrameworkACommon and to import it you have to write FrameworkACommon.Crypto but it will stop there. Exported headers won't be visible past FrameworkACommon, they are internal now.
Is there any way to get this kind of thing to work using CocoaPods? I've tried a number of things with modulemaps, but I just can't seem to get it to work
@cjwirth You can specify a module map for a CocoaPod spec.
|
0

I'm not entirely sure this applies to the use case described in this question, but I'm gonna post an answer nonetheless, in hope it helps some folks out there struggling with preventing a module in a Framework from being accessible from an external app.

I've posted this answer in a similar, more recent, SO question.

It involves using native code from Swift through a module without making this module accessible to external apps. I think the real trick here, and that could relate to this question the most, is the use of this new experimental Swift feature that allows to set an access-level modifier to an import, and thus prevent it from leaking in the external app that includes the Framework.

As I said in the other SO question, this feature will be fully available in Swift 6, and imports should even be internal by default.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.