Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Help -- UnityFramework Plugin won't compile (undefined symbols for architecture x86_64)

Discussion in '2019.3 Beta' started by Chadobado, Feb 1, 2021.

  1. Chadobado

    Chadobado

    Joined:
    Oct 19, 2016
    Posts:
    26
    Apologies if this is a trivial fix, I've lost 2 weeks trying to resolve this.

    Any help/suggestions from the community or Unity team would be ****greatly**** appreciated.

    Problem:

    We are unable to build a Swift project using UnityFramework (uaal) from a workspace for the iOS simulator if I try to use a custom plugin bundled in the Unity Project.

    Resulting in:
    Why am I even trying to do this?

    SwiftUI live previews run on top of the simulator (x86_64), so we are unable to use Uaal without it. I have been able to get uaal working in the simulator and w/ SwiftUI Previews without the custom plugin (a simple bridge/native call proxy), but obviously can't communicate between Unity/Swift without it.

    The built Unity-iPhone.xcodeproj w/ the plugin compiles/runs fine independently in the simulator.

    When incorporated into a workspace w/ the Swift project, UnityFramework compiles but if I reference the plugin from the Swift project, the Swift build fails w/ the above linker error. If I don't attempt to reference the plugin from my Swift project, it compiles/runs fine in the simulator AND the plugin is loaded (details below). If building to the device, it compiles and I am able to use the plugin as expected.

    Setup:

    Unity: 2020.2.1f1
    Xcode: 12.4
    Player settings > Target SDK: Simulator SDK
    Player settings > Target minimum iOS Version: 13.0

    Plugin (super simplified version):

    Unity project:

    #import <Foundation/Foundation.h>

    @interface Bridge : NSObject
    @End

    #import "Bridge.h"

    @implementation Bridge
    +(void)load
    { NSLog(@"[Bridge loaded]"); }
    @End

    Xcode settings:

    Bridge.h: UnityFramework target, Public
    Data: UnityFramework target
    UnityFramework Build settings:
    Other linker flags: -ObjC
    Header search paths: Added "$(SRCROOT)/Libraries/Plugins/iOS/Bridge"
    UnityFramework Build phases:
    Compile Source: Added Bridge.m
    Headers: Bridge.h is public

    Checking lipo shows UnityFramework builds correctly for x86_64:
    Running Unity-iPhone.xcodeproj independently in the simulator works, and shows the plugin being loaded in the console:
    Creating a new workspace w/ Unity-iPhone.xcodeproj and Swift project with:

    //called from a SwiftUI view: UnityBridge.Test()
    import Foundation
    import UnityFramework

    class UnityBridge: UIResponder, UIApplicationDelegate, UnityFrameworkListener {
    public static func Test() {
    print("Attempting to call bridge");
    Bridge.load();​
    }​
    }

    Build fails with the:
    If I comment out //Bridge.load(), the build completes successfully and the plugin is loaded when the Swift build runs in the simulator:
    Also tried compiling the plugin as a static library or framework:

    Tried a few other approaches that seemed more correct:
    • Built the plugin as a static library
    • Included the built libBridge.a and Bridge.h in Assets/Plugins/iOS/Bridge
    • Added a UnityFramework.modulemap to expose the plugin as a submodule as described here.
    • Other postprocess build steps to link the library, setup the modulemap, etc.
    Build fails with the same x86_64 symbol error.

    Really out of ideas here, so if anyone has any suggestions or spots a facepalm mistake it would be greatly appreciated.

    Big thanks in advance
     
    Last edited: Feb 1, 2021
  2. teemup_run

    teemup_run

    Joined:
    Jan 26, 2021
    Posts:
    3
    Are you using the new M1 Chip MacBooks to build? If so, then perhaps you could try setting [excluded architectures to "Arm64"] or something similar.
     
  3. Chadobado

    Chadobado

    Joined:
    Oct 19, 2016
    Posts:
    26
    Thanks @teempup_run, appreciate the suggestion.. unfortunately no, am on an intel machine :/
     
  4. mspinluca

    mspinluca

    Joined:
    Feb 7, 2021
    Posts:
    2
    Did you try Project Settings -> Player -> Other Settings -> Target SDK : Simulator SDK ?
     
  5. Chadobado

    Chadobado

    Joined:
    Oct 19, 2016
    Posts:
    26
    @mspinluca appreciate your comment, yes this is w/ Target SDK : Simulator SDK. Any other ideas appreciated thanks
     
  6. coder89

    coder89

    Joined:
    Oct 26, 2018
    Posts:
    29
    Have you managed to solve or workaround this linking error?

    We are having exactly same problems on xcode 12 & Unity 2021.1.12f and so far no luck. :/

    We are able to build and run our and Unity projects separately on iOS Simulator but we are not able to link them together. Linker says it can't find UnityFramework to link to (even though we could see it in the output directory - however, it is not built as a *.a or *.so library but it shows as an executable - possible Unity bug?).
     
    AviarLabs likes this.
  7. danieleCan

    danieleCan

    Joined:
    Jul 8, 2021
    Posts:
    1
    Hi Chadobado, did you find a solution at the end?
     
  8. Macoron

    Macoron

    Joined:
    Mar 11, 2017
    Posts:
    33
    Exactly same problem here. I've tried to create custom message bus to communicate with uaal. For unknown reason, XCode strips .mm or .swift implementation for x86_64. arm64 architecture works fine.

    We end up using pipeline described in this amazing article:
    https://medium.com/mop-developers/c...me-embedded-in-a-swiftui-ios-app-1cefb38ff439

    The author managed to do get UnityFramework instance by frameworks bundle:
    Code (CSharp):
    1.     private func loadUnityFramework() -> UnityFramework? {
    2.         let bundlePath: String = Bundle.main.bundlePath + frameworkPath
    3.  
    4.         let bundle = Bundle(path: bundlePath)
    5.         if bundle?.isLoaded == false {
    6.             bundle?.load()
    7.         }
    8.  
    9.         let ufw = bundle?.principalClass?.getInstance()
    10.         if ufw?.appController() == nil {
    11.             let machineHeader = UnsafeMutablePointer<MachHeader>.allocate(capacity: 1)
    12.             machineHeader.pointee = _mh_execute_header
    13.  
    14.             ufw?.setExecuteHeader(machineHeader)
    15.         }
    16.         return ufw
    17.     }
    If you try to call
    UnityFramework.getInstance()
    , the x86_64 linker will fail. But
    principalClass
    works great both on simulator and real device.
     
    langyanduan likes this.
  9. Macoron

    Macoron

    Joined:
    Mar 11, 2017
    Posts:
    33
    After a lot of research, I found solution for your problem.

    I don't know why, but
    Bridge.Load()
    won't work on a simulator. I suggested before to use principal class, but in an article above I found much better solution

    You can use
    NSClassFromString
    to load your custom class dynamically and avoid Linker issue. It works similar to reflection in C#. The working code should be something like this:
    Code (CSharp):
    1. NSClassFromString("Bridge").Load()