apollographql / apollo-kotlin

:rocket:  A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.
https://www.apollographql.com/docs/kotlin
MIT License
3.74k stars 653 forks source link

Linking globals named 'OBJC_CLASS_$_GatewayApiLong': symbol multiply defined! #4238

Closed sentinelweb closed 1 year ago

sentinelweb commented 2 years ago

Summary I am testing using the Kotlin Multiplatform version of Apollo. Our schema works fine when compiling for android but we are getting the above error when building iOS library : ./gradlew clean gateway_api:iosX64MainBinaries

Version 3.3.2

Description Add context about the problem here. How it happened and how to reproduce it:

Our schema has no scalar Long declaration but there are quite a few places that use an adhoc scalar Long definition in fields (e.g. below)

I am guessing this is the cause of the above error so I wanted to check if simply declaring a scalar Long in the schema and using it for fields would be the correct solution? As it might quite a big change for our organization.

Or is there some compilation flag i could add that would ignore this error?

i have also tried adding codegenModels.set("responseBased") and modifying our code to use this codegen structure - but i ended up getting the same error after the change.

{
  "name": "netUnitsSold",
  "description": "Net unit sold across aggregation",
  "args": [],
  "type": {
    "kind": "SCALAR",
    "name": "Long",
    "ofType": null
  },
  "isDeprecated": false,
  "deprecationReason": null
},

This is the error stacktrace when executing ./gradlew clean gateway_api:iosX64MainBinaries - same for pod install in XCode.

> Task :gateway_api:linkPodDebugFrameworkIosX64 FAILED
e: Compilation failed: Linking globals named 'OBJC_CLASS_$_GatewayApiLong': symbol multiply defined!

 * Source files: 
 * Compiler version info: Konan: 1.6.21 / Kotlin: 1.6.21
 * Output kind: FRAMEWORK

e: java.lang.Error: Linking globals named 'OBJC_CLASS_$_GatewayApiLong': symbol multiply defined!
        at org.jetbrains.kotlin.backend.konan.llvm.DefaultLlvmDiagnosticHandler.handle(diagnosticReport.kt:24)
        at org.jetbrains.kotlin.backend.konan.llvm.LlvmDiagnosticCollector.flush(diagnostics.kt:36)
        at org.jetbrains.kotlin.backend.konan.llvm.LinkModulesKt.llvmLinkModules2(linkModules.kt:36)
        at org.jetbrains.kotlin.backend.konan.llvm.objc.LinkObjCKt.linkObjC(linkObjC.kt:32)
        at org.jetbrains.kotlin.backend.konan.CompilerOutputKt.linkAllDependencies(CompilerOutput.kt:81)
        at org.jetbrains.kotlin.backend.konan.CompilerOutputKt.linkBitcodeDependencies(CompilerOutput.kt:125)
        at org.jetbrains.kotlin.backend.konan.llvm.BitcodePhasesKt$linkBitcodeDependenciesPhase$1.invoke(BitcodePhases.kt:349)
        at org.jetbrains.kotlin.backend.konan.llvm.BitcodePhasesKt$linkBitcodeDependenciesPhase$1.invoke(BitcodePhases.kt:346)
        at org.jetbrains.kotlin.backend.konan.KonanLoweringPhasesKt$makeKonanModuleOpPhase$1.invoke(KonanLoweringPhases.kt:65)
        at org.jetbrains.kotlin.backend.konan.KonanLoweringPhasesKt$makeKonanModuleOpPhase$1.invoke(KonanLoweringPhases.kt:63)
        at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
        at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
        at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
        at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:22)
        at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
        at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
        at org.jetbrains.kotlin.backend.common.phaser.NamedCompilerPhase.invoke(CompilerPhase.kt:96)
        at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.invokeToplevel(CompilerPhase.kt:43)
        at org.jetbrains.kotlin.backend.konan.KonanDriverKt.runTopLevelPhases(KonanDriver.kt:34)
        at org.jetbrains.kotlin.cli.bc.K2Native.doExecute(K2Native.kt:88)
        at org.jetbrains.kotlin.cli.bc.K2Native.doExecute(K2Native.kt:37)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:91)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:43)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:93)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:71)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:40)
        at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:168)
        at org.jetbrains.kotlin.cli.bc.K2Native$Companion$mainNoExitWithGradleRenderer$1.invoke(K2Native.kt:412)
        at org.jetbrains.kotlin.cli.bc.K2Native$Companion$mainNoExitWithGradleRenderer$1.invoke(K2Native.kt:411)
        at org.jetbrains.kotlin.util.UtilKt.profileIf(Util.kt:22)
        at org.jetbrains.kotlin.util.UtilKt.profile(Util.kt:16)
        at org.jetbrains.kotlin.cli.bc.K2Native$Companion.mainNoExitWithGradleRenderer(K2Native.kt:411)
        at org.jetbrains.kotlin.cli.bc.K2NativeKt.mainNoExitWithGradleRenderer(K2Native.kt:666)
        at org.jetbrains.kotlin.cli.utilities.MainKt$daemonMain$1.invoke(main.kt:62)
        at org.jetbrains.kotlin.cli.utilities.MainKt$daemonMain$1.invoke(main.kt:62)
        at org.jetbrains.kotlin.cli.utilities.MainKt.mainImpl(main.kt:17)
        at org.jetbrains.kotlin.cli.utilities.MainKt.daemonMain(main.kt:62)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:567)
        at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner.runInProcess(KotlinToolRunner.kt:136)
        at org.jetbrains.kotlin.compilerRunner.KotlinToolRunner.run(KotlinToolRunner.kt:81)
        at org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink.compile(KotlinNativeTasks.kt:657)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:567)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
        at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:242)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:227)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:210)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:193)
        at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:171)
        at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
        at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:61)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:42)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
        at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
        at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:180)
        at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
        at org.gradle.internal.Either$Right.fold(Either.java:175)
        at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
        at java.base/java.util.Optional.orElseGet(Optional.java:362)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:249)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:204)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:83)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:54)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
        at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:287)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
        at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:144)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:830)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':gateway_api:linkPodDebugFrameworkIosX64'.
> Compilation finished with errors
BoD commented 2 years ago

Hi! Thanks for reporting this!

This doesn't immediately ring a bell 🤔

However I'm not sure I understand what you mean by "Our schema has no scalar Long" - if the netUnitsSold field shown above is of type Long then it must be declared in the schema? On the other hand, if that wasn't the case, Apollo Kotlin should have emitted something like "Unknown type Long".

In any case if possible, it would help a lot if you could share a project so that we can reproduce and investigate this (if this can't be shared publicly feel free to send it to benoit.lubek@apollographql.com) 🙏

sentinelweb commented 2 years ago

hi, yes sorry it is actually declared i missed it before.

In the header file generated i can see that interface (GatewayApiLong) is actually generated twice - just have to check with the org what i can share. so i'll get back soon.

thanks for the quick response.

BoD commented 2 years ago

Thanks! Are you in a multi-module setup by any chance (wondering if it could be a type clash).

sentinelweb commented 2 years ago

Each schema is in it's own kmp module. The other module is very simple - it compiles fine and I can use it in the ios app. This gateway_api module has the bulk of the operations though.

sentinelweb commented 2 years ago

in the generated GatewayApi.h the conflicting interfaces are:

__attribute__((swift_name("KotlinLong")))
@interface GatewayApiLong : GatewayApiNumber
- (instancetype)initWithLongLong:(long long)value;
+ (instancetype)numberWithLongLong:(long long)value;
@end;

and

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Long")))
@interface GatewayApiLong : GatewayApiBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@property (class, readonly, getter=companion) GatewayApiLongCompanion *companion __attribute__((swift_name("companion")));
@end;

__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("Long.Companion")))
@interface GatewayApiLongCompanion : GatewayApiBase
+ (instancetype)alloc __attribute__((unavailable));
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable));
+ (instancetype)companion __attribute__((swift_name("init()")));
@property (class, readonly, getter=shared) GatewayApiLongCompanion *shared __attribute__((swift_name("shared")));
@property (readonly) GatewayApiApollo_apiCustomScalarType *type __attribute__((swift_name("type")));
@end;

So possibly the declared scalar Long in our schema is conflicting with the KotlinLong from the default KotlinNumber interfaces?

__attribute__((swift_name("KotlinNumber")))
@interface GatewayApiNumber : NSNumber
- (instancetype)initWithChar:(char)value __attribute__((unavailable));
- (instancetype)initWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
- (instancetype)initWithShort:(short)value __attribute__((unavailable));
- (instancetype)initWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
- (instancetype)initWithInt:(int)value __attribute__((unavailable));
- (instancetype)initWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
- (instancetype)initWithLong:(long)value __attribute__((unavailable));
- (instancetype)initWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
- (instancetype)initWithLongLong:(long long)value __attribute__((unavailable));
- (instancetype)initWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
- (instancetype)initWithFloat:(float)value __attribute__((unavailable));
- (instancetype)initWithDouble:(double)value __attribute__((unavailable));
- (instancetype)initWithBool:(BOOL)value __attribute__((unavailable));
- (instancetype)initWithInteger:(NSInteger)value __attribute__((unavailable));
- (instancetype)initWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
+ (instancetype)numberWithChar:(char)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedChar:(unsigned char)value __attribute__((unavailable));
+ (instancetype)numberWithShort:(short)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedShort:(unsigned short)value __attribute__((unavailable));
+ (instancetype)numberWithInt:(int)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedInt:(unsigned int)value __attribute__((unavailable));
+ (instancetype)numberWithLong:(long)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedLong:(unsigned long)value __attribute__((unavailable));
+ (instancetype)numberWithLongLong:(long long)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedLongLong:(unsigned long long)value __attribute__((unavailable));
+ (instancetype)numberWithFloat:(float)value __attribute__((unavailable));
+ (instancetype)numberWithDouble:(double)value __attribute__((unavailable));
+ (instancetype)numberWithBool:(BOOL)value __attribute__((unavailable));
+ (instancetype)numberWithInteger:(NSInteger)value __attribute__((unavailable));
+ (instancetype)numberWithUnsignedInteger:(NSUInteger)value __attribute__((unavailable));
@end;

i don't know if that helps - still checking about the schema but it might take a few days .. sorry

BoD commented 2 years ago

Ooh good catch, yes this is probably the culprit. Can you try to rename the Long scalar definition and usage to, for instance, MyLong in your schema, to see if that resolves the issue?

By the way, I noticed above you showed part of your schema in json, but you can convert it to SDL instead, which is more user-friendly:

./gradlew convertApolloSchema --from=src/main/graphql/schema.json --to=src/main/graphql/schema.graphqls
sentinelweb commented 2 years ago

It a corporate schema. So company wide. Probably you might need to change the namespaciing a bit? It's not urgent tho.

Possibly the numerical interfaces could be Klong etc? Just an idea..

sentinelweb commented 2 years ago

Eg

__attribute__((swift_name("KotlinLong")))
@interface GatewayApiKotlinLong : GatewayApiNumber 
BoD commented 2 years ago

In this PR, we're adding an (experimental) @targetName directive that you can set on your scalar declaration (by extending it), which will be used to chose the corresponding generated Kotlin type name. You will be able to use it like this:

# In a new file named extra.graphqls, next to your schema.graphqls

extend scalar Long @targetName(name: "GatewayApiLong")

In the meantime, you can still rename the Long scalar in your schema, locally on your project, and that should probably work.

sentinelweb commented 2 years ago

yes looks like that should work. I'm not sure how common it is for users to declare a scalar type with a name the same as a kotlin type (Integer, Long, Char, etc). I guess this would work for all those cases though.

when do you think it would be released? it not really urgent atm though. as we are just testing things out.

BoD commented 2 years ago

The @targetName directive has just been merged, so this will be in the next release, in the meantime it can be tried out with the snapshots.

sentinelweb commented 2 years ago

on nice ... i'll give it a whirl

sentinelweb commented 2 years ago

So i am trying this out. I have got the 3.4.1-SNAPSHOT in the project - i can see it loaded

I have extra.graphqls:

# In a new file named extra.graphqls, next to your schema.graphqls

extend scalar Long @targetName(name: "GatewayApiMyLong")

but it shows errors:

The extension 'Long' type is missing its base underlying type
'Long' tried to use an undeclared directive 'targetName'

Wondering if you have any suggestions for checking it?

BoD commented 2 years ago

Thanks for trying it out! Just making sure, are these messages you're seeing in the IDE? It's possible the directive is not known to the GraphQL plugin, so it highlights it as an error, but it will still compile OK. You can have a look at the generated code which should be in the build/generated/source/apollo/ folder of your module.

sentinelweb commented 2 years ago

it still the same error - so looks like it not getting picked up for some reason

./gradlew clean gateway_api:iosX64MainBinaries

e: Compilation failed: Linking globals named 'OBJC_CLASS_$_GatewayApiLong': symbol multiply defined!

 * Source files: 
 * Compiler version info: Konan: 1.6.21 / Kotlin: 1.6.21
 * Output kind: FRAMEWORK

e: java.lang.Error: Linking globals named 'OBJC_CLASS_$_GatewayApiLong': symbol multiply defined!

the generated Long class is

package com.wayfair.partners.gateway.api.type

import com.apollographql.apollo3.api.CustomScalarType

public class Long {
  public companion object {
    public val type: CustomScalarType = CustomScalarType("Long", "kotlin.Any")
  }
}
BoD commented 2 years ago

Hmm this is odd indeed. The class should be named GatewayApiMyLong. Could this be a cache issue (have you tried to clean/rebuild?). I also pushed a mini project here that generates the correct class name, maybe you can catch any difference with your setup?

martinbonnin commented 2 years ago

@sentinelweb anything else we can help with here?

sentinelweb commented 1 year ago

sorry i missed you message - i couldn't get this to work for our use case, i cleaned and rebuilt, etc - but luckily for us the offending Long scalar declaration was move to another module so the conflict disappeared.

allenwhite commented 1 year ago

@BoD @martinbonnin I am seeing this issue in my Multiplatform project on the latest version of Apollo, even with the extra.graphqls solution above. Any suggestions on a way to handle this without forcing the upstream API to make changes?

BoD commented 1 year ago

Hi @allenwhite. If you added the @targetName directive, can you check in the generated files (<yourmodule>/build/generated/source/apollo/service/com/example/type), if you see one named Long.kt? You should not see it but see MyLong.kt (or the name you picked).

allenwhite commented 1 year ago

@BoD Thanks for getting back to me. Yeah I checked, I see Long.kt and the default implementation there, despite having added the @targetName directive.

BoD commented 1 year ago

@allenwhite Just to be sure: which version of Apollo are you on? Is the extra.graphqls file next to the schema.graphqls one (like in this sample)?

allenwhite commented 1 year ago

@BoD I initially saw on an earlier version of Apollo, and updated to the latest (3.8.0) but still saw the issue. And yupp, I have that file right next to the schema file.

BoD commented 1 year ago

@allenwhite Would it be possible for you to provide a minimal barebones version of your project so we can have a look? (If this can't be public, you can share it to my email: benoit.lubek@apollographql.com)

allenwhite commented 1 year ago

Just shot something over to you @BoD . Thanks!

BoD commented 1 year ago

Thanks a lot! This helped identify the issue.

For the posterity in case other people have the same issue: Apollo was explicitly configured with schemaFile.set(...) which excludes the extra.graphqls file from being considered. Removing the option solved the issue (all schema files in src/commonMain/graphql are included by default).