0

I have successfully created an updated ZBar MonoTouch binding dll, following up on this answer here from a while ago, using the updated [Field] bindings to bind static NSStrings (previously I was just duplicating the value of the NSString in my binding dll).

The binding dll compiles fine (Compiled in Release mode).

And using the binding ZBar.dll from my app works fine in Debug builds, returning the correct NSString value from the native lib. However in Release builds it always returns null.

Note that I have the linker behaviour set to strip all assemblies for both Debug and Release builds, so it's nothing to do with the linker stripping anything out.

I tried turning off the LLVM compiler for Release, and it still returns null in Release builds. However enabling debugging in Release builds fixes it (obviously not a solution though).

Heres the binding code:

[Static]
interface ZBarSDK
{
    // extern NSString* const ZBarReaderControllerResults;
    [Field ("ZBarReaderControllerResults", "__Internal")]
    NSString BarcodeResultsKey { get; }
}

And here's the decompiled IL (According to MonoDevelop):

namespace ZBar
{
    public static class ZBarSDK
    {
        [CompilerGenerated]
        private static NSString _BarcodeResultsKey;

        [CompilerGenerated]
        private static readonly IntPtr __Internal_libraryHandle = Dlfcn.dlopen(null, 0);

        public static NSString BarcodeResultsKey
        {
            get
            {
                if (ZBarSDK._BarcodeResultsKey == null)
                {
                    ZBarSDK._BarcodeResultsKey = Dlfcn.GetStringConstant(ZBarSDK.__Internal_libraryHandle, "ZBarReaderControllerResults");
                }
                return ZBarSDK._BarcodeResultsKey;
            }
        }
    }
}

Monotouch: 6.0.10

Community
  • 1
  • 1
Tyson
  • 14,726
  • 6
  • 31
  • 43
  • Are you sure you need the "__Internal" second parameter to the FieldAttribute ? – Stephane Delcroix Mar 01 '13 at 12:00
  • @StephaneDelcroix Yes, according to the [binding docs here (Field section)](http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries#37-binding-fields): _If you are linking statically, there is no library to bind to, so you need to use the __Internal name_ – Tyson Mar 01 '13 at 12:16
  • @StephaneDelcroix Besides, it does work when debugging mode is enabled. You would think something like that would break it for all cases. – Tyson Mar 01 '13 at 12:18

1 Answers1

3

Add this to the additional mtouch arguments in the project's iOS Build options page:

--nosymbolstrip=ZBarReaderControllerResults

The difference between Debug and Release builds is that Release builds are stripped, thus removing the symbol for the field, so Xamarin.iOS can't find it at runtime. This option will make Xamarin.iOS tell the linker that it should keep that symbol, even if the symbol is not used (note that the binding to the field is a dynamic binding which happens at runtime, so the native strip tool is not able to see that the field is actually used).

Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86
  • Thanks, that sounds promising, will test tomorrow. Out of curiosity, what layer of linking are we talking about? It's not the managed IL linking/stripping is it? Your saying the native symbol is being stripped from the precompiled native Zbar lib file? I wasn't aware that happened within MT? Is this documented anywhere? – Tyson Mar 01 '13 at 14:57
  • This is the native strip tool (run `man strip` from a terminal to see more information). This is done by default by Xamarin.iOS for release builds to make them smaller. You can pass `--nosymbolstrip` (without any arguments) to mtouch to disable this completely if you're curious to see the difference. – Rolf Bjarne Kvinge Mar 01 '13 at 20:09
  • Ok got it working, thanks Rolf! However I needed to remove the underscore prefix, i.e. I used `--nosymbolstrip=ZBarReaderControllerResults`. Was that just a typo in your answer? – Tyson Mar 02 '13 at 01:05
  • However, this fix isn't an ideal solution - it means every app that uses ZBar.dll needs to perform this configuration. Is there any way to embed this instruction in the MT, i mean, Xamarin.iOS ;) binding ZBar.dll itself? – Tyson Mar 02 '13 at 01:08
  • @Tyson: I wasn't sure about the underscore or not, I guess I guessed wrong (I've fixed the answer now). The idea is to eventually make Xamarin.iOS automatically detect these fields, and not require passing --nosymbolstrip at all. – Rolf Bjarne Kvinge Mar 04 '13 at 12:04