Xamarin / MonoTouch: unable to compile in "Link SDK only" mode due to missing characters

I am trying to compile an iOS application using MonoTouch mode only in Link SDK mode. It compiles completely if the binding is completely disabled, but it also creates a colossal binary that is not suitable for release mode.

Unfortunately, one of the libraries I need somehow calls Expression.Visit, and I cannot figure out how to instruct the linker so as not to break it. This results in this compilation error:

Error MT2002: Failed to execute the command "System.Linq.Expressions.Expression System.Linq.Expressions.ExpressionVisitor :: Visit (System.Linq.Expressions.Expression)" from "System.Core, Version = 2.0.5.0, Culture = Neutral , PublicKeyToken = 7cec85d7bea7798e "(MT2002) (MyApp)

As user binding documentation , I installed a linker file to try and stop this:

<?xml version="1.0" encoding="UTF-8" ?> <linker> <assembly fullname="System.Core"> <type fullname="System.Linq.Expressions.ExpressionVisitor"> <method signature="System.Linq.Expressions.Expression Visit(System.Linq.Expressions.Expression)" /> </type> </assembly> </linker> 

Unfortunately, this has no effect - the error just happens as before.

The documentation mentions the preserve="fields" parameter, which I can provide for <type> , so I tried the following:

 <?xml version="1.0" encoding="UTF-8" ?> <linker> <assembly fullname="System.Core"> <type fullname="System.Linq.Expressions.ExpressionVisitor" preserve="methods" /> </assembly> </linker> 

That didn't work either.

Then I injected an XML syntax error into the file, and the assembly failed, saying that it could not parse the linker file so that at least I knew that the file was being read.

But then I tried to introduce errors in the assembly name:

 <?xml version="1.0" encoding="UTF-8" ?> <linker> <assembly fullname="NonexistentAssembly"> </assembly> </linker> 

This caused an error complaining that the assembly could not be resolved.

Then I tried to change the type name:

 <?xml version="1.0" encoding="UTF-8" ?> <linker> <assembly fullname="System.Core"> <type fullname="NonExistentType" preserve="methods" /> </assembly> </linker> 

Now this just got the error message "unable to resolve visitor :: visit expression", which I saw before. It seems that type names are not checked.

Moreover, neither signature names like this also displayed the same compilation error.

 <?xml version="1.0" encoding="UTF-8" ?> <linker> <assembly fullname="System.Core"> <type fullname="System.Linq.Expressions.ExpressionVisitor"> <method signature="jg98j23890rj2390erk90fk3ew!]['##'#'[" /> </type> </assembly> </linker> 

Therefore, it seems that as long as you specify the assembly name and have the correct XML structure, the linker file does not raise any exceptions. The documentation for the linker file, however, is not particularly detailed for such a complex issue and includes numerous syntax errors, i.e.:

 <type fullname="Foo" preserve="fields" /> <method name=".ctor" /> </type> 

In addition, this does not provide a technical description of the linker file format, so it is entirely possible that my definition is completely wrong.

I also tried just skipping the System.Core binding completely with --linkskip=System.Core , but this has no effect. I have tried this flag with and without --xml .

In the MvvmCross project, I tried to specify a new class to call the Visit method in the same style as the LinkerPleaseInclude.cs file, which is added to each iOS project by the MvvmCross NuGet package:

 [Preserve] public class PleaseIncludeVisitor : ExpressionVisitor { public PleaseIncludeVisitor() { this.Visit(null); } } 

Unfortunately, this also had no effect.

I am currently using Mono 3.2.6 ((no / 9b58377) and Xamarin.iOS v7.0.7.2.

+6
source share
1 answer

The main problem is that creating code at runtime on iOS is not possible.

This means that most of System.Linq.Expressions will generally not be available under normal circumstances (just as System.Refection.Emit cannot be provided).

To get around this solution, Xamarin.iOS provides an alternative implementation (which can interpret the most common expressions).

However, the current code is not 100% API compatible with the .NET platform (which has been fixed but not yet released). For instance.

System.Linq.Expressions.Expression System.Linq.Expressions.ExpressionVisitor::Visit(System.Linq.Expressions.Expression)

The above returns void in current releases of Xamarin.iOS (7.0.x). This is why the linker complains (this is not an error) since it cannot find this member link (and if it cannot find it, it cannot recreate smaller, related assemblies). It is not possible to save a member that does not exist (so your attempts to use XML files or attributes will not help).

The current workaround is to determine which of your assemblies uses this API and rebuild it (from the source) to use the existing System.Core.dll that comes with Xamarin.iOS.

Notes

I cannot figure out how to instruct the linker not to delimit it.

The component does not try to disable it, trying to save it (i.e., it must download the link in order to save it back). However, he cannot find this element in System.Core.dll , which makes it impossible to provide a reliable bound version of the assemblies.

 <method signature="System.Linq.Expressions.Expression Visit(System.Linq.Expressions.Expression)" /> 

This requires the preservation of something that does not exist. It will be ignored, that is, when the version of void returning is found, it will not match the XML description.

+6
source

All Articles