Adding 3rd party frameworks which an external lib depends on, to a Xamarin Studio project.

JakeSimpsonJakeSimpson Jake SimpsonUSMember

So here's the issue.

I've had to wrap the IOS native Parse SDK in a lib (or a ".a" file, as they are on here on IOS), that's in a project in XCode. I can generate the lib file ok, and I've been here http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries and here http://docs.xamarin.com/guides/ios/advanced_topics/native_interop and done my best to interpret this stuff, which is written for an older version of Xamarin studio than is currently out there.

So I have my .a file - I've ensured that it's got both the simulator AND arm versions in the .a file (ie it's a universal, or 'fat' lib) - pretty sure I've got that right.

I've got a bunch of static C style functions I want to call from C# in my mono project, and I've included the .a file as a "native reference" which, I'm assuming, does all the work of #1 and #2 in here http://docs.xamarin.com/guides/ios/advanced_topics/native_interop - that would makes sense, right? It's hard to now for sure since I can't find documentation on what "native references" are (it looks like a recent addition to the IDE?), nor can I actually see the command line that the Xamarin Studio IDE generates when it actually does compilation / linking, so I don't know for sure that it's doing the right -gcc flags, assuming that is what it does (I would expect it to, otherwise what's the point, right?).

Either way I compile ok, but when I run, I get a link error on start up where it looks like it's not loading my lib because my lib sits on top of the Parse.IOS framework. OK. I would expect that, since if I was using my lib in another Objective C executable, I would expect to need to link against frameworks it uses. Given that, I feel confident that the Native Reference set up is doing what it's supposed to (since it's trying to load it), but it's failing because of the native Framework dependency.

This is the error I see.

ProjectName[45077:c07] Could not load 'Parse.iOS' for registration: System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.  at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (System.Reflection.Assembly,bool)  at System.Reflection.Assembly.GetTypes () [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/Assembly.cs:357  at MonoTouch.ObjCRuntime.Runtime.RegisterAssembly (System.Reflection.Assembly a) [0x00062] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:127 ProjectName[45077:c07] This could be due to an outdated assembly kept by the simulator, location: /Users//bin/iPhoneSimulator/Debug/Parse.iOS.dll

So how do I get the framework into the C# project? I can't find any documentation on that. The closest I've gotten is this - being required to add

"-cxx -gcc_flags "-L${ProjectDir} -lMylibrary -lSystemLibrary -framework CFNetwork -force_load ${ProjectDir}/libMyLibrary.a"

to my project compile settings to load in not only my lib, but also a framework. However, I have to specify a path for both the lib and the framework, and I've no idea what the syntax for that looks like, nor do I know what adding the .a file as a Native Reference might have already set up in terms of -gcc_flags already being set up.

I don't want to get into why I'm not using the C# Parse SDK. I've spent days with it and it, basically, will not compile, even with the beta release of Monotouch. I'm not wasting any more time on that (I just don't have any more, I'm behind already) - I'd rather just do it myself with a lib and know it works than waste time on a beta release that is inherently not compiler stable. I don't want to spend time justifying that decision - I would rather get some.... comprehensive instructions on how I can include a prebuilt framework into a xamarin studio project.

Help?

Thanks!

Posts

  • RolfBjarneKvingeRolfBjarneKvinge Rolf Bjarne Kvinge USModerator, Xamarin Team Xamurai

    This error is a purely managed problem, it does not have anything to do with the native libraries you're using.

    Can you attach/pastebin the full build output? There might be some information there that can help locate the problem.

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    OK, more information.

    Just in an effort to get the lib loading directly, I've removed all reference to the parse.IOS framework within it. The lib is exactly the same, except it's just not dependent on parse.IOS anymore and any usage of that lib is commented out.

    That should be enough to get this external lib loading inside my C# app and at least make it so I know that it is the inclusion of the parse.IOS that I have to overcome.

    I've built the "fat" lib, I copied into the project directory and followed all the instructions in this - http://docs.xamarin.com/guides/ios/advanced_topics/native_interop

    You might want to update the documentation on the instructions of where the -gcc line needs to go - I would have thought that because it's a -gcc flag, and gcc is a compiler that it would go in project->Options->Compiler->Additional arguments, but that turns out to be wrong - it needs to go in the final projects IOS Build, as part of the mTouch arguments. I had to sit and try and few things before I figured out this is what the documentation meant.

    I did need the -cxx flag, because I got an extremely cryptic link error - Undefined symbols for architecture i386:  "___gxx_personality_v0", referenced from:      Dwarf Exception Unwind Info (__eh_frame) in libMyLib.a(MyLibFunctions.o)

    which stumped me for a while until I added that flag.

    Anyway, it feels like that the import is all working now.

    However, the invoking is not.

    This is what my invoke definitions look like (very simply)

                public const string dll = "__Internal";
    
        [DllImport( dll, EntryPoint="TryLoginUser" )]
        private static extern void TryLoginUser(StringBuilder userID, StringBuilder password);
    

    However, when I call this function - e.g.

        public static void ParseIOSLogin(string userID, string password)
        {
            StringBuilder s_userID = new StringBuilder( userID );
            StringBuilder s_password = new StringBuilder( password );
            TryLoginUser(s_userID, s_password);
        }
    

    I get an instant system.EntryPointNotFound exception.

    This is what the function looks like inside the lib

    void TryLogInUser(NSString * userID, NSString* password) {

    ifdef VERBOSE

    NSLog(@"IOSParseLib - Logging in User");
    NSLog(@"UserName %@", userID);
    NSLog(@"password %@", password);
    NSLog(@" ");
    

    endif

    }

    Any idea where I am going wrong here?

    Cheers

  • RolfBjarneKvingeRolfBjarneKvinge Rolf Bjarne Kvinge USModerator, Xamarin Team Xamurai

    Can you gist/pastebin the entire build output?

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    Not really. This is HUGE project, and it's not a public project. This is a port of a game that has not been announced. Plus there's just way way way too much to wade through in terms out output.

  • RolfBjarneKvingeRolfBjarneKvinge Rolf Bjarne Kvinge USModerator, Xamarin Team Xamurai

    What if you create a new project and just add this P/Invoke (and the link with the native library too of course)?

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    I think, from looking at this, that I'm actually including the .a file just fine. I think the problem I am having is finding the correct prototype definition in terms of what the objective C is expecting and what the C# thinks it is.

    I think this prototype in C# -

    private static extern void TryLoginUser(StringBuilder userID, StringBuilder password);

    is NOT the same as the one in Objective C, which looks like

    void TryLogInUser(NSString * userID, NSString* password)

    I was using a friends example code, and it's dawned on me that StringBuilder is what you use to construct a string that is a char *, not an NSString. However, I don't know what the right prototype DOES look like?

    Any help?

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    Also, I found the sharpie project you guys have, that is supposed to generate bindings from a head file. This is an awesome tool idea, but it doesn't work. I try generating a binding file and the app crashes with "Could not find a part of the path "/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h"."

    Error.

    So, great concept, doesn't work. This is probably one of the most frustrating things I've come across recently. I just don't seem to be able to get this binding right.

    Help?

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    OK, so there is no help here?

    All I want to do is link some C functions that are built into a library that is created in Objective C. I don't want to use selectors, or any of that stuff - most of what is detailed here - http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries - simply does not work.

    Even just trying to add the libraries in the way detailed here just gives compile errors. This, for example, gives me a compile error

    [assembly: LinkWith ("libMyLibName.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7, ForceLoad = true)]

    Sharpie doesn't work since it just crashes out telling me it is missing libraries, so as a tool, it's a nice idea, but since it doesn't work, it's pretty useless.

    All I want To Do is simply call a C function as declared in my lib. That's it. But apparently that is too much?

    Here is a function, in C, that is inside my lib. It's not in a class, it's just a basic function.

    void TryLogInUser(char * userID, char* password) { NSString *userIDNSString = [[NSString alloc] initWithUTF8String:userID]; NSString *passwordNSString = [[NSString alloc] initWithUTF8String:password];

    ifdef VERBOSE

    NSLog(@"IOSParseLib - Logging in User");
    NSLog(@"UserName %@", userIDNSString);
    NSLog(@"password %@", passwordNSString);
    NSLog(@" ");
    

    endif

    }

    It doesn't get any simpler than that.

    Here is my API definition

        [DllImport( "__Internal", EntryPoint="TryLoginUser" )]
        private extern static void TryLoginUser(string userID, string password);
    

    and here is the calling of this function

        public static void ParseIOSLogin(string userID, string password)
        {
            TryLoginUser(userID, password);
        }
    

    Again, couldn't really be simpler. However, when I run this, I get an EntryPointNotFound exception.

    I'm assuming that the string->Char* conversion takes place automatically - if that is not the case, can someone please indicate that? I've tried using stringBuilder and that doesn't work either.

    I'm pretty sure that the lib I am using is being included in the executable - I added this line to the mtouch commands.

    -cxx -gcc_flags "-L${ProjectDir} -lMyLibName -force_load ${ProjectDir}/libMyLibName.a"

    and I don't get any errors, so I'm pretty sure it's linking. I'm also pretty sure that the lib itself is universal and contains both arm7 and I386 code in it.

    Now, I think there is a problem with this line

    [DllImport( "__Internal", EntryPoint="TryLoginUser" )]

    I think this is not hooking up with the function in the lib? How can I tell what functions are being exposed by the linker? Is there some name mangling I should be doing?

    This is something that is really pressing for me, and the amount of support I've had here so far hasn't solved this. Hell, I'm prepared to pay someone to get support, but really need someone at Xamarin to reach out there.

    This honestly shouldn't be this hard?

  • JakeSimpsonJakeSimpson Jake Simpson USMember

    More info. Running nm on my lib I generate proves several things - I am generating the universal lib correctly because there are symbols for I386, arm7 and arm7s in there. Also, the symbols I am looking for are in there - mangled as compilers are wont to do, but there.

    I tried sticking a main in the lib, and then my project wouldn't link, claiming it had two main symbols (which it would do now), which I think proves that the C# project IS linking in my lib correctly.

    I think this is purely a naming convention issue, however I have no idea what the naming convention should be.

    Help. Please.

  • ChrisHonselaarChrisHonselaar Chris Honselaar NLBeta ✭✭✭

    Just a sanity check - is the C function you are testing with included in the public header, and/or marked with extern? Have you tested with a simple XCode project, to see if the lib can be called from there?

  • dalexsotodalexsoto Alex Soto USMember, Xamarin Team Xamurai

    Also You could make a Objective C wrapper arround it and then Bind it.

  • RolfBjarneKvingeRolfBjarneKvinge Rolf Bjarne Kvinge USModerator, Xamarin Team Xamurai

    Can you show the output from nm? I've seen issues in the past where the symbol is a private symbol (lowercase t instead of uppercase T). If this is the case you'd see exactly the behavior you're seeing, since only public symbols can be found.

Sign In or Register to comment.