protocolbuffers / protobuf

Protocol Buffers - Google's data interchange format
http://protobuf.dev
Other
65.11k stars 15.43k forks source link

circular header inclusion problem in ObjC version pod? #4301

Closed meritozh closed 6 years ago

meritozh commented 6 years ago

Seems there is a circular header inclusion problem:

GPBWellKnownTypes.h -->  Any.pbobjc.h -->  GPBProtocolBuffers.h
// but also
GPBProtocolBuffers.h --> GPBWellKnownTypes.h

It can compile through pod 'Protobuf', but if I pre build several pods, include this pod, then combine them into one static library, wrap and produce an final static core.framework with custom module.modulemap, it can not work. Xcode raise two error could not build module core and cannot find interface declaration for 'GPBAny'.

module.modulemap:

framework module core {
...

explicit module Protobuf {
    header "Any.pbobjc.h"
    header "Api.pbobjc.h"
    header "Duration.pbobjc.h"
    header "Empty.pbobjc.h"
    header "FieldMask.pbobjc.h"
    header "GPBArray.h"
    header "GPBArray_PackagePrivate.h"
    header "GPBBootstrap.h"
    header "GPBCodedInputStream.h"
    header "GPBCodedInputStream_PackagePrivate.h"
    header "GPBCodedOutputStream.h"
    header "GPBCodedOutputStream_PackagePrivate.h"
    header "GPBDescriptor.h"
    header "GPBDescriptor_PackagePrivate.h"
    header "GPBDictionary.h"
    header "GPBDictionary_PackagePrivate.h"
    header "GPBExtensionInternals.h"
    header "GPBExtensionRegistry.h"
    header "GPBMessage.h"
    header "GPBMessage_PackagePrivate.h"
    header "GPBProtocolBuffers.h"
    header "GPBProtocolBuffers_RuntimeSupport.h"
    header "GPBRootObject.h"
    header "GPBRootObject_PackagePrivate.h"
    header "GPBRuntimeTypes.h"
    header "GPBUnknownField.h"
    header "GPBUnknownFieldSet.h"
    header "GPBUnknownFieldSet_PackagePrivate.h"
    header "GPBUnknownField_PackagePrivate.h"
    header "GPBUtilities.h"
    header "GPBUtilities_PackagePrivate.h"
    header "GPBWellKnownTypes.h"
    header "GPBWireFormat.h"
    header "Protobuf-umbrella.h"
    header "SourceContext.pbobjc.h"
    header "Struct.pbobjc.h"
    header "Timestamp.pbobjc.h"
    header "Type.pbobjc.h"
    header "Wrappers.pbobjc.h"
  }
...
}
thomasvl commented 6 years ago

They are all #import directives, so the compiler make sure to only load the contents once. I'm not completely clear from you description what you are doing, but it sounds like you might be making your own packaging around a few pods? The one that could cause problems is if you are finding the headers via different imports and hence finding them in different spots. GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS is used to make the protobuf header use the #import <Protobuf/[name].h imports. The podpsec helps do this via some *_target_xcconfig directives. If you are manually setting up a target, you could have added an include path into the objectivec/google/protobuf subdirectory instead of setting up the GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS and that is causing the compiler to think there are multiple headers trying to define the same things.

meritozh commented 6 years ago

Yes, I package several pods into one. I don't know how to describe it in detail.

I know Clang will only load header once if it load through #import. I just sort headers then hand code content of explicit module Protobuf in module.modulemap, it can not compile, but if I move header "Any.pbobjc.h" to last line, it can compile. I don't think headers order in modulemap can affect module parsing result, success or not. If I disable clang module, it can compile. Or comment this line, it also can compile: https://github.com/google/protobuf/blob/e34ec6077af141dd5dfc1c334ecdcce3c6b51612/objectivec/GPBProtocolBuffers.h#L44

Defining GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS won't affect result, I have change header path manually.

By process of elimination, I think circular header inclusion may cause some internal error when Clang parsing module. Also I need more testing, will update this issue if I have any process.

meritozh commented 6 years ago

@thomasvl I test with a demo project. It seem circular inclusion will actually cause module parsing problem. Xcode raise error cannot find interface declaration for 'GPBAny'. Demo is here: https://github.com/meritozh/CircularIncludeTest

meritozh commented 6 years ago

no response?

thomasvl commented 6 years ago

no response?

Sorry, I don't think any of us that work on Apple platforms has gotten a chance to dig into this more and other things we work on have been higher priority.

My thought is since the pod has been around for a while without this coming up, it likely is specific to your setup and less likely to be a general problem.

The issue is open so if other people run into it they can also chime in and anyone looking to contribute could try looking at it also.

meritozh commented 6 years ago

Thanks. I'm interested in this problem. Maybe I will make a PR to fix it if I find a proper solution.