Xamarin.Android: How do you link a static library? - xamarin.android

I am trying to link a static library (foo.a) - which contains C++ code - in an Xamarin.Android project following the directions found in Xamarin's docs. Neither the "path sniffing method," nor the "Abi element within the project file" method seems to work.
Using either method I get unhandled exceptions when I attempt to call into the library functions:
I/mono( 2591): [ERROR] FATAL UNHANDLED EXCEPTION: System.EntryPointNotFoundException: ...
I should mention that I have had no trouble linking and calling into this library (built for armv7, armv7s) with my Xamarin.iOS project using the "additional mtouch arguments" -cxx method described here. All of my DLLImports are the same across platforms...
[DllImport(Import.lib, CallingConvention=CallingConvention.Cdecl )]
internal static extern IntPtr FooMethodName(args);
So, what am I missing?
FYI:
I am using Xamarin Studio 4.0.5 (build 4), Xamarin.Android 4.6.4 (Business Edition)

I realize this question is over a year old, but since I recently had to do exactly this, and hit my head in the same spot, I'll have a go at it anyway...
TL;DR: you cannot link static libraries with Xamarin for Android, you can only link dynamic libraries (.so)
Steps:
If your library is written in C you can skip the first step. But if your lib is written in C++ you must first declare your publicly exported functions as C-functions in your code (i.e. you have to put them inside an #extern "C" { } block). If you don't do this your function names will get subjected to C++ name mangling and Xamarin will not be able to find them.
extern "C"
{
void my_function(bool someParameter);
}
Using the Android NDK, compile your library to a dynamic link library (.so). A static library (.a) will not do. This is where I hit my head, as this is not that clear from the documentation. Adding to the confusion, on IOS it's the exact opposite: you can link static .a libs only there (as per the AppStore policies).
Do this for each processor architecture you wish to support (typically, armeabi, armeabi-v7a and x86)
From here on I assume you have a set of .so libraries, one for each processor architecure. The libraries are all named libX.so, where X is the project name of your library. E.g. "libmylibrary.so".
In your Xamarin Android project, add a folder "libs" below the project root. (You can use another name as well if you wish)
Below the folder "libs", create three child folders, named "armeabi", "armeabi-v7a" and "x86" respectively. Copy one of your .so files to each of these child folders (the one corresponding to the same processor architecture). This enables the Xamarin "path sniffing" feature that will select the right library for the right processor architecture.
Include the the three .so files in your project and for each one set the "Build Action" property to "AndroidNativeLibrary"
Now add the entry functions as static methods to a Xamarin class with the proper DllImport attributes:
namespace MyApp
{
public static class MyLibrary
{
[DllImport("libmylibrary", EntryPoint = "my_function")]
public static extern void MyFunction(Boolean someParameter);
}
}
That's it. You should now be able to call MyLibrary.MyFunction() from your Xamarin C# code

Related

What is a dynamic framework as opposed to a non-dynamic one?

Xcode 6 allows for dynamic frameworks.
What is a dynamic framework?
Both dynamic framework and static framework is a bundle containing a binary and some other things. The binary is called dynamic library or static library.
The binary is what you code is after compiling, your functions, classes, method become binary form, and they are called symbols.
When building your project.
Your code will be built into a binary, let's call it MyProjectBinary.
If your project links to a static library, then after building MyProjectBinary, linker check the symbols in MyProjectBinary and if it uses some part of the static library, for example, use a class in the static library), then linker will copy all the symbols related to the class and combine them in to MyProjectBinary. So no matter how many static library you use, you only get one building result, which is MyProjectBinary.
If you link to dynamic library, then you are telling the linker that, when MyProjectBinary is running, there will be that dynamic library at a suitable place. Dynamic library is not magic, in fact, you've used them for long time. All the frameworks Apple provides are dynamic libraries. They are guaranteed to exist when you app is running on device/simulator.
Let's assume that your project links to a dynamic library called MyDynamicLibrary. When building your project, first MyProjectBinary is still generated the same as using static library. Then, linker just add some information to MyProjectBinary, mark where to find "MyDynamicLibrary" at runtime. Nothing from MyDynamicLibrary will be add to MyProjectBinary
When running your project:
For the project using static library, nothing special happens, since all the code needed is inside MyProjectBinary, it just runs.
For the project using dynamic library, when your code calls a function which is in MyDynamicLibrary, the system tries to find MyDynamicLibrary according to the information stored in MyProjectBinary, if it finds MyDynamicLibrary, then for MyProjectBinary, the function is used like in MyProjectBinary. If it can't find MyDynamicLibrary, them an error will happen and you app will be terminated.
So why do we need dynamic library for iOS 8?
Before iOS8, an app can have only one executable binary, so using static library is OK.
But when iOS 8 comes, you can deliver multiple executable binary in one app, the additional binaries are extensions' executable binaries. This brings up a problem, if there are some code that are uses by multiple executable binaries, and if using static library, same symbols will be copied into every executable, thus takes more space. This is the time when dynamic library comes in handy, we can put these code in dynamic library, and deliver only one copy of the dynamic library for app, the app and its extensions can use the same dynamic library.

How to make sure whether my static library works fine

We are developing a Xamarin iOS application by making use of SUP MBOs. We have generated the code in Objective C and in order to access it from C# code base(Xamarin), this generated code should be bundled as a static library (.a file) with some SUP specific static libraries and SUP header classes. We are able to create universal static library file(.a file) with help of Build fat static library (device + simulator) using Xcode and SDK 4+
Now my question is how to make sure whether the universal static library file which we have created is working or not?
We have created a sample static library file by just implementing a add method and were able to access it through C# code(using Xamarin) but we are getting this error -## MT5211: Native linking failed, undefined Objective-C class: _OBJC_CLASS ## when using SUP generated code. we are giving all correct values to all properties in build setting of Xcode "other linker flags", "library search path", "header search path" but I have no idea how we can go ahead with this. We are not sure whether we are missing something or in wrong path?
The best option is to create a Binding project for the native library (and a corresponding test application that exercises the binding project to make sure it works).
If you have any problems (build/linker/runtime errors), we'll need to see the header file, the binding code you've created and the full build output in order to diagnose the problem properly.

How to include two static libraries that are almost the same for iOS

I have one static library for testing and one for release. The debugging static lib has calls that aren't available in the release version. In my code I use preprocessor macro to guard around calls that are available in the testing static lib.
How do I include both libs in the project and make one of them be linked during the linking process depending on the build I am doing?
NOTE: I don't have access to the code to the static library so I can't make any changes. All I have access to is the client code making use of the lib.
In the Target Build Settings, under Linking, Other Link Flags - you can include your debugging library in Debug, and the real one in Release (Deployment, etc). First remove it from the Link Binary With Libraries under Build Phases.

Embed OpenCV framework inside another xCode project without linking

I have developed an xCode static library for an iPhone App using OpenCV.
Now I want to give my static library to them but I don't want them to go through the hassle of making OpenCV work in their project by changing build settings and all that, that's what I already had to do myself in the static library.
I usually use the 'Projectception' method by dragging my static-library-project into my main xCode project. However when I use this method I usually need to add all the frameworks I use in the static library project again in my main project in the 'Link Binary with Libraries' build phase.
So my question is: is there a way that the OpenCV is only in my static library project and that a new project that imports this static library does not have to do anything extra for OpenCV to work?
Yes. Clone(copy) opencv inside your project (headers and implementation)*, desclare the copied files inside your project and don't use any c/c++ include folder and any library linkage.
*implementations are in modules/.../src/

Library? Static? Dynamic? Or Framework? Project inside another project

I have an existing iOS app and want to add a large chunk of code that I've been developing as another project just for ease of testing. The new chunk basically deals with saving an image to various sharing services, etc.. Because that sharing code needs a lot of testing and future updating, I was wondering what the best way to incorporate that code chunk into my existing app.
I don't know if it should be a static library, dynamic library or a framework, and honestly, I'm not really sure what the difference is, or how I should go about it and get it set up in Xcode.
All I know is that I need/want to keep a separate testing and updating app for the sharing code and have the main app use it.
First, some general definitions (specific to iOS):
Static library - a unit of code linked at compile time, which does not change.
However, iOS static libraries are not allowed to contain images/assets (only code). You can get around this challenge by using a media bundle though.
A better, more formal definition can be found on Wikipedia here.
Dynamic library - a unit of code and/or assets linked at runtime that may change.
However, only Apple is allowed to create dynamic libraries for iOS . You're not allowed to create these, as this will get your app rejected. (See this other SO post for confirmation and reasoning on such).
Software Framework - a compiled set of code that accomplishes a task... hence, you can actually have a static framework or a dynamic framework, which are typically just the compiled versions of the above.
See the Wiki on Software Framework for more details.
Hence on iOS, your only option is basically to use a static library or static framework (the main difference being that a static framework is distributed as a compiled .a file most often, whereas a static library may simply be included as a subproject - you can see all of the code - which is compiled first and its resulting .a file used as a dependency by the project).
Now that we're clear(er) on these terms, setting up a static library and supporting media bundle for iOS isn't too difficult, and there are many tutorials on how to do such. I personally would recommend this one:
https://github.com/jverkoey/iOS-Framework
This is a pretty straight-forward guide and doesn't have the disadvantage of dealing with "fake static libraries"... check it out for more info...
Once you've created your static library, it's as easy as including it as a submodule within Git for use across different projects.
Good Luck.
EDIT
Regarding a subproject within a project, as far as I know, to get this to work/compile correctly, you essentially have to set up a compile chain where the subproject is compiled first, which creates a static framework .a file that is used as a dependency by the project.
Here's another useful tutorial which talks about this:
http://www.cocoanetics.com/2011/12/sub-projects-in-xcode/
EDIT 2
As of iOS 8, Apple now permits developers to create dynamic frameworks! (Note: your app must have a minimum target of iOS 8 to include a dynamic framework... back porting isn't allowed.)
This has been added as a new project template. In Xcode 6.1, this can be found at:
New Project -> iOS -> Framework & Library -> Cocoa Touch Framework
Mach-O file format(Mach Object - .o)
In iOS world every source file is converted into object files - ABI[About] Mach-O file[About] which will be packaged into a final executable bundle(application, framework), file (library) and it's behavior is determined by Mach-O type[About]
Package is a directory which behavious itself as a file - opaque file. It is created for user experience to complicate making some changes into internal structure that can cause unpredictable program behaviour. Package is used in Document Package or with a Bundle. You can use Show Package Contents in a Finder
Bundle is a directory with a specific structure to organize a binary(executable code) and resources for that code(e.g. images, nibs... Assets.car file[About]).
Bundle contains Info.plist[About] file. Bundle was created for developer experience. Also it can be packaged. There are several types of bundle:
application bundle - Application target
framework bundle and versioned bundle as a subtype - Framework Target
loadable bundle(aka plug-in bundle) - '... Bundle' (UI Testing Bundle, Unit Testing Bundle) - can be loaded at runtime. .bundle extension for Mac OS
[Mac OS] XPC Service - Cross Process Communication is a kind of Inter Process Communication (IPC). It can be used as a module on a different process(managed by launchd root process)[About]
others(dSYM[About] bundle)
Application - .ipa, .app[About] - packaged application bundle - launchable program.
Application extension[About] - from iOS v8 - extends functionality of Application which are available when user interacts with other application. App extension as a bundle is a part of Containing app but it is run on their own sandbox(processor, memory...), app which try to use app extension is called Host App. Types of extension app:
Action
Share
Photo Editing
Today aka widget
...
to share common code and resources. It's available when Deployment target is iOS 8+.
Tests - packaged loadable bundle which is used to test a binary. Plug-in architecture allows us to add a new functionality(test cases) as a separate module into existing binary
Libraries and Frameworks
[Library vs Framework]
Martin Fowler on InversionOfControl
A Library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.
A Framework embodies some abstract design, with more behavior built in. In order to use it you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points. The main control of the program is inverted, moved away from you to the framework. This phenomenon is Inversion of Control (also known as the Hollywood Principle - "Don't call us, we'll call you"
Libraries and Frameworks on iOS
They can help you to solve: modularity, reusing, encapsulation, improve build time
Library is a collection of Mach-O object files[check static or dynamic] compiled for one or more architectures.
Static library - .a(aka static archive library, static linked shared library[doc]) - When you add it into your application the static linker during compilation time will merge the object files from the library and package them along with the application object files into one single executable file. The disadvantage is a big output file
From Xcode 9.0, Swift static library is supported.
Dynamic library - .dylib(aka dynamic shared library, shared object, dynamically linked library[doc]) is dynamically linked with the app's executable at load or runtime, but not copied into it. On practice app's package will contain Frameworks folder with .dylib file. All iOS and macOS system libraries are dynamic. The disadvantage is a slow launch time since all dynamic libraries should be copied and linked.
[iOS static vs dynamic library]
[Static vs dynamic linking]
Text-based stub library - .tbd[About], it is a text stub of dynamic library which is located on a target device. As a result you should not package a dynamic library into your bundle. It has a size effect.
Framework aka binary framework - .framework is a not packaged framework bundle(to allow developers to easily take a look at headers and resources) which contains a compiled static or dynamic library, header files and resources.
Static framework contain a static library packaged with its resources.
Dynamic framework aka Embedded framework - from iOS v8 - contains the dynamic library and resources. In addition to that, dynamic framework can include different versions of the same dynamic library in a single bundle (versioned bundle). Also Embedded framework is used in App Extension
[Static vs dynamic framework]
Umbrella framework [Aggregate target] is a framework that contains other frameworks. It is not officially supported on iOS and that is why it is not recommended for developers to create them[Official doc]. In actuality it's a set of sub-frameworks(or Nested Frameworks). When you create a framework which has a dependency, a consumer (such as an app) is responsible for adding this dependency along with your framework into the project. As a developer, it's natural to try to find a way to transfer this duty from consumer to your's. As a result you think that Umbrella framework is the rescue but usually it leads to a serious issues with managing versions and complexity of creating and supporting it.
Fake Framework - is a result of specific operations under a static library to create a bundle with .framework extension that will behave yourself as a dynamic framework. This technic was used when Xcode did not support creating a framework since did not have a framework template. One of realisation of a fake framework. With Xcode 6, Apple has added iOS framework support.
Modular Framework[About] - #import it is a framework which contains a .modulemap file inside. Module can contains submodules. The main advantage is that you save a build time with Modular Framework.
Universal Library or Framework (aka Fat) [lipo] [Aggregate target] contains multiple architectures. For example your release build should support a some arch which you can regulate via Build Active Architecture Only [ONLY_ACTIVE_ARCH]
XCFramework[About] was introduced by Xcode 11 and it is a bundle which includes multiple architectures(arm, x86_64...) and platforms(iOS, MacOS...). It should replace a Universal Framework
Dependency[About] You are able to use third party code as a part of your target. It allows you to reuse a code from a lot of sources like - another project, project in the same workspace, another target, library, framework etc.
How to build and use a Static Library:
[Swift consumer -> Swift static library]
[Swift consumer -> Objective-C static library]
[Objective-C consumer -> Swift static library]
[Objective-C consumer -> Objective-C static library]
How to build and use a Dynamic Framework[change to static]
[Swift consumer -> Swift dynamic framework]
[Swift consumer -> Objective-C dynamic framework]
[Objective-C consumer -> Swift dynamic framework]
[Objective-C consumer -> Objective-C dynamic framework]
[Xcode Build System]
[Xcode components]
[Dynamic linker]
You can also create .podspec file for CocoaPods( http://guides.cocoapods.org/making/private-cocoapods.html#1.-create-a-private-spec-repo ) and use it like any other pod with the only difference that it's your private pod and is not visible to outside world(I'm not sure what will happen if your pod should create CoreData model, but that's not the case, as I understand).

Resources