o-o-awake-o-o o-o-awake-o-o - 5 months ago 62
iOS Question

Xamarin - error building a binding library Messaging.g.cs

Having issues building a binding library for Xamarin.iOS. Basically I need to build it to reference the

dll
into a separate project.

Here my example project.

The issue is the auto generated
Messaging.g.cs
appears to error and finishes mid line:

//
// Auto-generated from generator.cs, do not edit
//
// We keep references to objects, so warning 414 is expected

#pragma warning disable 414

using System;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using UIKit;
using GLKit;
using Metal;
using MapKit;
using ModelIO;
using Security;
using SceneKit;
using CoreVideo;
using CoreMedia;
using QuickLook;
using Foundation;
using CoreMotion;
using ObjCRuntime;
using AddressBook;
using CoreGraphics;
using CoreLocation;
using AVFoundation;
using NewsstandKit;
using CoreAnimation;
using CoreFoundation;

namespace ApiDefinition {
partial class Messaging {
static internal System.Reflection.Assembly this_assembly = typeof (Messaging).Assembly;

const string LIBOBJC_DYLIB = "/usr/lib/libobjc.dylib";

[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static IntPtr IntPtr_objc_msgSend (IntPtr receiever, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static IntPtr IntPtr_objc_msgSendSuper (IntPtr receiever, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static IntPtr IntPtr_objc_msgSend_IntPtr (IntPtr receiever, IntPtr selector, IntPtr arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static IntPtr IntPtr_objc_msgSendSuper_IntPtr (IntPtr receiever, IntPtr selector, IntPtr arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr (IntPtr receiver, IntPtr selector, IntPtr arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static void void_objc_msgSendSuper_IntPtr (IntPtr receiver, IntPtr selector, IntPtr arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static int int_objc_msgSend (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static int int_objc_msgSendSuper (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static void void_objc_msgSend_int (IntPtr receiver, IntPtr selector, int arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static void void_objc_msgSendSuper_int (IntPtr receiver, IntPtr selector, int arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static float float_objc_msgSend (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static float float_objc_msgSendSuper (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static void void_objc_msgSend_float (IntPtr receiver, IntPtr selector, float arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static void void_objc_msgSendSuper_float (IntPtr receiver, IntPtr selector, float arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static bool bool_objc_msgSend (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static bool bool_objc_msgSendSuper (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static void void_objc_msgSend_bool (IntPtr receiver, IntPtr selector, bool arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static void void_objc_msgSendSuper_bool (IntPtr receiver, IntPtr selector, bool arg1);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static global::System.Double Double_objc_msgSend (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSendSuper")]
public extern static global::System.Double Double_objc_msgSendSuper (IntPtr receiver, IntPtr selector);
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
public extern static void vo


I also followed the official walktrough from Xamarin.

The original repo for the project I am trying to build is here which is a binding project for the original Objectice-C here.

I cannot figure out why
Messaging.g.cs
errors and prevents the build completing.

Any help would be appreciated.

All the best,

John

Answer

I have managed to solve the issue.

I hope this answer helps other Xamarin developers in future.

If you are using an Objective C binding library, you should build with XCode and generate the ApiDefinition.cs and StructsAndEnums.cs using Objective Sharpie available here.

The problem I was experiencing was the auto generated code does not handle Delegates properly. Moreover, the [Native] attribute caused the interpreter to use incompatible data types - i.e. and enum struct with uint.

Compounding the issues above I was also attempting to bind more than one .a static libraries within the same project.

So, some things you will need to refactor within your Objective Sharpie generated C# files:

Remove any duplication of method signatures In my example the tool generated the following code:

        // @optional -(BOOL)revealControllerPanGestureShouldBegin:(SWRevealViewController *)revealController;
        [Export("revealControllerPanGestureShouldBegin:")]
        bool RevealController(SWRevealViewController revealController);

        // @optional -(BOOL)revealControllerTapGestureShouldBegin:(SWRevealViewController *)revealController;
        [Export("revealControllerTapGestureShouldBegin:")]
        bool RevealController(SWRevealViewController revealController);

Whereas to avoid the compiler throwing duplicate method errors it should be:

        // @optional -(BOOL)revealControllerPanGestureShouldBegin:(SWRevealViewController *)revealController;
        [Export("revealControllerPanGestureShouldBegin:")]
        bool RevealControllerPanGestureShouldBegin(SWRevealViewController revealController);

        // @optional -(BOOL)revealControllerTapGestureShouldBegin:(SWRevealViewController *)revealController;
        [Export("revealControllerTapGestureShouldBegin:")]
        bool RevealControllerTapGestureShouldBegin(SWRevealViewController revealController);

Next, find any example where the tool has generated an enum struct which inherits from a unsupported primitive.

So, for example:

[Native]
public enum FrontViewPosition : uint
{
    LeftSideMostRemoved,
    LeftSideMost,
    LeftSide,
    Left,
    Right,
    RightMost,
    RightMostRemoved
}

Changes to public enum FrontViewPosition : ulong.

Next remove any [Verify] decorations.

Finally, I found that Objective Sharpie handles extension methods poorly and results in the generated code trying to create a static class with virtual methods inside...

To fix, find all instances of [Category], for example:

// @interface SWRevealViewController (UIViewController)
[Category]
[BaseType(typeof(UIViewController))]
partial interface UIViewController_SWRevealViewController
{
    // -(SWRevealViewController *)revealViewController;
    [Export("revealViewController")]
    SWRevealViewController RevealViewController{ get; };
}

And change it to

// @interface SWRevealViewController (UIViewController)
[Category]
[BaseType(typeof(UIViewController))]
partial interface UIViewController_SWRevealViewController
{
    // -(SWRevealViewController *)revealViewController;
    [Export("revealViewController")]
    SWRevealViewController RevealViewController();
}

Now clean and rebuild and the auto generated code will now compile correctly. Reference the binding dll in any desired project to make use of it.

If anyone is looking at using the SWRevealViewController library in Xamarin then to save you time you can use my repo here.

Good luck and have fun.

John

Comments