Xamarin/MonoTouch:无法在“仅链接 SDK"中编译;由于缺少符号而导致的模式 [英] Xamarin/MonoTouch: Unable to compile in "Link SDK only" mode due to missing symbols

查看:21
本文介绍了Xamarin/MonoTouch:无法在“仅链接 SDK"中编译;由于缺少符号而导致的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Link SDK only 模式下使用 MonoTouch 编译我的 iOS 应用程序.如果我完全关闭链接,它编译完全正常,但它也会产生一个不适合发布模式的巨大二进制文件.

不幸的是,我需要的库之一以某种方式调用 Expression.Visit,但我不知道如何指示链接器不将其删除.这导致此编译错误:

<块引用>

错误 MT2002:无法解析来自System.Core,版本 = 2.0.5.0,Culture=neutral, PublicKeyToken=7cec85d7bea7798e" (MT2002) (MyApp)

根据 关于自定义链接的文档,我已经设置建立链接器文件以尝试阻止这种情况发生:

不幸的是,这没有任何影响 - 错误就像以前一样发生.

文档提到了一个 preserve="fields" 参数我可以提供给 ,所以我尝试了:

那也没有用.

然后我在文件中引入了一个 XML 语法错误,构建失败,说它无法解析链接器文件,所以我至少知道文件正在被读取.

但后来我尝试在程序集名称中引入错误:

这导致了错误,抱怨无法解决程序集.

然后我尝试修改类型名称:

现在,它刚刚开始显示我之前看到的相同的无法解析 expressionvisitor::visit"错误.似乎没有检查类型名称.

此外,签名名称也不是,因为这也出现了相同的编译错误.

这样看来,只要指定程序集名称并具有有效的 XML 结构,链接器文件就不会导致抛出任何异常.但是,链接器文件的文档对于如此复杂的主题并不是特别冗长,并且包含许多语法错误,即:

<方法名称=".ctor"/></类型>

另外,它没有给出链接器文件格式的技术描述,所以我的定义完全有可能是完全错误的.

我也尝试过完全跳过 System.Core 与 --linkskip=System.Core 的链接,但这没有效果.我在有和没有 --xml 的情况下都试过这个标志.

在 MvvmCross 项目中,我尝试指定一个新类来调用 Visit 方法,其风格与 MvvmCross NuGet 包添加到每个 iOS 项目的 LinkerPleaseInclude.cs 文件相同:

[保存]公共类 PleaseIncludeVisitor : ExpressionVisitor{公共请包括访问者(){this.Visit(null);}}

不幸的是,这也没有效果.

我目前使用的是 Mono 3.2.6 ((no/9b58377) 和 Xamarin.iOS v7.0.7.2.

解决方案

主要问题是无法在 iOS 运行时进行代码生成.

这意味着System.Linq.Expressions的很大一部分通常在正常情况下是不可能提供的(就像System.Refection.不能提供 Emit).

为了解决此问题,Xamarin.iOS 提供了一种替代实现(可以解释最常见的表达式).

然而,当前代码不是 100% 与 .NET 框架兼容的 API(已修复但尚未发布).例如.

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

以上在当前 Xamarin.iOS (7.0.x) 版本中返回 void.这就是为什么链接器会抱怨(这不是错误),因为它找不到此成员引用(如果找不到,则无法重新创建较小的链接程序集).不可能保留一个不存在的成员(这就是为什么您尝试使用 XML 文件或属性无济于事).

当前 解决方法是确定您的哪个程序集正在使用此 API 并重建它(从源代码)以使用现有的 System.Core.dll使用 Xamarin.iOS.

注意事项

<块引用>

我不知道如何指示链接器不要将其删除.

链接器不会尝试将其剥离,而是尝试将其保留(即它必须加载引用才能将其保存回来).但是,它无法在 System.Core.dll 中找到该成员,因此无法提供程序集的有效链接版本.

<块引用>

那是要求保留一些不存在的东西.它将被忽略,即当发现 void 返回版本时,它将与 XML 描述不匹配.

I am trying to compile my iOS application using MonoTouch in Link SDK only mode. It compiles completely fine if I turn off linking entirely but it also produces a colossal binary which is not suitable for release mode.

Unfortunately, one of the libraries that I need somehow invokes Expression.Visit and I can't figure out how to instruct the linker to not strip it out. This results in this compilation error:

Error MT2002: Failed to resolve "System.Linq.Expressions.Expression System.Linq.Expressions.ExpressionVisitor::Visit(System.Linq.Expressions.Expression)" reference from "System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" (MT2002) (MyApp)

As per the documentation on custom linking, I have set up a linker file to try to stop this happening:

<?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, that doesn't have any effect - the error just happens as before.

The documentation mentions a preserve="fields" parameter I can supply to <type>, so I tried that:

<?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.

I then introduced an XML syntax error into the file and the build failed saying it couldn't parse the linker file so I at least know that the file is being read.

But then I tried introducing errors into the assembly name:

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

That caused an error, complaining that the assembly couldn't be resolved.

I then tried to mangle the type name:

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

Now, that just started showing the same "unable to resolve expressionvisitor::visit" error I was seeing before. It seems that type names are not checked.

Also, neither are signature names as this also presented 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>

So it seems that so long as you specify the assembly name and have a valid XML structure, the linker file does not cause any exceptions to be thrown. The documentation for the linker file though is not especially verbose for such a complex topic and includes numerous syntax errors, i.e.:

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

Also, it doesn't give a technical description of the linker file format so it's entirely possible that my definition is totally wrong.

I have also tried just skipping the linking of System.Core entirely with --linkskip=System.Core but this has no effect. I have tried this flag both with and without --xml.

In the MvvmCross project, I tried specifying a new class to call the Visit method in the same style as the LinkerPleaseInclude.cs file that gets added to every 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.

解决方案

The main issue is that it is not possible to do code generation at runtime on iOS.

That means that a large part of System.Linq.Expressions would, normally, be impossible to provide under normal circumstances (just like System.Refection.Emit can't be provided).

To workaround this Xamarin.iOS has been providing an alternative implementation (that can interpret the most common expressions).

However the current code is not 100% API compatible with the .NET framework (that's fixed but not yet released). E.g.

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

The above returns void in the current Xamarin.iOS (7.0.x) releases. That why the linker complains (it's not a bug) as it cannot find this member reference (and if it can't find it it cannot recreate the smaller, linked, assemblies). It is not possible to preserve a member that does not exist (which is why your attempts to use XML files or attributes won't help).

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

Notes

I can't figure out how to instruct the linker to not strip it out.

The linker does not try to strip it out it tries to keep it in (i.e. it must load the reference to be able to save it back). However it cannot find that member in System.Core.dll making it impossible to provide a valid linked version of the assemblies.

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

That's asking to preserve something that does not exist. It will be ignored, i.e. when the void-returning version is found it will not match the XML description.

这篇关于Xamarin/MonoTouch:无法在“仅链接 SDK"中编译;由于缺少符号而导致的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆