【发布时间】:2012-05-03 21:20:45
【问题描述】:
是 iOS 的元语法静态库。 . .
http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers
。 . .与常规的旧 C++ 编译的原型文件兼容吗?我确实不想使用生成 Obj-C 的捆绑编译器。
有没有什么方法可以编译谷歌为 iOS 提供的库?
【问题讨论】:
标签: c++ ios protocol-buffers
是 iOS 的元语法静态库。 . .
http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers
。 . .与常规的旧 C++ 编译的原型文件兼容吗?我确实不想使用生成 Obj-C 的捆绑编译器。
有没有什么方法可以编译谷歌为 iOS 提供的库?
【问题讨论】:
标签: c++ ios protocol-buffers
好的。在这种情况下,元语法库(或任何其他第 3 方库)似乎是不必要的。您可以直接将 Google 源代码添加到您的项目中。我在 google 讨论组中找到了 Nicola Ferruzzi 的以下答案。 . .
原来的答案在这里。 . .
http://groups.google.com/group/protobuf/browse_thread/thread/ca4218d7db144252
这个答案的内容包含在下面的图片中,以便永久记录......
编辑
自从今晚第一次尝试此操作以来,除了下面列出的步骤之外,我还需要执行几个步骤(这适用于 protobuf 2.5.0)。
find . -name "*unittest*" -exec rm -rf {} \; 的 shell 中使用以下命令
testing的文件夹
stringprintf.cc 中注释掉#include <google/protobuf/testing/googletest.h>
我在我的应用程序中使用最新版本.. 你真的不需要 objc direct 支持,如果你熟悉 C++,只有一点 你必须从 std::string 传递给 NSData ,反之亦然。而它的 很简单。
编译和测试我发现的最简单的方法就是导入 我自己的项目中的整个谷歌目录:)(第二次你可以 制作你自己的框架,但为了测试这个过程就可以了)
- 下载最新版本
- autogen 配置和制作就像您刚刚为 macosx 构建一样(您需要命令行工具)。这样你就得到了 protoc
二进制文件和 macosx 库(你不需要)- 打开你的 Xcode iOS 项目
- 将“新文件”添加到您的项目并选择 google 目录
- 将 google headers 目录添加到您的附加包含目录中
- 将 protobuffer src 目录中的 config.h 添加到您的应用中
- 从 google 组中删除所有包含 unitest 的内容 :)
- 从 google 组中删除编译器和 java 的东西;
您应该能够在没有任何链接错误的情况下进行编译。为你带来 一个想法这是我直接编译的
然后你可以使用 protoc 为你的生成 c++ 源文件 协议。要将它们与 objc 一起使用,您必须将源重命名为 文件“mm”然后你可以做类似的事情
序列化到 NSDATA
假设您的消息称为 Packet
- (NSData *)getDataForPacket:(Packet *)packet { std::string ps = packet->SerializeAsString(); return [NSData dataWithBytes:ps.c_str() length:ps.size()];从 NSDATA 读取
- (Packet *)getPacketFromNSData:(NSData *)data { char raw[[data length]]; Packet *p = new Packet; [data getBytes:raw length:[data length]]; p->ParseFromArray(raw, [data length]); return p; }
【讨论】:
config.h 中的“tr1”。另外,如果编译失败message.cc,在message.cc文件中添加include <iostream>。您可以通过将以下行添加到您的 Podfile 来为使用 Cocoapods 的 Xcode 5 项目添加对 Google Protocol Buffers 的支持。
pod 'GoogleProtobuf', '~> 2.5.0'
这会将 C++ 版本的 protobuf 代码放入项目的 Pod 中。它还将在您的项目中的文件夹Pods/GoogleProtobuf/bin/protoc 中添加protoc 编译器。
您可以在项目中创建自定义构建规则,自动将.proto 文件转换为.ph.{h,cc} 文件。我是这样做的:
将构建规则设置为“处理名称匹配的源文件:*.proto 使用自定义脚本”。该脚本应包括以下内容:
cd ${INPUT_FILE_DIR}
${SRCROOT}/Pods/GoogleProtobuf/bin/protoc --proto_path=${INPUT_FILE_DIR} ${INPUT_FILE_PATH} --cpp_out=${INPUT_FILE_DIR}/cpp
将输出文件设置为包括以下内容:
$(INPUT_FILE_DIR)/cpp/$(INPUT_FILE_BASE).pb.h
$(INPUT_FILE_DIR)/cpp/$(INPUT_FILE_BASE).pb.cc
您在项目中包含的任何 .proto 文件现在都将自动转换为 C++,然后作为构建的一部分进行编译。
【讨论】:
我想根据实际问题,我的评论值得作为答案发布:
我正在使用Booyah提供的原生Obj代码生成的略微修改版本
它支持开箱即用的重复字段,但为了使用 ObjC 快速枚举,您需要将 PBArray 类型(基本上是类型化的 c 缓冲区)转换为它所代表的 NSObject 数组 - NSNumber 或 protobuf 消息对象。您可以在 this change: 中看到更新后的快速枚举代码示例。您还可以在 PBArray 上添加一个名为 toObjects 的类别。
我只是用-fno-objc-arc标记生成的代码,但是你可以从booyah pull requests获得arc和2.5的支持。
这些说明非常适合设置,但如果人们想要更明确地说明我使用的类别、我如何构建 protobuf-objc 插件、如何获得对类前缀的支持(例如 IXMyProtoMessage 而不是 MyProtoMessage)或者我如何生成代码让我知道,我会尽量留出时间来写一篇文章。我将它与超过 50 个具有大量跨项目依赖项的 proto 文件一起使用。
该库的一个弱点是它在生成的代码中不包含典型的 Protobuf 反射 api,因此执行诸如将消息转换为 NSDictionary 之类的操作将不得不对 objC 运行时做一些骇人听闻的事情(代码没有t 遵循典型的 KV 合规性)或从具有反射 api 的 protos 编写自定义代码生成器(我使用 python + jinja2 完成了此操作)。或者 - 更好且难度相似的,将反射 API 添加到代码生成器中;)。
【讨论】:
PBArray 转换为NSArray 的扩展程序?
编辑:我之前回答过这个问题,但被版主删除了。所以我已经包含了教程中的一些代码。
一个教程和上面贴的答案几乎一样 - Using Google Protocol Buffers in Objective-C on iOS and the Mac
按照 learnvst 的答案中给出的步骤,并参考 cmets 中的陷阱。我遵循完全相同的步骤,除了
将 google headers 的目录添加到您的附加包含目录中 我在标题搜索路径中添加了 src/ 目录,而不是 google 目录。
另外,当我做#import xyz.pb.h 时,项目还没有建立。当我将我的 .m 文件重命名为 .mm 时,我能够构建。这一点在教程中很巧妙地提到了:P。
基本上,导入任何 .pb.h 文件的任何 .m 文件都应使用扩展名 .mm
这是教程中的一些内容 -
原文件
package kotancode;
enum ZombieType {
SLOW = 0;
FAST = 1;
}
message ZombieSighting {
required string name = 1;
required double longitude = 2;
required double latitude = 3;
optional string description = 4;
required ZombieType zombieType = 5 [default = SLOW];
}
ZombieSightingMessage.h
// -- ZombieSightingMessage.h - note my C++ object is not in the public interface.
#import <Foundation/Foundation.h>
@interface ZombieSightingMessage : NSObject
- (void)doSomething;
@end
ZombieSightingMessage.mm
// -- ZombieSightingMessage.mm
#import <UIKit/UIKit.h>
#import "ZombieSightingMessage.h"
#import "zombie.pb.h"
@implementation ZombieSightingMessage
- (void)doSomething {
// Doing random stuff with a UIView here to show the mixing
// of C++ and Objective-C/Cocoa syntax in the same file...
UIView *uiView = [[UIView alloc] init];
[uiView setCenter:CGPointMake(20, 10)];
// instantiate my protobuf-generated C++ class.
kotancode::ZombieSighting *zombieSighting = new kotancode::ZombieSighting();
zombieSighting->set_name("Kevin");
zombieSighting->set_description("This is a zombie");
zombieSighting->set_latitude(41.007);
zombieSighting->set_longitude(21.007);
zombieSighting->set_zombietype(kotancode::ZombieType::FAST);
// Some small tomfoolery required to go from C++ std::string to NSString.
std::string x = zombieSighting->DebugString();
NSString *output = [NSString stringWithCString:x.c_str() encoding:[NSString defaultCStringEncoding]];
NSLog(@"zombie: %@", output);
// Instantiate another zombie from the previous zombie's raw bytes.
NSData *rawZombie = [self getDataForZombie:zombieSighting];
kotancode::ZombieSighting *otherZombie = [self getZombieFromData:rawZombie];
// Dump the second zombie so we can see they match identically...
NSString *newOutput = [NSString stringWithCString:otherZombie->DebugString().c_str() encoding:[NSString defaultCStringEncoding]];
NSLog(@"other zombie: %@", newOutput);
// Grimace all you want, but this is C++ and we need to clean up after ourselves.
free(zombieSighting);
free(otherZombie);
}
// Serialize to NSData. Note this is convenient because
// we can write NSData to things like sockets...
- (NSData *)getDataForZombie:(kotancode::ZombieSighting *)zombie {
std::string ps = zombie->SerializeAsString();
return [NSData dataWithBytes:ps.c_str() length:ps.size()];
}
// De-serialize a zombie from an NSData object.
- (kotancode::ZombieSighting *)getZombieFromData:(NSData *)data {
int len = [data length];
char raw[len];
kotancode::ZombieSighting *zombie = new kotancode::ZombieSighting;
[data getBytes:raw length:len];
zombie->ParseFromArray(raw, len);
return zombie;
}
@end
编辑:我使用的是 Xcode 4.5。即使在我按照所有步骤操作之后,我仍然收到链接器错误。
找不到架构 i386 的符号
因此,我无法在模拟器上运行代码。但它适用于实际设备
【讨论】: