8

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)

4

1 回答 1

12

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
于 2015-02-23T17:28:11.523 回答