212

Now I would like to migrate my ObjC framework to Swift and I got the following error:

include of non-modular header inside framework module 'SOGraphDB'

The references is to a header file which just define a protocol and I use this header file in some classes to use this protocol.

Is seems related to the module feature but it is at the moment not quite clear how to fix, do you know a solution?

UPDATE:

This is a Swift compiler error.

UPDATE 2:

A quick fix (but not solving the root cause) is to set the following setting to yes: CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES

Daniel
  • 8,794
  • 4
  • 48
  • 71
Stephan
  • 4,263
  • 2
  • 24
  • 33
  • 4
    It seems there is a new build setting for " CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" – Stephan Jun 08 '14 at 05:31
  • 1
    Has anyone seen this on includes that are public and modular? I see this with a vanilla (cocoapods) project: https://github.com/CocoaPods/CocoaPods/issues/3092 and https://www.dropbox.com/s/trhe5vwhzoa9bf5/umbrella_file_breaks_symbol_lookup.tar.gz?dl=0 – Chris Conover Jan 31 '15 at 08:45
  • Has anyone made a quick script that enables this automatically? – fatuhoku Aug 04 '15 at 17:37
  • @fatuhoku [yeah](http://stackoverflow.com/a/32080491/878969) – funroll Aug 18 '15 at 18:59
  • None of these solutions worked for me, it looks like it was a bolts.framework collision in my case. Deleting it solved the problem: http://stackoverflow.com/a/33114309/3324388 – Aggressor Oct 13 '15 at 23:36
  • This happened to me today and I am using XCode 7.3.1, it's a Parse project with FB SDK in it too.. Specifically the error was coming from Parse libraries it seemed like but earlier I had "errors" in my code saying some Parse objects couldn't be found, I had Parse imported in my bridging header so it was weird I was getting these errors. So I added specific "import Parse" in my ViewController, then project built... Then I started the getting the error in the question, removing those imports solved the issue. – C0D3 Jun 15 '16 at 20:48

21 Answers21

325

Is your header public?

Select the header file in the project explorer. Then in the section on the right in xcode, you'll notice there is a dropdown next to the target. Change that from "project" to "public". This worked for me.

public header

kgreenek
  • 4,986
  • 3
  • 19
  • 30
  • I accept this answer even it is the same as I stated. – Stephan Jun 22 '14 at 18:34
  • 2
    You can also go to the Headers build phase of your framework and quickly see which headers are Public, Project, and Private. – Jose Ibanez Jul 14 '14 at 22:20
  • I didn't think this simple task could possibly be the solution as I had fought with this for over an hour before coming here to SO. Lo and behold, this was EXACTLY the solution and worked immediately. – TMc May 31 '15 at 16:02
  • 2
    And what if I *want* these headers to be internal? – Raphael Mar 02 '17 at 14:57
  • @Raphael: Don't import internal headers into a public header. If you wish to use definitions from an internal header in a class declared in a public header, consider importing the internal header in the .m file instead. – simioliolio Mar 21 '17 at 08:52
  • 2
    This also solves my issue! In my case, my one pod that depends on another pod cannot import it because of modular issue. So I made some headers included as target for another pod, using public mode. And it solves the issue! – Chen Li Yong Jul 09 '18 at 07:39
141

This is an expected compiler behaviour and for a very good reason.

I think the majority of people running into this issues is caused after they switch from Application Target to Framework Target and start adding C and Objective C headers into framework's umbrella header expecting it to have a same behaviour as application's Bridging Header, which behaves differently. The umbrella header is actually designated for mixed swift, obj-c framework and its purpose is exposing the APIs to the outer world that your framework has in objective-c or c. That means the headers we put there should be in the public scope.

It should not be used as a place that exposes Objective-C/C headers that are not a part of your framework to your framework's swift code. Because in that case these headers will be also exposed as the part of our framework module to the outer world, which is often not what we want to do since it breaks the modularity. (And that is exactly why Allows Non-modular Includes in Framework Modules defaults to NO)

In order to expose Objective-C/C library to your framework swift code, we should define a separate swift module for such library. Then a standard swift import YourLegacyLibrary can be used.

Let me demonstrate this on some typical scenario: embedding libxml2 into our framework.

1. You first need to create a module.modulemap file which would look in this way:

For OSX framework:

module SwiftLibXML2 [system] {
  header "/usr/include/libxml2/libxml/xpath.h"
  export *
}

For iOS framework:

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

All it does is that it wrap ups the header and any other headers it references inside swift module, so that swift will then be able to generate the swift bindings for these C interfaces.

2. Then in your xcode project directory create a folder SwiftLibXML2 and put this module.modulemap there

3. In Build Settings, add $(SDKROOT)/usr/include/libxml2 to Header Search Paths

4. In Build Settings, add $(SRCROOT)/SwiftLibXML2 to Import Paths

5. Under Project's General tab, add libxml2.tbd to Linked Frameworks and Libraries.

Now you import this module where needed with:

import SwiftLibXML2

(if you want to look a more complete module.map example, I would suggest referencing Darwin's module.modulemap at /usr/include/module.modulemap, you would need to have Xcode command-line tools installed to go there, reference Missing /usr/include in OS X El Capitan)

Community
  • 1
  • 1
ambientlight
  • 7,212
  • 3
  • 49
  • 61
  • 1
    The file name `module.map` is deprecated, it should be renamed `module.modulemap` http://clang.llvm.org/docs/Modules.html#attributes – Hyperbole Aug 22 '16 at 20:30
  • How to `import SwiftLibXML2` in Objective-C? Thanks! – Itachi Dec 21 '16 at 04:27
  • same way as any other obj-c imports: #import but make sure you did steps 3-5. – ambientlight Dec 21 '16 at 08:19
  • We did this, but then the build artifact can not be moved between machines: the Objective-C (sub)module is apparently linked using absolute paths, causing errors when compiling, say, an app that uses the framework you shipped. – Raphael Mar 21 '17 at 09:53
  • the error is most likely specific to your build process, this is just a module definition so that llvm languages that support modules can interop with others, I don't think it can by itself affect your build artifacts, may the community correct me if I am wrong – ambientlight Mar 21 '17 at 10:23
  • Xcode 9 doesn't seem to have *Import Paths* in the Build Settings when your project type is Cocoa Touch Framework. I'm trying to embed an Objective-C framework in my Swift SDK framework. Any ideas? – mph Feb 28 '18 at 04:27
  • @mph: Does specifying it via user-defined setting with key SWIFT_INCLUDE_PATHS work for you? – ambientlight Feb 28 '18 at 08:31
  • @ambientlight Never mind. I got it working. I just wasn't formatting my import statements properly. :) – mph Mar 01 '18 at 22:30
  • @Raphael I am facing this same issue. It only works for my machine. – nr5 Feb 21 '20 at 15:13
57

Here's how to automatically apply the quick fix so you don't have to change Pods.xcodeproj manually after each pod install.

Add this snippet to the end of your Podfile:

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
funroll
  • 35,925
  • 7
  • 54
  • 59
30

Solution for me was to go on target-> build settings->Allow non-modular includes in Framework Modules switch to YES!

Konrad Krakowiak
  • 12,285
  • 11
  • 58
  • 45
Vlad Burlaciuc
  • 341
  • 3
  • 2
  • Also worked with Cocoapods here. No need to do the magic from the other answer after the pod install – brainray Sep 19 '15 at 19:18
  • 3
    I've done this step.. it worked for a while.. and now it is not working... I included the pod-install step too. But it is now failing again. Anything else I should be checking? I am not seeing the GoogleMobileAds.Framework as an option for changing headers to Public. – Michael Rowe Nov 18 '15 at 14:00
  • This didn't work for me. Still getting the error with Parse. Xcode 7.3.1 – C0D3 Jun 15 '16 at 19:34
  • I had to restart XCode after making this change for it to work. – John Fowler Feb 09 '18 at 18:26
  • 1
    What is the impact of changing this setting? – nr5 Jun 25 '19 at 12:34
16

In Swift:

1. Modify your Xcode project and targets' Build Settings as mentioned below:

Allow Non-modular Includes In Framework Modules: No

Enable Bitcode: Yes

2. Use the current latest version available for GoogleMaps iOS SDK (use CocoaPods for getting it):

GoogleMaps (1.10.4)

3. Comment the problematic import:

//import GoogleMaps

4. Create or modify your bridging header file, adding the problematic import:

[Your Xcode Project Name]-Bridging-Header.h

// Use this file to import your target's public headers 
// that you would like to expose to Swift.
#import <GoogleMaps/GoogleMaps.h>

5. Clean and re-build your Xcode project.

King-Wizard
  • 15,628
  • 6
  • 82
  • 76
15

I think I got around this. I have some model code that uses sqlite3 in a framework. In my case, the culprit was <sqlite3.h>.

The problem was that in my Module/Module.h header, I imported a public header that imported <sqlite3.h>. The solution was to hide all the sqlite3_xxx types and make sure they were not visible in any public .h. All direct references to sqlite3 were made private or project visibility. For example, I had a public singleton that had some sqlite3_stmt pointers hanging off it. I moved those to a separate class that is now only a forward declaration in that public header. Now I can build.

Incidentally, the CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES setting didn't work. I tried setting it both in the framework and the dependent project. This workaround was necessary, though I'm not sure why.

Jimmy Dee
  • 1,070
  • 1
  • 11
  • 17
  • This totally helped! In my case, it was Reachability. – Daniel Brim Sep 20 '14 at 07:28
  • 4
    I am pretty sure this is the solution to my problem when I try to include SSZipArchive in my framework module. The public header is imporing and giving the same error. Can you post your source code somewhere because I'm struggling to get it to work since I only understands part of your answer.. thanks! – Bruce Jun 15 '15 at 01:00
7

Don't

#import "MyOtherFramework.h"

Do

#import <MyOtherFramework/MyOtherFramework.h>
hfossli
  • 22,616
  • 10
  • 116
  • 130
6

This answer is out-dated.

When importing frameworks, you must import all header files that share dependencies with the root header. The easiest way to ensure this always works is to import all headers in the framework's "Headers" folder into your public headers path.

enter image description here

The Swift compiler uses this information to generate a map of non-mangled symbols along with their associated type information.

seo
  • 1,959
  • 24
  • 18
  • This seems to defeat the purpose of having the Framework files, but it worked for me. Chartboost and RevMob have both recently started using Framework files instead of just libs. Copying everything from their headers to my app headers resolves the issue. – Jason Short Apr 29 '15 at 22:48
  • Is this the only solution? I have 6 frameworks and each framework has around 20 headers. It creates a mess. Any alternate? – vivin Oct 02 '15 at 17:07
  • 1
    More than likely. This is probably no longer relevant as it was a workaround in an Xcode bug. – seo Oct 02 '15 at 17:54
3

The header file was allocated to the target but was only marked as project visible, just a change to public lead to the resolution of this error.

Stephan
  • 4,263
  • 2
  • 24
  • 33
3

Switching Build settings > Allow non-modular includes in Framework Modules to YES! solved the same issue for me.

2

I know that this is an old question, but I had the same issue and nothing from above helped me. So I hope my answer will be helpful for somebody. In my case the problem was in ALWAYS_SEARCH_USER_PATHS setting. When it was set to NO project built and worked ok. But as far as one of the pod required it to be set to YES I was receiving an error

Include of non-modular header inside framework module

After couple cups of coffee and all day researching I found out that according to known issues of Xcode 7.1 Beta 2 release notes:

• If you get an error stating "Include of non-modular header inside framework module" for a framework that previously compiled, make sure the "Always Search User Paths" build setting is set to "No". The default is "Yes" only for legacy reasons. (22784786)

I was using XCode 7.3 though, but seems like this bug hasn't been fixed yet.

iyuna
  • 1,787
  • 20
  • 24
  • This is what helped me! I had to change some imports after switching to NO but now I was able to import my needed framework! – Pavel Gurov May 04 '17 at 07:37
2

I would like to add my experience with the problem as well.

Just to summarize :

  • @ambientlight's answer is great and it fixes most of the problems.
  • allowing non-modular headers is another solution (see some of the answers above).
  • marking the framework's headers as public (only the ones that you want to expose) and importing them in the umbrella header.

Here are my 2 additions to the above answer(s):

  • carefully check the imports in your project for headers which import your frameworks directly in them (instead of using forward declaration, if possible) -- it is not a good practice to include a header file inside another header file; sometimes this causes a problems, because if not done properly this may lead to multiple include-ing of one header and create linker issues.
  • UPDATE: make sure that the architectures of the library and that of the target that you want to link it to match.
  • and lastly, after doing all of the above, I still kept bumping onto that error. So I dug a little more and found (in the apple developer forums, but I lost the link :( ) that if you include the headers in the umbrella header not like this <framework/headerName.h>, but only like this "headerName.h", the problem goes away.

I tried this last one, and so far I haven't experienced this problem anymore, however I suspect that this solution is valid only if you have applied some of the top answers (note: they are not all compatible with each other, for example, the module approach and the allowing of non-modular header includes).

AmitaiB
  • 1,656
  • 1
  • 19
  • 19
Georgi Boyadzhiev
  • 1,351
  • 1
  • 13
  • 18
1

I had this exact problem when including my own framework in a project. Fixed it by putting all imports of sqlite3.h in .m files not in public .h ones. I'm assuming that other libraries may flag similar issues with Xcode.

Rob Sanders
  • 5,197
  • 3
  • 31
  • 58
1

I had the specific problem with Facebook 4.02 sdk and FBSDKCoreKit.

I did all the steps but still error about non modular header. i drag and dropped only the specific header from the framework to build phases-> header section.

Then automatically created a copy of the header on the project navigator at the top.

I removed it from the build phases -> header and deleted the new file and worked fine.

Like it reseted or something.

Haris
  • 129
  • 1
  • 9
1

In my case (Xcode 9 beta 6 - Swift 4 - using Cocoapods) this was solved when I deleted Podfile.lock and the Pods directory and ran pod install again

m_katsifarakis
  • 1,777
  • 1
  • 21
  • 27
1

I got this problem after updating a project from swift2 to swift3. I was using XCode 8.3.2 to update the code and could not get rid of the error “non-modular header inside framework module”. When I opened the same project in another version of XCode (version 9.0.1) the error did not appear.

DevB2F
  • 4,674
  • 4
  • 36
  • 60
1

I tried every possible solution that I found on this thread setting target-> build settings->Allow non-modular includes in Framework Modules switch to YES! etc. etc.

But nothing worked.

I started getting this error when I installed pods by commenting use_frameworks! , because I wanted to have static library for pods.

Reason Swift compiler throwing (on Xcode 13) this error because I was importing private framework header #import "TFLTensorFlowLite.h" in public .h file, so I imported it in .m file as shown in below screenshots and it stopped throwing this error by Swift compiler (note my Framework had both Objective c and swift code)

enter image description here

enter image description here

Waaheeda
  • 394
  • 3
  • 14
0

Most commonly this error is caused by the chosen answer, yet I had this error appear once by accident when dragging framework files into my new project folder. I clicked to delete the frameworks but accidentally pressed to only 'Remove Reference' to the frameworks rather than to actually delete the files completely. At this point if I opened my project folder in Finder I saw files like 'CoreLocation' and 'AudioToolbox' there. Deleting these files from the project folder and cleaning the project fixed the issue.

Chris Klingler
  • 5,258
  • 2
  • 37
  • 43
0

After allowing to import non modular includes, you could try to import that module using Objective-C Bridging header:

#import <YandexMobileMetrica/YandexMobileMetrica.h>
Yuri Korshev
  • 85
  • 1
  • 9
0

I solved it removing Modules folder from the framework.

  • Browse to your framework location which is present in the App Project using finder

  • Go inside Test.framework folder (In the above case it will be SOGraphDB.framework) & Delete Modules folder.

  • Clean and Re Build the app, it will solve the problem.

Vittal Pai
  • 3,317
  • 25
  • 36
-3

I had this problem importing the Parse framework. The only way I could fix it was to discard all my changes since my last commit (simply deleting the framework and cleaning the project did not work) and add Parse again (after a fresh download of the SDK) with its other required frameworks.

amurray4
  • 125
  • 1
  • 7