1

I'm trying to set up the following arrangement of private Cocoapods:

PodA depends on PodB which depends on CommonCrypto.

CommonCrypto is a dylib that ships with iOS but doesn't have a Swift header module. Within PodB I've created a custom module.modulemap with the following contents:

module CommonCrypto [system] {
    header "/usr/include/CommonCrypto/CommonCrypto.h"
}

PodB passes the lint test (pod spec lint PodB.podspec) after adding the following lines:

# Ensure module isn't deleted by CocoaPods
s.preserve_paths = 'path_to/PodB/CommonCrypto'
s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '$(PODS_ROOT)/path_to/CommonCrypto' }

Within PodA, I depend on PodB with s.dependency = 'PodB'. When linting PodA with pod spec lint --sources=myrepo PodA.podspec I get an error compiling any Swift file with import PodB:

missing required module 'CommonCrypto'

How can I go about fixing this? It doesn't matter to me if CommonCrypto is private or public to PodB.

I tried adding export * to module.modulemap but that made no difference.

Tim
  • 4,560
  • 2
  • 40
  • 64

4 Answers4

1

I solved this issue with a (slightly) ugly workaround; I exported the include path to the parent project.

Since include paths are multi-valued, a list as opposed to a single setting, Cocoapods can merge whatever the parent project (PodA) sets with whatever the subproject (PodB) requires.

I had tried this solution before but it failed since I was using HEADER_SEARCH_PATHS instead of SWIFT_INCLUDE_PATHS. The relevant bit of the fixed podspec looks like this:

# Ensure module isn't deleted by CocoaPods
s.preserve_paths = 'path_to/PodB/CommonCrypto'
s.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/path_to/CommonCrypto' }
s.user_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/path_to/CommonCrypto' }

user_target_xcconfig is what allows PodB to inject build settings into PodA. This is generally not a great idea and could be used to screw up all kinds of things, so I'd welcome a better solution, but in the particular case of pointing parent pods to a module I think it is acceptable.

That said I think this solution would fail if PodA depended on both PodB and PodC where both B and C required CommonCrypto...

Tim
  • 4,560
  • 2
  • 40
  • 64
1

So far I've had good luck just copying all of the needed CommonCrypto headers into a single bridging header, and including that into the pod. CommonCrypto changes very rarely, and it is reasonably likely that it will be a modular header before any important changes happen to it. See RNCryptor.h for an example header file. Note that all the #ifdef conditionals are included, and each entire header is included (not just what is required for this project). This should protect against multiple packages importing the same file (as long as the header doesn't change).

The resultant podspec just includes the .h as a source:

s.source_files = 'RNCryptor.swift', 'RNCryptor.h'
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    Yes, I spent awhile trying to understand your `CommonCrypto-Swift` pod before I realized you'd abandoned it for this approach. I was going to try it this way if I couldn't get modulemap method to work. Either way, I hope Apple turn it into a modular header sooner rather than later. – Tim Oct 06 '15 at 20:41
  • Yeah; I'm deleting that one. It was an interesting experiment but didn't work well. – Rob Napier Oct 06 '15 at 20:45
0

Did you add the framework to podB's spec file?

s.frameworks = 'CommonCrypto'
Scott H
  • 1,509
  • 10
  • 14
  • That seems to cause `PodB` to fail at link time. It is looking for a `CommonCrypto` framework and not finding it. – Tim Oct 06 '15 at 08:02
  • Oh sorry, I haven't worked with CommonCrypto before. Is it called something else? I see a libcommonCrypto.tdb in my apple supplied frameworks. – Scott H Oct 06 '15 at 16:39
0

using $(PODS_TARGET_SRCROOT) instead of $(PODS_ROOT)/podname/ worked for me

s.source_files = 'Classes/**/*.swift', 'modules/**/*.map'
s.preserve_paths = 'modules/**/*.map'

s.pod_target_xcconfig = {
   'SWIFT_INCLUDE_PATHS[sdk=iphoneos*]'         => '$(PODS_TARGET_SRCROOT)/modules/iphoneos/CommonCrypto',
   'SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]'  => '$(PODS_TARGET_SRCROOT)/modules/iphonesimulator/CommonCrypto',
}

module.map files: modules/iphoneos/CommonCrypto/module.map:

module CommonCrypto [system] {
    header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}

modules/iphonesimulator/CommonCrypto/module.map:

module CommonCrypto [system] {
    header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}
Hogdotmac
  • 282
  • 6
  • 7