2

I just started porting an Android app to iOS, and am hitting a major roadblock that I can't figure out despite scouring many similar questions.

I am attempting to follow the pattern implemented in the CastVideos sample where the GoogleCast API is encapsulated in a singleton class which I've called CastManager. To use my singleton class, I #import "CastManager.h" in AppDelegate.m. Then in CastManager.h, I #import <GoogleCast/GoogleCast.h> so that I can use classes and protocols from it as part of CastManager's public interface. However, because I'm importing CastManager.h in both CastManager.m and AppDelegate.m, the linker is finding duplicate symbols from the GoogleCast framework.

This is my CastManager.h:

#import <GoogleCast/GoogleCast.h>
#import <Foundation/Foundation.h>

@interface CastManager : NSObject

@property(nonatomic, strong) GCKDeviceScanner *deviceScanner;

+ (instancetype)sharedCastManager;

@end

And corresponding CastManager.m:

#import "CastManager.h"

@implementation CastManager

+ (instancetype)sharedCastManager {
    NSLog(@"sharedCastManager");
    static CastManager *singleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singleton = [[self alloc] init];
    });
    return singleton;
}

- (instancetype)init {
    NSLog(@"init()");
    if (self = [super init]) {
        self.deviceScanner = [[GCKDeviceScanner alloc] init];
    }
    return self;
}

@end

And this is the main part of my AppDelegate.m:

#import "AppDelegate.h"
#import "CastManager.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    CastManager *castManager = [CastManager sharedCastManager];
    return YES;
}

However, this results in the following error from the linker when attempting to build the project:

duplicate symbol _kGCKDeviceCapabilityVideoOut in:
    /Users/nate/Library/Developer/Xcode/DerivedData/MyCastApp-ezrgxdnlvywpanerezulnarzknno/Build/Intermediates/MyCastApp.build/Debug-iphonesimulator/MyCastApp.build/Objects-normal/x86_64/AppDelegate.o
    /Users/nate/Library/Developer/Xcode/DerivedData/MyCastApp-ezrgxdnlvywpanerezulnarzknno/Build/Intermediates/MyCastApp.build/Debug-iphonesimulator/MyCastApp.build/Objects-normal/x86_64/CastManager.o
... many similar errors ommitted for brevity ...
duplicate symbol _kGCKDeviceCapabilityAudioIn in:
    /Users/nate/Library/Developer/Xcode/DerivedData/MyCastApp-ezrgxdnlvywpanerezulnarzknno/Build/Intermediates/MyCastApp.build/Debug-iphonesimulator/MyCastApp.build/Objects-normal/x86_64/AppDelegate.o
    /Users/nate/Projects/MyCastApp/GoogleCast.framework/GoogleCast(GCKDevice.o)
ld: 8 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

As far as I can tell, this exactly copies the pattern as defined in the CastVideos sample, but the sample compiles fine, and mine doesn't, and I've scoured through both projects trying to find what is different, but I just don't see it. Further, I don't see anything really wrong with doing this, and would expect it to work fine. I can't think of any other way to do it, really.

Here are the relevant files from the CastVideos sample for comparison:

Other questions point to solutions that don't apply or don't fix it:

  • I'm not importing a .m file on accident.
  • I don't have duplicate references to any files in the project.
  • The "Compile Sources" section of the "Build Phases" project setting doesn't include any duplicates.
  • I've added the '-ObjC' linker flag as described by the GoogleCast API docs, though it has the same error with or without it.
  • I've tried deleting the delegate data and doing a clean before building.
  • This is with Xcode 6.3.1 running on OS X Yosemite 10.10.3 and the GoogleCastSDK-2.6.0 package from the SDK documentation page

I have checked in my sample project with the problem at https://github.com/nshafer/MyCastApp

Any help is greatly appreciated!

Edit: the duplicate is somewhat related, it's definitely about the same symbols, but the answers there didn't help, as I'm not using Object-C++, but rather just Objective-C. I don't have a .mm file, just a .m file.

1

3 Answers 3

8

For me it helped to switch the "No Common Blocks" compiler setting to NO:

enter image description here

It pretty much seems to make sense, the setting is explained here: What is GCC_NO_COMMON_BLOCKS used for?

2
  • This solved it, thank you so much! I looked back at the CastVideos sample, and "No Common Blocks" is set to No there as well, but it's not highlighted as being non-default, so I missed it.
    – Niicodemus
    Commented Apr 29, 2015 at 16:57
  • Recent update to XCode (6.4) made new targets default this option to YES which drove me bonkers until finding this answer, thanks. Commented Jul 2, 2015 at 18:15
0

The linker tells you that you have a variable named kGCKDeviceCapabilityVideoOut in two files, AppDelegate.m and CastManager.m. Since it's not in your source code, it's most likely in the GoogleCast code that you are including.

Either change the GoogleCast.h file, or make sure it is only included in one .m file. Including it from CastManager.h means it is indirectly included in every file that includes CastManager.h, so I would avoid that and only include it from CastManager.m. You'll probably have to add

@class GCKDeviceScanner;

in your CastManager.h file.

1
  • This works for classes, such as GCKDeviceScanner, but not for interfaces like GCKDeviceScannerListener, which my class needs to abstract, which is why I accepted the other answer. Thank you for your help, though.
    – Niicodemus
    Commented Apr 29, 2015 at 17:00
0

I found another fix, which is to edit GCKDevice.h in the GoogleCast.framework/Headers folder. Change the 4 constants from GCK_EXPORT to GCK_EXTERN near the top of the file.

/** Device capability flag for video out. */
GCK_EXTERN const NSInteger kGCKDeviceCapabilityVideoOut;
/** Device capability flag for video in. */
GCK_EXTERN const NSInteger kGCKDeviceCapabilityVideoIn;
/** Device capability flag for audio out. */
GCK_EXTERN const NSInteger kGCKDeviceCapabilityAudioOut;
/** Device capability flag for audio in. */
GCK_EXTERN const NSInteger kGCKDeviceCapabilityAudioIn;

I detailed this in a bug report I filed with Google's issue tracker, but it was marked as a duplicate of another somewhat related issue. Either way, it will perhaps get fixed in the next version. Until then, I would suggest going with changing the "No Common Blocks" setting as detailed in Joobik'com's answer, as that doesn't involve changing the 3rd party code.

Not the answer you're looking for? Browse other questions tagged or ask your own question.