Bug 51548 - Compile Error MT5211 When Using Mobile Center
Summary: Compile Error MT5211 When Using Mobile Center
Alias: None
Product: iOS
Classification: Xamarin
Component: General (show other bugs)
Version: XI 10.4 (C9)
Hardware: Macintosh Mac OS
: Normal normal
Target Milestone: (C9)
Assignee: Rolf Bjarne Kvinge [MSFT]
Depends on:
Reported: 2017-01-16 00:18 UTC by Zhen Liu
Modified: 2017-01-25 18:39 UTC (History)
6 users (show)

See Also:
Is this bug a regression?: ---
Last known good build:

Test Case (29.63 KB, application/zip)
2017-01-16 18:03 UTC, Alex Soto [MSFT]

Description Zhen Liu 2017-01-16 00:18:10 UTC
# Steps to reproduce
Create a new Xamarin.Forms project, add Mobile Center Nuget Packages to the project and then call MobileCenter.Start function in AppDelegate.FinishedLaunching
Build for device (iPhone)
# Expected behavior
Successfully build the project for iOS platform

# Actual behavior
15 MT5211 build errors.

# Supplemental info (logs, images, videos)
One of the errors like this
MTOUCH: Error MT5211: Native linking failed, undefined Objective-C class: MSLogger. The symbol '_OBJC_CLASS_$_MSLogger' could not be found in any of the libraries or frameworks linked with your application. (MT5211) (Test5211.iOS)

# Test environment (full version information)
Cycle 9 Xamarin Studio Professional on macOS.
Comment 1 Alex Soto [MSFT] 2017-01-16 18:03:02 UTC
Created attachment 19357 [details]
Test Case

I can reproduce this issue using 

=== Xamarin Studio Enterprise ===

Version 6.2 (build 1718)
Installation UUID: 48af9690-0e4c-4b21-b82d-5c9cce64d17e
	Mono 4.8.0 (mono-4.8.0-branch/9e8f0ee) (64-bit)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 408000429

=== Apple Developer Tools ===

Xcode 8.2 (11766)
Build 8C38

=== Xamarin.iOS ===

Version: (Visual Studio Enterprise)
Hash: a7f1dc3
Branch: master
Build date: 2017-01-08 14:16:01-0500

=== Build Information ===

Release ID: 602001718
Git revision: 0591bf7fba648f3ece7d03b790ff8c35f494e69d
Build date: 2017-01-09 14:51:42-05
Xamarin addins: cc3da0af6946082a463525b3db698a6b04ce2c2f
Build lane: monodevelop-lion-cycle9

=== Operating System ===

Mac OS X 10.12.2
Darwin iAlexRet.local 16.3.0 Darwin Kernel Version 16.3.0
    Thu Nov 17 20:23:58 PST 2016
    root:xnu-3789.31.2~1/RELEASE_X86_64 x86_64
Comment 2 Alex Soto [MSFT] 2017-01-16 18:04:35 UTC
The class is definitely there

Alex$ lipo -info MobileCenter.a
Architectures in the fat file: MobileCenter.a are: armv7 armv7s i386 x86_64 arm64
iAlexRet:mobilecenter Alex$ strings MobileCenter.a | grep MSLogger
+[MSLogger initialize]
+[MSLogger currentLogLevel]
+[MSLogger setCurrentLogLevel:]
+[MSLogger setLogHandler:]
+[MSLogger logMessage:level:tag:file:function:line:]
+[MSLogger isUserDefinedLogLevel]
+[MSLogger setIsUserDefinedLogLevel:]
Comment 3 Alex Soto [MSFT] 2017-01-16 18:12:06 UTC
Build Log: https://gist.github.com/dalexsoto/57afa82637e42c905ee3f9be89f4f30f

From: https://gist.github.com/dalexsoto/57afa82637e42c905ee3f9be89f4f30f#file-build-log-L1228

> clang  -framework Foundation -framework UIKit /Users/Alex/Projects/Bug51548/iOS/obj/iPhone/Debug/mtouch-cache/MobileCenter.a /Library/Frameworks/Xamarin.iOS.framework/Versions/ /Library/Frameworks/Xamarin.iOS.framework/Versions/ -lz -isysroot /Applications/Xcode82.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.2.sdk -Qunused-arguments -miphoneos-version-min=8.0 -arch arm64 -shared -read_only_relocs suppress -install_name @executable_path/libMicrosoft.Azure.Mobile.iOS.Bindings.dll.dylib -fapplication-extension -o /Users/Alex/Projects/Bug51548/iOS/obj/iPhone/Debug/mtouch-cache/Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.dylib -x assembler /Users/Alex/Projects/Bug51548/iOS/obj/iPhone/Debug/mtouch-cache/Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.s -DDEBUG

We are extracting and giving the static library to clang so must be something else.
Comment 4 Rolf Bjarne Kvinge [MSFT] 2017-01-16 18:32:49 UTC
@Alex, is the MSLogger class in the arm64 slice in the binary?

    nm -arch arm64 /Users/Alex/Projects/Bug51548/iOS/obj/iPhone/Debug/mtouch-cache/MobileCenter.a | grep MSLogger
Comment 5 Alex Soto [MSFT] 2017-01-16 21:19:00 UTC
@Rolf, looks like it is, inside arm64 and armv7

iAlexRet:mobilecenter Alex$  nm -arch arm64 MobileCenter.a | grep MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
0000000000000168 t +[MSLogger currentLogLevel]
000000000000013c t +[MSLogger initialize]
0000000000000238 t +[MSLogger isUserDefinedLogLevel]
00000000000001c0 t +[MSLogger logMessage:level:tag:file:function:line:]
0000000000000174 t +[MSLogger setCurrentLogLevel:]
0000000000000244 t +[MSLogger setIsUserDefinedLogLevel:]
000000000000018c t +[MSLogger setLogHandler:]
0000000000000658 S _OBJC_CLASS_$_MSLogger
0000000000000630 S _OBJC_METACLASS_$_MSLogger
00000000000004f0 s l_OBJC_$_CLASS_METHODS_MSLogger
00000000000005e8 s l_OBJC_CLASS_RO_$_MSLogger
00000000000005a0 s l_OBJC_METACLASS_RO_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger
                 U _OBJC_CLASS_$_MSLogger

iAlexRet:mobilecenter Alex$  nm -arch armv7 MobileCenter.a | grep MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
00000108 t +[MSLogger currentLogLevel]
000000de t +[MSLogger initialize]
000001aa t +[MSLogger isUserDefinedLogLevel]
00000162 t +[MSLogger logMessage:level:tag:file:function:line:]
00000116 t +[MSLogger setCurrentLogLevel:]
000001ba t +[MSLogger setIsUserDefinedLogLevel:]
00000132 t +[MSLogger setLogHandler:]
00000484 S _OBJC_CLASS_$_MSLogger
00000470 S _OBJC_METACLASS_$_MSLogger
000003c4 s l_OBJC_$_CLASS_METHODS_MSLogger
00000448 s l_OBJC_CLASS_RO_$_MSLogger
00000420 s l_OBJC_METACLASS_RO_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
         U _OBJC_CLASS_$_MSLogger
Comment 6 Alex Soto [MSFT] 2017-01-16 21:33:58 UTC
@Rolf I was also thinking that could be a visibility issue but that also seems fine


> MobileCenter.a:MSLogger.o: 0000000000000658 (__DATA,__objc_data) external _OBJC_CLASS_$_MSLogger
> MobileCenter.a:MSLogger.o: 0000000000000630 (__DATA,__objc_data) external _OBJC_METACLASS_$_MSLogger
Comment 7 Alex Soto [MSFT] 2017-01-17 00:16:59 UTC
@Rolf: Tested the native library with a Xcode project and works fine, after some other filed attempts Sebastien came to the rescue and suggested to disable fastdev and it built fine without it.

@Zhen Liu uncheck "Enable incremental builds" in your Project Options > Build > iOS Build  as a workaround
Comment 8 Sebastien Pouliot 2017-01-17 00:48:22 UTC
Downgrading severity as there's a workaround for the issue.
Comment 9 Rolf Bjarne Kvinge [MSFT] 2017-01-17 07:03:57 UTC
What happens is that we link the native library into Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.dylib, but the code that is actually using referencing these classes is compiled into libregistrar.o, which is only linked into the main app, so the native linker will just remove the native library from Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.dylib (since it's not used).

One possible solution is to add -force_load to third-party native libraries when linking them into dylibs, but that would be a functional difference between incremental builds and non-incremental builds, so I don't think it's a good idea.

Unfortunately I think this will probably hit most projects using binding projects and incremental builds (which suggests another (temporary) solution: automatically disable incremental builds if any binding projects are used).

A more permanent solution would be to ask the linker to keep any bound classes (I'm not sure if passing '-u _OBJC_CLASS_$_MSLogger' will work, but if not, we can generate an ObjC file that just does '[MSLogger class]' which will have the pretty much the same effect).

@Sebastien, I can try to implement the permanent solution in master, and if it turns out to be too complicated (or other problems show up that causes it to take too long/risky to fix), we can easily implement the temporary solution in C9.

BTW this works by accident in C8: the native library is linked into both Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.dylib and the executable, and since the native linker does not add anything from the native library in Microsoft.Azure.Mobile.iOS.Bindings.dll.arm64.dylib, everything works fine. Had there been any P/Invokes in the managed binding assembly to the native library (which would have prevented the native linker from removing the native library), then we'd end up with two copies of the native library in the process.
Comment 10 Sebastien Pouliot 2017-01-17 13:46:46 UTC
Let's do (and test) this* on master - with a potential backport to C9 or a service release later.

* We'll discuss options on the next meeting -> https://trello.com/c/SMvrUWAN/665-incremental-builds-fastdev
Comment 11 Sebastien Pouliot 2017-01-17 13:54:48 UTC
@Rolf in the mean time let's add this to the 10.4 release notes as a known issue.
Comment 12 Rolf Bjarne Kvinge [MSFT] 2017-01-18 10:05:55 UTC
Comment 13 Rolf Bjarne Kvinge [MSFT] 2017-01-19 07:05:53 UTC
cycle9: https://github.com/xamarin/xamarin-macios/pull/1530

Note You need to log in before you can comment on or make changes to this bug.