alexeyxo / protobuf-objc

Google Protocol Buffers for Objective-C
http://protobuf.io/#objc
Apache License 2.0
670 stars 135 forks source link

Are packages and options available? #83

Open lolgear opened 8 years ago

lolgear commented 8 years ago

Not sure if it is a bug or my dirty hands, but..

I followed these steps:

  1. brew install protobuf
  2. git clone <this repo>
  3. ./scripts/build.sh
  4. fill up all needed information for proto files.
  5. ( somewhere between previous steps: link protoc to correct folder /usr/local/bin ) ( Also I added project via cocoapods, but it doesn't matter )

Ok, I try to run protoc --plugin=/usr/local/bin/protoc-gen-objc *.proto --objc_out="./"

Several issues appeared.

First: Can't use options

    package ponyprotobuffed;

    import "objectivec-descriptor.proto";
    option (google.protobuf.objectivec_file_options).package = "PonyProtobuffed";
    option (google.protobuf.objectivec_file_options).class_prefix = "PNP";
    option (google.protobuf.objectivec_file_options).relax_camel_case = true;

No luck with class prefix or package. These options not found. File "objectvicec-descriptor.proto" not found.

If I remove all options and leave only

option class_prefix="PNP" or option objc_class_prefix="PNP"

result is the same - no luck.

package doesn't work well (names aren't prefixed by package name).

Second: Can't use default value for enum.

enum PNPPonyProtobuffedPonyType {
   Cute
   Awesome
}

message Pony {
    required PNPPonyProtobuffedPonyType ponyType = 2 [default = PNPPonyProtobuffedPonyTypeCute]
}

Unknown value PNPPonyProtobuffedPonyTypeCute or Cute.

E-B-Smith commented 8 years ago

The obj-c options like class prefix are added only for the generated obj-c code.

So in your protobuf definitions, if you define:

enum PonyType {
   Cute
   Awesome
}

message Pony {
    required PonyType ponyType = 2 [default = Cute];
}

The generated obj-c code will be:

typedef NS_ENUM(SInt32, PNPPonyType) {
     PNPPonyTypeCute = 0
    ...
};

@interface PNPPony : NSObject {
   SInt32 ponyType;
   ...
}

The obj-c definitions only effect obj-c code generation because they're specific to the idiosyncratic way that people expect obj-c code to be written.

If you want the class prefix to be global for all code generation across, say C++ or go, you need to add that yourself in the proto definitions.

lolgear commented 8 years ago

@E-B-Smith could you post more complex example with class_prefix and other options like package name?

For example, there are two files: ponyEnums.proto and pony.proto

I want to generate files with prefix PNP and in package PonyProtobuffed. So, the whole prefix will be PNPPonyProtobuffed.

files are

ponyEnums.proto

enum PonyType {
   Cute = 0;
   Awesome = 1;
}

pony.proto

message Pony {
    required PonyType ponyType = 2 [default = Cute];
}

Now they would be generated without any prefix.

UPD: question about scattered enums.

if several enums are specified as properties in different messages, how they should be declared in different .proto files?

In my example it should be, for example, PonyLover message with pony type.

ponyLover.proto

message PonyLover {
    required PonyType ponyType = 2 [default = Cute];
}

Should I duplicate declaration of ponyType in each .proto file where it needed?

UPD2: I see something interesting: "objectivec-descriptor.proto" file lives in protobuf-objc/src/compiler/google/protobuf/objectivec-descriptor.proto. But I didn't have access to it from my project directory.

E-B-Smith commented 8 years ago

The options should be the header in each of your proto files.

Also, you can import PonyEnums.proto in your Pony.Proto file:

Pony.proto:

package ponyprotobuffed;

import "objectivec-descriptor.proto";
option (google.protobuf.objectivec_file_options).package = "PonyProtobuffed";
option (google.protobuf.objectivec_file_options).class_prefix = "PNP";
option (google.protobuf.objectivec_file_options).relax_camel_case = true;

import "PonyEnums.proto";

message Pony {
    required PonyType ponyType = 2 [default = Cute];
}
E-B-Smith commented 8 years ago

Also, the "objectivec-descriptor.proto" describes the obj-c extensions to protobuf and isn't part of your project.

lolgear commented 8 years ago

@E-B-Smith

yes, thanks, latest bug that still exists: I cloned repository in directory different from project directory. And now I can not access to objectivec-descriptor.proto file.

--proto-path option doesn't help.

protoc --plugin=/usr/local/bin/protoc-gen-objc pony.proto --objc_out="./"

It lays somewhere depths of protobuf-objc: protobuf-objc/src/compiler/google/protobuf/objectivec-descriptor.proto

If I try to linked it via ln -s it fails with error: no declaration of google.FileOptions.

E-B-Smith commented 8 years ago

(This answer was updated with more info.)

Here's an example project that builds the Pony protobuf. You can download and try it out:

PrettyPonies.zip

Executing the script 'make-ponies' will make obj-c and go files (as a cross compile example) and place the source files in the 'Build' folder.

Here's the PrettyPonies project folder layout:

make-ponies
Pony.proto
PonyEnums.proto
objectivec-descriptor.proto
google/protobuf/descriptor.proto

Here's the bash compile script:

#!/bin/bash
set -euo pipefail

#  Make Pony protobufs:

mkdir -p ./Build/golang
mkdir -p ./Build/obj-c
mkdir -p ./Build/java

protoc Ponies.proto PonyEnums.proto \
    --go_out=./Build/golang \
    --objc_out=./Build/obj-c \
    --java_out=./Build/java
lolgear commented 8 years ago

Could you make PR as a result of this confusing issue? ( Maybe description in readme and another example project ) However, I think it is solved and ready for pony ride!

E-B-Smith commented 8 years ago

The unexpected project file locations are needed so that the java cross compile works.

Java expects files in particular places and is pretty inflexible about file locations.

Good luck with your project!