"Include of non-modular header"......其他地方未回答



假设我有一个socket框架,它定义了一个Obj-C协议SocketResponder。然后,假设在我的服务框架中,它依赖于Sockets框架并与之链接。我的服务框架混合了Obj-C和一点Swift代码,其中一个Obj-C类型,比如networktimerresponder符合SocketResponder协议,所以:

// Services/NetworkTime.h
#import <Sockets/Sockets.h>
@interface NetworkTimeResponder: <SocketResponder>
…

这看起来非常直接,但是编译器给出了错误:Include of non-modular header inside framework module 'Services.NetworkTime': "...Sockets.framework/Headers/Sockets.h"

我读了一大堆"解决方案"。(StackOverflow的每一页结果),但没有一个适用于这种情况。

我相信我理解的问题是,如果应用程序然后导入服务和套接字框架的头,那么实际上有两个定义的类型在套接字框架的头,所以它可能是有问题的。

但我真的很困惑,因为这有什么不同,说,AppKit导入基础和声明类型符合NSCopying,我的应用程序导入AppKit和基础?这个问题似乎只出现在模块的情况下,这是因为我的一个框架中有一点Swift ?我不熟悉模块的根本区别和影响。

有人能解释一下吗?

TLDR:被导入和链接的目标框架,也需要是一个模块。

我使用的这些项目都是十年前开始的,所以它们的编译器设置随着时间的推移而变化。Both "定义模块"and "启用C和Obj-C模块"(DEFINES_MODULECLANG_ENABLE_MODULES)off。然而,在我的一个框架中添加了一点Swift代码后,Xcode将DEFINES_MODULECLANG_ENABLE_MODULES设置为YES。

现在,如果"模块"框架,在它的任何公共头文件中,从"非模块"中导入任何公共头文件框架,这是当这个错误弹出。

归根结底就是"嘿,这个目标是一个模块,而那个不是。">

为什么这是个问题?这就深入探讨了模块存在的部分原因。如果我们看看CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES(一些不太知情的人会建议打开它),那么答案就变得更清晰了:

"启用此设置允许从使用非模块化包含在框架模块中。这本质上是不安全的,就像头文件一样在任何导入的客户端使用时可能导致重复的定义框架和非模块化都包含。">

如果你知道头include是如何工作的,并且你理解为什么C/c++在头文件中使用大量的#ifdef来避免重复声明,那么关键是:模块避免了所有这些令人头痛的事情,并保证只存在一个声明。通过"允许在框架模块中包含非模块"您现在重新引入了具有副本的可能性。

https://clang.llvm.org/docs/Modules.html

所以这个故事的寓意是,如果给定的目标是一个模块,那么它在公共头文件中#导入的所有内容也应该是一个模块。

相关内容

  • 没有找到相关文章

最新更新