Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CommonCrypto modulemap doesn't work with Swift framework #102

Open
srozner opened this issue Feb 7, 2018 · 19 comments
Open

CommonCrypto modulemap doesn't work with Swift framework #102

srozner opened this issue Feb 7, 2018 · 19 comments
Labels

Comments

@srozner
Copy link

srozner commented Feb 7, 2018

I am using JSONWebToken within my own Swift framework. This does not work with the standard modulemap CommonCrypto solution. I found this link that pulls together and describes the issues with including CommonCrypto, particularly within a Swift Framework.

http://ioscake.com/importing-commoncrypto-in-a-swift-framework.html

The easiest solution may be to include this approach specifically targeted at Cocoapods:

pod 'CommonCryptoSwift', :git => 'https://github.com/onmyway133/CommonCrypto.swift'

Or it may be used as a basis for a solution you trust.

@kylef
Copy link
Owner

kylef commented Feb 7, 2018

@srozner Can you please share with me the error you are seeing and some steps to reproduce?

@srozner
Copy link
Author

srozner commented Feb 7, 2018

Hopefully not too long :) but this is my understanding of old CryptoSwift use and the issue with CommonCrypto modulemap use.

OLD

Project "MySDK" included JSONWebToken pod in Podfile, which also included CryptoSwift as a dependency.

target 'MySDK' do
use_frameworks!
pod 'JSONWebToken'
end

So when building our app "MyApp", I directly include the "MySDK" framework built locally and must also include the JSONWebToken pod in Podfile (can't be embedded in MySDK as a Swift framework). This again adds CryptoSwift as a pod dependency.

target 'MyApp' do
use_frameworks!
pod 'JSONWebToken'
end

In this case, CryptoSwift is dynamically linked to MySDK "Framework" and then actually included/embedded in MyApp with the pods (building an app and not a framework).

NEW

For "MySDK" the Podfile is the same. Instead of including and dynamically linking to the CryptoSwift framework, the CommonCrypto modulemap seems to directly embed a mapping into MySDK framework. Everything compile fine here.

For "MyApp" the Podfile is again the same. I must still include JSONWebToken for the app to include this framework dynamically linked to MySDK framework. Unfortunately the CommonCrypto modulemap in JSONWebToken seems to try directly embedding a mapping into MyApp again.

The modulemap embedded in MySDK framework and MyApp, via including pod JSONWebToken in both project, causes a "Redefinition of module 'CommonCrypto'" when building MyApp.

====================
....../Pods/JSONWebToken/CommonCrypto/module.modulemap:1:8: error: redefinition of module 'CommonCrypto'
module CommonCrypto [system] {
^
....../Pods/JSONWebToken/CommonCrypto/module.modulemap:1:8: note: previously defined here
module CommonCrypto [system] {
^
:0: error: could not build Objective-C module 'JWT'

Each "module CommonCrypto [system]", in MySDK and MyApp via JSONWebToken, seems to create a direct embedded instance of the CryptoSwift module mapping. Xcode then sees the duplication and can't resolve it as being equivalent. So it sees it as a "Redifinition" error.

POSSIBLE SOLUTION

My understanding of the solutions are to move the "module CommonCrypto [system]" into a separate framework (like CComonCrypto or CommonCryptoSwift in some examples). This results in dynamically linking one of these CommonCrypto framework wrappers to both MySDK and MyApp. It is just a dynamic link in MySDK and then MyApp actually embeds the CommonCrypto framework once without conflict.

The link I posted above seems to have one solution using an existing CommonCryptoSwift pod. It looks like this handles compilation for iOS device, iOS simulator, Mac OSX and other platforms. It them looks like a Swift framework, just like CryptoSwift was, and builds the app without error.

This is a long explanation, but it took me a long time to find these details and wrap my head around them. Hopefully this keeps you from having to dig as deep as I did.

@kylef
Copy link
Owner

kylef commented Feb 7, 2018

Okay, so the problem is when you use JSONWebToken alongside another dependency which also contains a module map for CommonCrypto? Then at compile time they are not built isolated and thus you are hitting a duplicate module map for CommonCrypto error. Do I understand correctly?

I'm having a little bit of a difficulty the part about CryptoSwift, I'm looking at the CryptoSwift package that you mention and I am not seeing any dependencies in it nor a module map file in the pod spec (https://github.com/krzyzanowskim/CryptoSwift/blob/master/CryptoSwift.podspec). Perhaps you are using a different version or this is unrelated to the problem?

@srozner
Copy link
Author

srozner commented Feb 7, 2018

I think you understand it correctly. My issue is I am including JSONWebToken through an intermediate Swift Framework of my own MySDK. So anyone using my framework (MySDK) would encounter this, as when I build MyApp which links to MySDK.

JSONWebToken switched from using CryptoSwift (which was built as a Swift Framework pod and dynamically linked) to using Apple's CommonCrypto (included as an embedded module mapping) in v2.2.0 I believe. It appears CryptoSwift does not compile in Xcode 9 due to obsolete numeric type use. CryptoSwift worked as it was dynamically linked in MySDK and MyApp, whereas the CommonCrypto module as defined is embedded in the intermediate MySDK and tries to again be embedded in MyApp.

I mentioned the previous use of CryptoSwift as it was working due to it inclusion as a separate, dynamically linked Swift Framework.

Believe me, it took a while to wrap my head around this. It is the fact I am using JSONWebToken in my own "intermediary" Swift Framework that causes this.

Project 1:

MySDK (Swift Framework)

  • Pod JSONWebToken (in Podfile to dynamically link Swift Framework via pod)

Project 2:

MyApp (actual app)

  • Include MySDK (builds SDK Framework into app - but not the dependent Frameworks)
    • JSONWebToken only dynamically linked in MySDK and not built into app automatically
  • Pod JSONWebToken (in MyApp Podfile again to actually build into app)

Including the JSONWebToken pod in an intermediary Swift Framework (MySDK), which then requires an app to include both the intermediate (MySDK) and the JSONWebToken pod to build, causes the trouble.

I'll answer anything you need to get your head wrapped around this problem.

@kylef kylef added the bug label Feb 7, 2018
@srozner
Copy link
Author

srozner commented Feb 8, 2018

I really, really appreciate how quick you have responded. I look forward to your eventual response, and feel free to ask for more info.

@srozner
Copy link
Author

srozner commented May 30, 2018

FOLLOW UP: attempts to fix the method CommonCrypto is included have seemed futile. If you use nested dynamic framework pods using a CommonCrypto (or other?) module map, you will end up with a duplicate module map link error with no easy fix. My case is:

APP with Dynamic Framework Pods

  • Include SDK Dynamic Framework
  • Include JSONWebTokens Dynamic Framework Pod used by SDK (duplicate CommonCrypto)
    SDK with Dynamic Framework Pods
  • Include JSONWebTokens Dynamic Framework Pod
    JSONWebTokens Dynamic Framework Pod
  • Include CommonCrypto module map (first CommonCrypto mapping)

ISSUE: The error stems from the JSONWebToken Dynamic library in the SDK exposing the CommonCrypto module map, and the JSONWebToken in the APP also exposing a duplicate module map. The conflict fails to resolve and aborts the link.

WORK AROUND: My fix was to compile my SDK with Static Library Pods, but remain building my SDK as a Dynamic Framework and using Dynamic Framework Pods in the APP. THIS REQUIRES LATER COCOAPODS AND MAYBE XCODE 9 TO BUILD STATIC SWIFT LIBRARIES. JSONWebTokens is built as a Static Library and appears NOT to expose the CommonCrypto module map. My SDK is still build as a Dynamic Framework to include resources. None of my SDK pods have resources and work fine as Static Libraries. My APP builds its pods as Dynamic Frameworks and includes my SDK as such.

ODDITY: The APP builds JSONWebTokens as a Dynamic Framework! All the APP pods are built this way. The SDK does NOT embed the JSONWebTokens Static Library (painful to even try), so the APP must still build it. The APP's JSONWebTokens Dynamic Framework pods DOES satisfy the link dependency of the SDK's JSONWebTokens Static Library. The APP is embedding the dynamic framework, so it makes sense the linker can resolve. It just feels dirty, but this is the only way I have been able to get a nested framework use of a CommonCrypto module map to work.

APP with Dynamic Framework Pods

  • Include SDK Dynamic Framework
  • Include JSONWebTokens DYNAMIC FRAMEWORK Pod for SDK link (only CommonCrypto map)
    SDK with STATIC LIBRARY Pods
  • Include JSONWebTokens STATIC LIBRARY Pod
    JSONWebTokens STATIC LIBRARY Pod
  • Includes CommonCrypto but seems it DOES NOT EXPOSE the mapping from static library

@mpvosseller
Copy link

Just an FYI that in Xcode 10 beta the JSONWebToken pod now fails to build with this error. You can reproduce by creating an empty project in Xcode 10 beta, adding the JSONWebToken pod, and building.

/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk/usr/include/CommonCrypto/module.modulemap:1:8: error: redefinition of module 'CommonCrypto'
module CommonCrypto [system] [extern_c] {

@egv
Copy link

egv commented Jun 7, 2018

and do you have a solution for this in Xcode 10 beta?

@mpvosseller
Copy link

@egv deleting the directory Pods/JSONWebToken/CommonCrypto seems to work but I'm not sure why those files were needed in the first place or if doing so has any implications I'm not seeing.

@egv
Copy link

egv commented Jun 7, 2018

@mpvosseller thanks! Just figured that out myself half an hour ago. Now I will check if breaks build in Xcode 9.4

@srozner
Copy link
Author

srozner commented Jun 7, 2018

I would guess Apple has "finally" exposed CommonCrypto to Swift natively. It was only Obj-C in Xcode 9, which required that module you deleted. That wrapper module caused my issue, which a huge number of people were caught out on (Stack Overflow has numerous threads). If Apple now exposes CommonCrypto to Swift natively, it makes sense that the CommonCrypto wrapper would cause a duplicate mapping. Removing the CommonCrypto folder would then fix both the Xcode 10 build and my own issue.

radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 12, 2018
(avoids collision with system framework exposed in iOS 12)
re kylef#102
radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 12, 2018
radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 12, 2018
radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 12, 2018
@radianttap
Copy link

I've been trying to resolve this by using CCommonCrypto name instead of just CommonCrypto (which clashes with Apple's name in iOS 12). Similar to what's done in Arcane

But I can't seem to get it to work properly. :(

@jonblatho
Copy link
Contributor

jonblatho commented Jul 24, 2018

I’ve made a fork of this repo and published a release with several changes, including a fix in Package.swift for this issue. Importantly it requires Swift 4.1, but it should be a useful fix for people who need Xcode 10 support now without breaking Xcode 9.3/9.4 support. (Just be sure to run $ swift package update any time you hop between Xcode 9 and 10!)

If you want to fork the repo and make the fix yourself, you can see my fix in this commit.

Edit: I should clarify that this may not fix the topic of this GitHub issue, but it fixes what others have been going through in the comments.

radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 31, 2018
- remove CommonCrypto file(s) from the file system
- added new aggregate target which conditionally builds CommonCrypto
- link to that target in all 4 of our targets

Per: https://stackoverflow.com/a/42852743/108859

re kylef#102
radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Jul 31, 2018
@radianttap
Copy link

Now just need to figure out the incantation for the podspec file

radianttap pushed a commit to radianttap/JSONWebToken.swift that referenced this issue Aug 1, 2018
- no additional target
- run script before Compile Sources
re kylef#102
@radianttap
Copy link

@kylef, I'm not sure what's the idea with your master branch, as it seems you removed the project and podspec.

In case anyone needs to use this as CocoaPod, take a look at my podspec branch. This compiles just fine in both iOS 11 and iOS 12, standalone and as pod.

@SamMcNeilly
Copy link

Hi @radianttap - this might be an incredibly stupid question, but how to I use your fork with my Podfile? I'm familiar with adding sources to the Podfile (e.g. source 'https://github.com/CocoaPods/Specs.git') but can't figure out how to get your fix integrated.

Apologies if I'm missing something really obvious here, and thanks for your hard work!

@radianttap
Copy link

@SamMcNeilly Like this:

pod 'JSONWebToken', :git => 'https://github.com/radianttap/JSONWebToken.swift.git', :branch => 'podspec'

@saltwat5r
Copy link

You can also remove CommonCrypto directory from Pods by adding this at the end of your Podfile:

post_install do |installer|

    require 'fileutils'

    FileUtils.rm_rf('Pods/JSONWebToken/CommonCrypto')

end

You should uninstall JSONWebToken pod at first and then install again with this script in your Podfile.

@dfixbugs1
Copy link

dfixbugs1 commented May 29, 2019

THERE IS AN EASY FIX!!

**See https://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework

section:
Update for Xcode 10

Xcode 10 now ships with a CommonCrypto module map making this workaround unnecessary.**

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants