Search Unity

Undefined symbol for architecture armv7: Game Center + Amazon

Discussion in 'iOS and tvOS' started by StevenSauer, Dec 4, 2013.

  1. StevenSauer

    StevenSauer

    Joined:
    Mar 25, 2013
    Posts:
    19
    **Issue:**
    I've found multiple people with different versions of this problem but none of them seemed to help. I posted this here because it is only iOS relevant, though my version of the issues seem to arise from the Amazon Game Center libs/plugins I'm using.
    Going to the "Link Binaries with Libraries" my GameCenter.a and my AmazonInsightsSDK.a seem to be there and I can't seem to find any .mm files around by these names to add to the Compile sources either. I am building this project from the Unity Game Engine using multiple plugins, though I don't see how that could result in the issue. It could be that I'm not looking for the correct files as well though. I had Game Center working a couple months ago but since I moved back from Android Development, it's been broken.
    I've also already tried reinstalling Unity XCode as well as reimporting the latest versions of the plugins in question.

    **Error Log:**
    Undefined symbols for architecture armv7:
    "_OBJC_CLASS_$_CTTelephonyNetworkInfo", referenced from:
    objc-class-ref in AmazonInsightsSDK.a(AIIOSDeviceDetails.o)
    "__gameCenterIsGameCenterAvailable", referenced from:
    RegisterMonoModules() in RegisterMonoModules.o
    ld: symbol(s) not found for architecture armv7
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    **Used Software:**
    I am using Unity 4.3.1f1, XCode 5.0.2, and the latest versions of both Prime31's Game Center Plugin for Unity and Amazons Full Plugin Package for Game Circle and IAP.

    Thank you all for your help.
     
  2. vladimirg

    vladimirg

    Joined:
    Jun 26, 2013
    Posts:
    43
    It's missing the CTTelephonyNetworkInfo class, which is one of Apple's classes. It is present in the CoreTelephony framework. Is your project linked with it? If not, that's the issue.
     
  3. StevenSauer

    StevenSauer

    Joined:
    Mar 25, 2013
    Posts:
    19
    Thanks a lot!
    That fixed my weird Amazon one!
    Have any idea about the:

    "__gameCenterIsGameCenterAvailable", referenced from:
    RegisterMonoModules() in RegisterMonoModules.o

    A lot of people are saying that it's an issue where I need to use AppCleaner to remove and reinstall Unity and XCode to fix.

    EDIT: Trying the complete removal of Unity and XCode and then reinstalling did not work.
     
    Last edited: Dec 5, 2013
  4. vladimirg

    vladimirg

    Joined:
    Jun 26, 2013
    Posts:
    43
    Oops, didn't that see that one.

    First - you're running on a device, right? Plugins don't usually work in the simulator.

    If you're running from the device and the problem is still happening, read on:

    Here's what's happening - RegisterMonoModules.cpp is auto-generated by Unity and is used to link function names from C# to C++. What functions? Only the ones that were declared in C# as those that should be called from within C++ (you can look in the C# code for the [DllImport("__Internal")] attribute, that's the one that tells Unity that this function should be linked to the C++ side).

    Now, if you're missing that symbol, the most likely scenario is that something went wrong with one of the plugins, probably the GameCenter one. Go into your C# code (which by now must also include the GameCenter plugin's C# code as well) and look for the offending function. How is it declared? Then go into RegisterMonoModules.cpp and see if it's linked there. We shall proceed depending on these investigations.
     
  5. StevenSauer

    StevenSauer

    Joined:
    Mar 25, 2013
    Posts:
    19
    Thanks for being so helpful as well as informative - I like to know what's going on, not just being given the answer.

    C#
    [DllImport("__Internal")]
    private static extern bool _gameCenterIsGameCenterAvailable();

    // Checks to see if GameCenter is available on the current device and iOS version
    public static bool isGameCenterAvailable()
    {
    if( Application.platform == RuntimePlatform.IPhonePlayer )
    return _gameCenterIsGameCenterAvailable();
    return false;
    }

    C++
    This is in the RegisterMonoModules() function:
    mono_dl_register_symbol("_gameCenterIsGameCenterAvailable", (void*)_gameCenterIsGameCenterAvailable);
    This is the declaration at the top:
    void _gameCenterIsGameCenterAvailable();

    The function RegisterMonoModules() is called from my main.mm and it has the include for "RegisterMonoModules.h"

    The only other place I can find the call in question using basic search is in the Assembly-CSharp-firstpass.dll.s
     
  6. Alexey

    Alexey

    Unity Technologies

    Joined:
    May 10, 2010
    Posts:
    1,624
    ok, lets go in tiny steps (to the end you should understand how to fix it)
    when you do [DllImport("__Internal")] you tell mono that you will PInvoke this function later (it is all done under the hood)
    The thing is: how the code would actually *know* what function to call? The answer is simple: on AOT platofrms (ios) it will be linked in (if you check your registermodules you will see that it has prototype and we take pointer to the function) and for JIT it will be loaded from dynamic lib (this time - by name).
    And now we go into wonderful world of mangling. Here you can find more info and links to go on: https://en.wikipedia.org/wiki/Name_mangling
    But for now lets keep it easy and simply state that c++ will change function name (to specify return types, arguments types etc), so inside lib or so/dll it will have *different* name from what you see. You will be glad to know that it is easy to fix - you just declare your function differently - you add extern "C" :
    extern "C" essentially tells the linker that you want no mangling whatsoever (it is a bit more complicated but in our case thats enough info).

    Now, just for fun: did you notice that linker error has extra '_' before function name?
    if you check register modules again, you will notice that your prototype is inside big extern "C" block, so mono/unity/linker expects it to have c linkage (and apple linker adds underscore for c-linked funcs under the hood). But if you didnt specify extern "C" when implementing your function - sure _ was not added, so function cannot be found

    I think thats enough for today's lecture ;-)
     
  7. StevenSauer

    StevenSauer

    Joined:
    Mar 25, 2013
    Posts:
    19
    Wow, thanks a lot for the detailed reply Alexey. Helpful and insightful.

    I feel like I understand what you're saying, but allow me to make sure: Because of the way the linker does name mangling (what I understand as the forcing of unique naming convention based on some schema - in this case a C based external call) it adds the '_' to the attempted call. But if the original function declaration did not specific this, then when it is linked, it will not be giving the additional '_' and thus the linking fails?

    It is to my understanding that extern "C" is c/c++ syntax only. Just in case I tried a few times in my C# script with nothing compilable. So, I'm assuming the extern "C" declaration needs to be added to the C++ functions that my C# script is linking to (what I assume is) XCode/Objective-c.

    Correct me at all if I am wrong at all, I'm still a novice with the Objective-C stuff.

    My problem is that I haven't a clue where this C++ function/file would be. I am using a Prime31 plugin for my Game Center so I'm not sure if I have any access to their .dll at all. Of course, I could have just been misinformed about the extern "C" in C# or perhaps just attempted it incorrectly when I did.
     
  8. Alexey

    Alexey

    Unity Technologies

    Joined:
    May 10, 2010
    Posts:
    1,624
    yes - it is native side
    i would assume that
    is wrong, try to remove leading '_' - i would expect the function to be called gameCenterIsGameCenterAvailable so might be that you pasted stuff here wrong
     
  9. StevenSauer

    StevenSauer

    Joined:
    Mar 25, 2013
    Posts:
    19
    I would have assumed that too, thing is there are a lot of functions exactly like this one (_gameCenterAuthenticateLocalPlayer, _gameCenterIsPlayerAuthenticated, etc.) all being called C# side by a function with the same name but without the leading '_gameCenter'.

    Not only that, _gameCenterIsGameCenterAvailable is the only linker error I get in XCode, none of the other ones fail (though this could just be that the linker gives up after the first failure and the rest of them are indeed failing as well)

    EDIT: I tried removing the '_' from the C# side with the same error only wiht 1 '_' instead of 2
     
    Last edited: Dec 5, 2013
  10. vladimirg

    vladimirg

    Joined:
    Jun 26, 2013
    Posts:
    43
    Is _gameCenterIsGameCenterAvailable declared and implemented anywhere in the project? The declaration in RegisterMonoModules is not enough - the linker can't find the implementation.

    If it's declared in the GameCenter plugins' headers but is not implemented in any source file, you can dump the symbols of GameCenter.a and see if it's there (probably not, if the linker can't find it).