Swift编译器错误:"non-modular header inside framework module"。

212

现在我想将我的 ObjC 框架迁移到 Swift,但是我遇到了以下错误:

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

引用的是一个头文件,该头文件仅定义了一种协议,我在某些类中使用此头文件以使用此协议。

它似乎与模块功能有关,但目前还不太清楚如何修复,你知道解决方案吗?

更新:

这是Swift编译器错误。

更新2:

一个快速修复方法(但不能解决根本原因)是将以下设置设置为yes: CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES


4
似乎有一个新的构建设置"CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES"。 - Stephan
1
有人在公共和模块化的包含文件中遇到过这个问题吗?我在一个纯净的(CocoaPods)项目中看到了这个问题:https://github.com/CocoaPods/CocoaPods/issues/3092 和 https://www.dropbox.com/s/trhe5vwhzoa9bf5/umbrella_file_breaks_symbol_lookup.tar.gz?dl=0 - Chris Conover
有人写过一个快速脚本可以自动实现这个吗? - fatuhoku
@fatuhoku 是的 - funroll
这些解决方案都对我没用,看起来在我的情况下是 bolts.framework 冲突了。删除它解决了问题:https://dev59.com/Sl0b5IYBdhLWcg3wO_I_#33114309 - Aggressor
今天我遇到了这个问题,我正在使用XCode 7.3.1,这是一个包含FB SDK的Parse项目。具体来说,错误似乎来自于Parse库,但之前我的代码中也有一些“错误”,说找不到某些Parse对象,我已经在我的桥接头文件中导入了Parse,所以我很奇怪为什么会出现这些错误。因此,我在我的ViewController中添加了特定的“import Parse”,然后项目构建成功...然后我开始遇到问题中的错误,删除这些导入就解决了问题。 - C0D3
21个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
324

你的头文件是公开的吗?

在项目资源管理器中选择头文件。然后在Xcode中右侧的部分,你会注意到目标旁边有一个下拉菜单。将其从“项目”更改为“公共”。这对我有用。

公共头文件


我接受这个答案,即使它与我所说的相同。 - Stephan
2
您还可以转到框架的 Headers 构建阶段,快速查看哪些头文件是公共的、项目的和私有的。 - Jose Ibanez
我从没想过这个简单的任务可能是解决方案,因为我在这里之前已经与此斗争了一个多小时。然而,这正是解决方案,立刻奏效。 - TMc
2
如果我想让这些标题内部,该怎么办? - Raphael
@Raphael:不要将内部头文件导入公共头文件。如果您希望在公共头文件中声明的类中使用来自内部头文件的定义,请考虑在.m文件中导入内部头文件。 - simioliolio
2
这也解决了我的问题!在我的情况下,我的一个依赖于另一个 pod 的 pod 无法导入它,因为存在模块化问题。因此,我将一些头文件作为另一个 pod 的目标包含在内,使用公共模式。这解决了问题! - Chen Li Yong

142
这是一种预期的编译器行为,有非常好的原因。我认为大多数人遇到这些问题是在从“应用程序目标”切换到“框架目标”后开始将C和Objective C头文件添加到框架的“汇总标头”中,期望它具有与“应用程序的桥接标头”相同的行为,但实际上“汇总标头”是为混合Swift、Obj-C框架指定的,并且其目的是将框架在Objective-C或C中拥有的API公开给外界。这意味着我们放置在那里的头文件应该在公共范围内。 不应将其用作向您的框架的Swift代码公开不属于框架组成部分的Objective-C/C头文件的位置。因为在这种情况下,这些头文件也会被公开为我们的框架模块的一部分,而这通常不是我们想要做的,因为它会破坏模块化。(这正是为什么"允许非模块化包含在框架模块中"默认为"NO"的原因) 为了将Objective-C/C库暴露给您的框架Swift代码,我们应该为此类库定义一个单独的Swift模块,然后可以使用标准的Swift "import YourLegacyLibrary"。 让我在一些典型情况下演示这一点:将libxml2嵌入到我们的框架中。 1.首先,您需要创建一个像这样的“module.modulemap”文件: 对于OSX框架:
module SwiftLibXML2 [system] {
  header "/usr/include/libxml2/libxml/xpath.h"
  export *
}

针对iOS框架:

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

它的作用是将头文件及其引用包装在 Swift 模块中,以便 Swift 可以为这些 C 接口生成 Swift 绑定。

2. 然后在您的 xcode 项目目录中创建一个名为 SwiftLibXML2 的文件夹,并将此 module.modulemap 文件放置其中。

3.构建设置中,将$(SDKROOT)/usr/include/libxml2添加到头文件搜索路径中。

4.构建设置中,将$(SRCROOT)/SwiftLibXML2添加到导入路径中。

5. 在项目的 通用选项卡下,将libxml2.tbd 添加到链接的框架和库中。

现在,您可以通过以下方式在需要的地方导入此模块:

import SwiftLibXML2

(如果您想查看更完整的module.map示例,我建议参考达尔文的module.modulemap,路径为/usr/include/module.modulemap,但需要安装Xcode命令行工具才能访问,参考在OS X El Capitan中缺失/ usr / include


1
文件名module.map已经过时,应该重命名为module.modulemap。http://clang.llvm.org/docs/Modules.html#attributes - Hyperbole
如何在Objective-C中导入SwiftLibXML2?谢谢! - Itachi
与任何其他 Obj-C 导入方式相同: #import <libxml/xpath.h>但请确保您已完成第 3-5 步。 - ambientlight
我们尝试过这样做,但是构建产物无法在不同机器之间移动:Objective-C(子)模块显然使用绝对路径链接,导致编译时出现错误,例如使用您提供的框架的应用程序。 - Raphael
错误很可能是特定于您的构建过程,这只是一个模块定义,以便支持模块的 LLVM 语言可以与其他语言进行交互。我认为它本身不会影响您的构建产物,如果我错了,希望社区纠正我。 - ambientlight
显示剩余4条评论

57

以下是如何自动应用快速修复,让您无需在每次 pod install 后手动更改 Pods.xcodeproj 文件。将以下代码片段添加到您的 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

30

对我而言解决方案是进入 target-> build settings->Allow non-modular includes,将Framework Modules中的开关切换为YES!


在这里还使用了Cocoapods。 pod安装后无需执行其他答案中的魔法。 - brainray
3
我已经完成了这一步骤...它起初是有效的...但现在不再有效了...我也包括了pod-install 步骤。但现在它又失败了。还有什么其他的我应该检查吗?我没有看到GoogleMobileAds.Framework作为将头文件更改为Public选项的选项。 - Michael Rowe
这对我没用。仍然在使用Parse时出现错误。Xcode 7.3.1。 - C0D3
我必须重新启动XCode才能使更改生效。 - John Fowler
1
更改此设置会产生什么影响? - nr5

16
Swift 中:

1. 根据以下方式修改您的 Xcode 项目和目标的构建设置:

在框架模块中允许非模块化包含:否

启用位码:是

2. 使用当前最新版本的 GoogleMaps iOS SDK(使用 CocoaPods 获取):

GoogleMaps(1.10.4)

3. 注释有问题的导入:

//import GoogleMaps

4. 创建或修改桥接头文件,并添加导致问题的导入:

[您的 Xcode 项目名称]-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. 清理并重新编译你的Xcode项目。


1
这非常有帮助!而且在使用Cocoapods的GoogleMobilAds框架时表现出色。 - bluenowhere
有关如何创建头文件的更详细信息,请参见:https://dev59.com/floU5IYBdhLWcg3wnn8P#51227304。 - lenooh

15

我想我解决了这个问题。我有一些使用sqlite3的模型代码在一个框架中。在我的情况下,罪魁祸首是<sqlite3.h>。

问题在于,在我的Module / Module.h头文件中,我导入了一个公共头文件,该头文件导入了<sqlite3.h>。解决方法是隐藏所有sqlite3_xxx类型,并确保它们不可见于任何公共.h文件中。所有对sqlite3的直接引用均为私有或项目可见性。例如,我有一个公共单例,上面挂着一些sqlite3_stmt指针。我将那些移动到了一个单独的类中,该类现在只是那个公共头文件中的前向声明。现在我可以构建了。

顺便说一下,CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES设置没有起作用。我尝试在框架和相关项目中都设置了它。虽然我不确定为什么,但这个解决方法是必要的。


这真的很有帮助!在我的情况下,是可达性问题。 - Daniel Brim
4
我很确定这是解决我在尝试将SSZipArchive包含到我的框架模块中时遇到的问题的方法。公共头文件正在导入<zlib.h>并且出现了相同的错误。你能否在某处发布你的源代码,因为我很难让它正常工作,只理解了你回答的部分内容。谢谢! - Bruce

7

不要

#import "MyOtherFramework.h"

#import <MyOtherFramework/MyOtherFramework.h>

6

这个回答已经过时了。

在导入框架时,您必须导入与根头文件共享依赖项的所有头文件。要确保始终如此,请将框架“Headers”文件夹中的所有头文件导入到您的公共头文件路径中。

enter image description here

Swift编译器使用此信息生成非mangled符号的映射以及它们相关联的类型信息。


这似乎违背了拥有框架文件的目的,但对我来说起作用了。Chartboost和RevMob最近都开始使用框架文件而不仅仅是库。将它们头文件中的所有内容复制到我的应用程序头文件中可以解决问题。 - Jason Short
这是唯一的解决方案吗?我有六个框架,每个框架大约有20个头文件。这会导致混乱。还有其他选择吗? - vivin
1
很可能这已经不再相关了,因为它只是用来应对 Xcode 缺陷的一个解决方法。 - seo

3

这个头文件已经分配给了目标,但只被标记为项目可见,将其更改为公共的会导致此错误得到解决。


我该怎么做呢?我的TwitterKit头文件出了问题。 - Vinod Sobale

3

切换到 Build settings > Allow non-modular includes in Framework Modules, 把它的值改为 YES!,对我来说解决了同样的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,