We recently pushed out version 2.2.2 of our AerisWeather SDK for iOS to fix some issues with using Objective-C and Swift modules in Xcode 7 and Cocoapods. While tweaking our internal projects to better support modules, we ran into this dreaded compiler error in Swift 1.2 when trying to build the updated libraries:
There were many of these errors and they all appeared within the umbrella headers of each of our frameworks, Aeris.h for example. At first, we figured it was some weirdness caused by using our ObjC AerisWeather libraries in a Swift project, but our libraries were being included in the project’s bridging header properly.
When confronted with this error, there are of course more common things to check. First, make sure all headers that should be public and are listed in the framework’s umbrella header are flagged as public within the library’s project under the file’s Target Membership. In our case, this wasn’t the cause. So then the second thing to check is your project’s build settings and make sure the value for Allow Non-modular Header Includes in Framework Modules is set to YES, which is a new build setting in Xcode 7:
Additionally, if you are using Cocoapods for including other dependencies in your project you’ll also need to set this build setting to YES for each pod. A quick and painless way to do this adds a post_install action in your project’s Podfile to set this automatically:
post_install do |installer| installer.pods_project.build_configuration_list.build_configurations.each do |configuration| configuration.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'] = 'YES' end end
In many cases going through these two steps will fix your issues. But alas, we were still plagued by the same non-modular header error from our AerisWeather frameworks.
After hours of endless browsing online and trying many different things with our project in search of a solution, we finally came across a thread on Apple’s developer forums that included a response from someone on Apple’s staff, so that had to be the answer right? Here’s his response with emphasis placed on the cause of our issue:
This happens because in 7.1:
The Swift compiler is stricter about including non-modular header files than it was in previous releases. Debugging a Swift target requires that frameworks be properly modular, meaning all of the publicly-imported headers are either accounted for in the framework’s umbrella header, are imported from another modular framework, or are listed explicitly in a custom module.modulemap file (advanced users only).
The compiler will run into issues if the same header file is accessible both through Header Search Paths (‘-I’, ‘-isystem’) and Framework Search Paths (‘-F’, ‘-iframework’), even if there are symbolic links involved. In these cases, you should prefer using Framework Search Paths. (Note that this invalid configuration may be generated by external systems, such as CocoaPods.)
Unfortunately, CocoaPods can commonly create header search paths that let the compiler find headers at a location which does not appear (to the compiler) to be a part of a module.
NOTE: The “Allow Non-modular includes in Framework Modules” build setting does not apply to Swift (and it would not be safe if it did, Swift requires access to modules for proper debugging support).
That was it! Since our AerisWeather libraries are frameworks, they are being included in the Framework Search Paths build setting of our project. But since we’re including it via Cocoapods, Cocoapods is also including the path to the header files in the project’s Header Search Paths in the Cocoapod’s configuration file your project’s target is inheriting. Simply adjust your target’s Header Search Paths build setting and either remove the path pointing to the libraries public headers or simply remove the `$(inherited)` line to prevent inheriting Cocoapod’s header search paths:
Once we made this simple, but highly unknown, change to our project, the compiler was once again satisfied and our project was building properly using our AerisWeather frameworks as modules via Cocoapods. Hopefully this post will save someone out there a lot of time and headache trying to track down the cause of this error they are also seeing.
We’re constantly updating and improving our AerisWeather iOS SDKs to use the latest iOS APIs and have many more things planned for them in 2016. So sign up for our AerisWeather API, download our latest iOS SDKs and start building your own Aeris-powered apps!