【问题标题】:Building a wrapper framework for C++ project in Xcode在 Xcode 中为 C++ 项目构建包装框架
【发布时间】:2018-01-19 05:22:32
【问题描述】:

所以,我有一个 C++ 项目,我想将它放入一个框架中,该框架将充当 C++ 代码的包装器(用 Objective-C/C++ 编写),以便以后可以在 Swift 或 Objective 中使用它-C 项目,只需将框架添加到应用程序即可。

到目前为止我所取得的成就:

  • 创建了所有包装器
  • 在构建阶段暴露了包装器的公共标头
  • 在构建阶段添加了一个运行脚本,以简单地将所有 C++ 标头(保留其文件目录结构)复制到框架的目录中,以便使用框架的应用程序可以使用它们。我这样做而不只是将它们放在构建阶段的标题字段中的原因是因为有很多文件和文件夹,这样做需要我将每个标题更改为 #include "LocalHeader.h" 而不是它是如何目前写为#include "CppRootFolder/Subfolder/Header.h"。我也不想这样做,因为我想保持 C++ 文件不变。

问题:

一切似乎都运行良好,除了在构建实际应用程序时,xcode 会出错,说它在文件结构中找不到文件。为了说明我的意思,我有以下几点:

  • 框架的伞形文件将 #include "CppRootFolder/umbrella.h"(c++ 伞形文件)
  • 在 CppRootFolder/umbrella.h 中,我有几个 #include "CppRootFolder/Subfolder/Header.h"
  • 每个子文件夹中的每个标题都包含从 c++ 代码的根文件夹引用它们的其他标题。

我对此的看法:

我似乎很清楚,问题在于编译器需要从 c++ 代码的根文件夹中找到头文件。所以,在实际的 App 中,在构建设置中,我将头搜索路径添加到:$BUILT_PRODUCTS_DIR/FrameworkName.framework/Headers,这是我使用脚本复制所有头的位置。但是,构建失败并产生大量随机错误,无法识别已定义的类型。

关于如何让它发挥作用的任何想法?

谢谢

更新(日志):

<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/Box2D.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:
#import "World.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:
#import "Box2D/Box2D.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:34:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:34:
#include "Box2D/Common/b2Settings.h"
         ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Settings.h:153:8: error: must use 'struct' tag to refer to type 'b2Version'
extern b2Version b2_version;
       ^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "Headers/Box2D.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D.h:17:
#import "World.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:9: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/World.h:10:
#import "Box2D/Box2D.h"
        ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:35:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Box2D.h:35:
#include "Box2D/Common/b2Draw.h"
         ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Draw.h:22:10: note: in file included from /Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Draw.h:22:
#include "Box2D/Common/b2Math.h"
         ^
/Users/luis/Library/Developer/Xcode/DerivedData/Project-dgathvjusrdgslfvqqcvkeqyjzcb/Build/Products/Debug-iphoneos/Box2D.framework/Headers/Box2D/Common/b2Math.h:28:31: error: unexpected type name 'int32': expected expression
        int32 ix = *reinterpret_cast<int32*>(&x);

【问题讨论】:

  • 您是在为 macOS 还是 iOS 开发应用程序? CPU架构不一样。您是否尝试过创建库项目?或者您是否将 C++ 和 Objective-C++ 代码放在同一个应用程序项目中? Objective-C++ 的文件扩展名是 .mm 而不是 .m 吗?
  • 当您遇到构建问题时,请始终复制粘贴错误消息。有两个原因:更容易理解你的问题(我们不依赖你的解释),如果有人有类似的问题,更容易谷歌搜索。
  • 对于iOS,这是一个cocoa touch框架项目,添加到一个ios app项目中,c++和obj-c++代码一起在framework项目中,obj-c++的扩展名是.mm
  • @MarekR 构建日志似乎有点随机,这就是我决定不粘贴它的原因,但如果你愿意,我可以这样做
  • 它们不能是随机的,这只是表明你不了解它们。

标签: c++ ios objective-c xcode frameworks


【解决方案1】:

当你编写一个包装器时,C++ 不应该在外面可见。 所以#include "cppHedarFile.h" 不应该在包装器之外访问,否则在Objective C 代码中使用C++ 时会出错。

所以不应该有 C++ 头文件的伞头文件。

请提供技术细节:您看到的复制粘贴错误消息。您对错误的解释可能会产生误导。


除了这一行,您没有粘贴所有内容:
/Box2D.framework/Headers/Box2D/Common/b2Math.h:28:31: error: unexpected type name 'int32': expected expression
    int32 ix = *reinterpret_cast<int32*>(&x);

告诉我我是对的。 很可能您包含来自 Objective C 文件 *.m 的 C++ 头文件。 对于此类文件,无法访问 C++ 标准标头,这就是无法识别类型 int32 的原因。

就像我在乞讨时写的那样。当您围绕 C++ 编写 Objective C 包装器时,禁止包含来自公共头文件的 C++ 头文件。 您只能从仅由*.mm 使用的内部标头中形成*.mm 文件。 这样包装器就可以完成他们的工作并从包装器的用户那里处理 C++。


例子

公开标头KXSomeClass.h:

@interface KXSomeClass : NSObject

@property (nonatomic, readonly) BOOL allowed;

- (NSUInteger)someAction:(NSString *)s;

@end

私人标头KXSomeClass+Internal.h

// this header is used only by wrappers
#import "KXSomeClass.h"
#include <memory>
@interface KXSomeClass ()

- (instancetype)initWithNativeSomeClass:(const std::shared_ptr<SomeClass>&)nativeObject;

@end

实现KXSomeClass.mm

#import "KXSomeClass+Internal.h"

@interface KXSomeClass ()
@property (assign, nonatomic) std::shared_ptr<SomeClass> native;
@end

#import "KXSomeClass+Internal.h"
#include "cpp/SomeClass.h"

@implementation CSCapability

- (instancetype)initWithNativeSomeClass:(const std::shared_ptr<SomeClass>&)nativeObject
{
    if (self = [super init]) {
         _native = nativeObject;
    }
    return self;
}

- (NSUInteger)someAction:(NSString *)s
{
    return _native->SomeAction(s.UTF8String);
}

- (BOOL)allowed
{
    return _native->Allowed();
}

@end

【讨论】:

  • 对不起,我想我没有正确地写我所做的:我的意思是伞头包含一个头(链接到一个 .mm 文件)并且这个类中有 c++ 对象,所以在接口(头文件)中,我包含了识别 c++ 对象所需的 c++ 头文件。在接口中的实例变量声明期间,我还能如何使用 c++ 类?
  • 太棒了!还有一个问题,添加所有这些额外的类别和标题会影响性能吗?这与在实际公共标头中使用 __cplusplus 相比如何?
  • 它不是一个类别而是扩展名(注意没有名字)。不,没有额外的开销,这只是将需要 C++ 的 API 与不需要 C++ 的 API 分开。
猜你喜欢
  • 2015-12-20
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 2019-02-03
  • 2017-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多