Mac Bindings Library RRS feed

  • Question

  • User167521 posted

    Ok, the Mac Bindings Library template has finally arrived by way of Xamarin 6.0. Thanks Guys. But now to understand how to use it...

    There's online documentation for the older iOS Bindings Library which seems a little all-over-place to me. And there's a little in-line documentation in the ApiDefinition file which gets generated when I first create a Mac Bindings Library project which seems a tad simplistic. Apologies for my density.

    In a nutshell, I'm trying to get information about installed printers on the Mac which appears to be only available via the native Core Printing API. Using XCode, I've created a native static library, libPrintCoreNativeLibrary.a, which has an interface derived from NSObject and declares a single method. In the implementation of that method, I call into the Core Printing API and generate a Dictionary of CFStringRefs which gets returned by the method. Using Xamarin Studio, I create a Mac Bindings Library project. On the first step, I add my native libPrintCoreNativeLibrary.a file to the project, but no code-behind file gets generated.

    So of the three projects in play here, my native OSX library, the bindings library, and the Mac app, I have these questions...

    1. Is there some sort of dressing required in my native library in order for the bindings library to import it and generate that code-behind?
    2. Is the ApiDefinition file in the binding library just a straight pass-through layer? Or can additional business logic be added there to further process the results returned from my native library.
    3. Am I even allowed to bind to my own native library? If not, what library do I need to bind to the Core Printing API, and where is it?
    4. Is there anything else I need to know?


    Monday, June 13, 2016 4:38 PM

All replies

  • User35201 posted

    I would start with reading:


    To answer your questions:

    • No. As long as you have a valid objective-c, you should be good to go. See https://developer.xamarin.com/guides/cross-platform/macios/binding/objective-sharpie/ for help getting started on the binding.
    • By default no, it is a thing layer. But you can mark your binding with Internal https://developer.xamarin.com/guides/cross-platform/macios/binding/binding-types-reference/#InternalAttribute and provide a nicer API. We normally do this just for things that don't map nicely to C#. I would personally not put business logic in the binding layer. Make a lib that lives on top for that.
    • You can bind to any library that exposes objective-c, but sharpie might have trouble with non-user libraries.
    • Be careful to get your bindings correct. Sharpie gets you 90% of the way, but it isn't perfect. Review every sharpie binding by hand. If you mess up a binding, you can get fun crashes later.
    Monday, June 13, 2016 5:02 PM
  • User167521 posted

    Thanks Chris. I looked at the objective-c binding documentation and because the application code samples are all different applications, it's hard for me to reconcile which of the 3 projects in play they belong to. And with the new Mac Bindings Library Xamarin Studio template, is Objective Sharpie still in the picture? Do I still need to use it? And what do think would be keeping that code-behind for my library not to be created?

    I think it would be good if there was one good, cohesive sample available for at least a proof-of-concept.

    What do you think?

    Monday, June 13, 2016 8:48 PM
  • User35201 posted

    Here's the tl;dr;

    • The binding project uses your API definition files to generate code to invoke objective-c. If you add a native reference, it will also embed that library inside your final assembly.
    • How do you get your API definition? You can write it out by hand, or you can ask objective sharpies to generate you something to start from, based on a obj-c header file. Objective-sharpie doesn't give you a project, it just generates API definitions that you use in a binding project.
    • If you want to layer additional functionality on top of your binding, I would suggest a "normal" Xamarin.Mac library that references your binding project library.

    I'm rather unclear on what you mean by "code-behind for my library".

    Monday, June 13, 2016 8:59 PM
  • User167521 posted

    After creating the Mac Bindings Library, the comments in the generated ApiDefinition.cs file has this...

    // The first step to creating a binding is to add your native library ("libNativeLibrary.a")
    // to the project by right-clicking (or Control-clicking) the folder containing this source
    // file and clicking "Add files..." and then simply select the native library (or libraries)
    // that you want to bind.
    // When you do that, you'll notice that MonoDevelop generates a code-behind file for each
    // native library which will contain a [LinkWith] attribute. MonoDevelop auto-detects the
    // architectures that the native library supports and fills in that information for you,
    // however, it cannot auto-detect any Frameworks or other system libraries that the
    // native library may depend on, so you'll need to fill in that information yourself.
    // Once you've done that, you're ready to move on to binding the API...
    Monday, June 13, 2016 10:32 PM
  • User167521 posted

    Chris, I have no need to add BL to the Bindings library. It just wasn't clear whether I could or couldn't. I assume you haven't tried the new Mac Bindings Library template in 6.0. If that's correct, can you give it a try and let me know if it really works as advertised? It failed for me on the 1st step:(.


    Monday, June 13, 2016 10:46 PM
  • User35201 posted

    I assume you haven't tried the new Mac Bindings Library template in 6.0

    I'm the lead of Xamarin.Mac. I helped write the binding library support. :smile:

    However, I'm having a very difficult time parsing out what problem/question you are running into.

    Could you post what you've tried \ maybe post the project \ exact build error you are hitting \ detailed question on what you are asking?

    Tuesday, June 14, 2016 1:36 PM
  • User167521 posted

    Chris - I'm just trying to follow the steps as outlined in the ApiDefintion.cs file and also on the Binding Objective-C Libraries guide. I just want to create a simple native Mac library which returns a Dictionary of CFStringRefs. Build a Mac Binding library for it, and then consume it in a Mac application.

    As I said, on the very first step where I add the lib...a file to the Mac Binging library project, no code-behind file gets generated.

    Also, from the "Binding Objective-C Libraries" guide:

    __"Building the library will produce your native binding.

    To complete this binding, you should add the native library to the project. You can do this by adding the native library to your project, either by dragging and dropping the native library from Finder onto the project in the solution explorer, or by right-clicking the project and choosing Add > Add Files to select the native library. Native libraries by convention start with the word "lib" and end with the extension ".a". When you do this, Xamarin Studio will add two files: the .a file and an automatically populated C# file that contains information about what the native library contains:" __

    So I think if you yourself could build the 3 simple projects using the Mac Bindings Library template in Xamarin Studio 6.0, outline the exact steps to do it successfully and post the projects and the steps somewhere, that would be great.


    Tuesday, June 14, 2016 2:36 PM
  • User35201 posted

    I've brought your request up to documentation, for consideration in the future. I would expect the steps would be roughly:

    • Build your native project (if needed)
    • New Mac Binding Project
    • Right click native reference, add your lib (.a, .dylib, .framework whatever)
    • In ApiDefinition create a C# definition that matches your objective-c API. You can do this via objective sharpie (see documentation) or typing in the definition directly. This is where you get to do the heavy lifting of getting it right.
    • Build.
    • From another XM library or exe, reference your binding lib.
    • Build that. Use new API.

    If you have a specific question, please post what step you are in, an example project, and\or the full build log.

    Tuesday, June 14, 2016 7:13 PM
  • User167521 posted

    Ok Chris, I've attached a zip file containing 3 projects, an XCode project which builds a native library, a Xamarin.Mac app project, and a Xamarin Mac Bindings project. What I did was.

    1. Instead of adding the libMacNativeLib.a to the MacBindingsLib project via "Add Files", I added it to the "Native References" section via "Add Native Reference".
    2. It still did not create the so-called code-behind file so I manually created the lib.MacNativeLib.linkwith.cs file.
    3. Added a reference to the MacBindingsLib to MacBindingsApp project.

    When I build the app and try to run, I get the exception shown in the attached screenshot. The same behavior occurs if I add the libMacNativeLib.a to the MacBindingsLib project via "Add Files".

    If you can get this working, please let me know what in addition you had to do.


    Tuesday, June 14, 2016 9:42 PM
  • User35201 posted

    You header defines the type:

    @interface MacNativeLib : NSObject

    However your definition defines it as:

    > interface PrintCoreLib

    These are not the same.

    Your C# definition must exactly match the objective-c interface you are binding. You re getting that error because we are trying to load the native class "PrintCoreLib" instead of "MacNativeLib" and there is no such thing.

    If you fix your definition to match, things start working.

    Tuesday, June 14, 2016 9:53 PM
  • User167521 posted

    Nice catch but...

    I renamed the interface in ApiDefinition.cs to MacNativeLib, but I still get the exception on the line...

            var printCoreLib = new MacBindingsLib.MacNativeLib();

    Is that how I should be getting to it from the app?

    Tuesday, June 14, 2016 10:03 PM
  • User35201 posted

    Then likely your native reference isn't being pulled in to your binding lib. Make sure it is pointing to the right spot. I would personally change the location of your native lib derived data (https://developer.apple.com/library/ios/recipes/xcodehelp-locationspreferences/DerivedData/DerivedData.html), and remove \ readd the native reference in your project lib to point to that (so it will be relative).

    Beyond that, if you still are having issues, you might have to debug the steps of the process to figure out why your copy does not work at mine does.

    Looking at the build log:

    • Does your binding library's CoreCompile step pull in your library as a resource (/resource:../libMacNativeLib.a)
    • Does the CompileToNative step in the project using the library clang's step reference the library (aka, is it getting linked in).

    Then checking matching stuff like:

    • Is the class I'm trying to reference named the same in managed and native
    • Is the class I'm trying to reference actually in the binary (nm libMacNativeLib.a and compare the output to what you expect).

    Successfully using binding projects may require sharpening your debugging skill to figure out what is going wrong, since unlike C# when you make mistakes they can be much trickier to track down.

    Wednesday, June 15, 2016 1:31 PM
  • User167521 posted

    Ahhh... so my little test projects actually worked for you. Can you send me those projects back so I can diff them with what I have? I just want to make sure we're starting on the same page.

    Thanks Chris.

    Wednesday, June 15, 2016 2:25 PM
  • User35201 posted

    Here is the project. It is a bit larger, since I did not clean it so you can see that the output is correct.


    Wednesday, June 15, 2016 2:58 PM
  • User167521 posted

    Interesting, and quite inexplicable, Chris. I did a diff and it looks like the only things you did were...

    1. Copy the libMacNativeLib.a up with level and reference it as "..\libMacNativeLib.a". I'm not sure how you were able to change the reference to that because every time I add a Native Reference, the reference path is always absolute. At any rate since that was the only diff, I copied your .csproj file to use, and it still did not work.

    2. Changed the location of the Derived Data. I changed it to Relative, removed the libMacNativeLib.a reference from the Bindings project and re-added it directly from the Derived Data. The reference to it in the .csproj file was still absolute, but holy cow, it worked!

    So I'm not really sure what got it all to work, but the process seems a tad sensitive. I'm going to try the process again with my real "native" library and Mac app to see if it's repeatable. I'll let you know.

    Thanks again Chris. You're help is always much appreciated.

    Wednesday, June 15, 2016 4:09 PM
  • User137764 posted

    I am in need to use PMServerCreatePrinterList and the rest of the PM API. @ChrisHamons can you confirm this is in cycle 10?

    Monday, February 13, 2017 8:52 PM
  • User35201 posted

    Those are all in master right now, so yes I'd expect them in the release after C9 hit stable.

    Monday, February 13, 2017 10:52 PM