applejag/Newtonsoft.Json-for-Unity

Add NullableAttribute to package link.xml

applejag opened this issue · 3 comments

Description

Based on the issue found by @SwingWren in #52

For some reason IL2CPP strips the NullableAttribute:.ctor(byte) constructor when using High Stripping Level, which it shouldn't as the attribute is clearly used in the referenced invokation.

Motivation

Even high managed stripping level should work.

Suggested solution

  1. Add the following to the link.xml inside the package:

    <assembly fullname="Newtonsoft.Json">
      <type fullname="System.Runtime.CompilerServices.NullableAttribute"/>
      <type fullname="System.Runtime.CompilerServices.NullableContextAttribute"/>
    </assembly>
  2. Add a forum post on https://forum.unity.com asking if this is intended or buggy behaviour

Inspiration sources

Media

Signature from metadata inside Visual Studio:

        [NullableAttribute(2)]
        public JToken? this[string propertyName] { get; set; }

IL:


  .method public hidebysig newslot specialname virtual final 
          instance void  set_Item(string propertyName,
                                  class Newtonsoft.Json.Linq.JToken 'value') cil managed
  {
    .param [2]
    .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) 
    // Code size       43 (0x2b)
    .maxstack  3
    .locals init (class Newtonsoft.Json.Linq.JProperty V_0)
    IL_0000:  ldarg.0
    IL_0001:  ldarg.1
    IL_0002:  ldc.i4.4
    IL_0003:  call       instance class Newtonsoft.Json.Linq.JProperty Newtonsoft.Json.Linq.JObject::Property(string,
                                                                                                              valuetype [netstandard]System.StringComparison)
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  brfalse.s  IL_0014

    IL_000c:  ldloc.0
    IL_000d:  ldarg.2
    IL_000e:  callvirt   instance void Newtonsoft.Json.Linq.JProperty::set_Value(class Newtonsoft.Json.Linq.JToken)
    IL_0013:  ret

    IL_0014:  ldarg.0
    IL_0015:  ldarg.1
    IL_0016:  callvirt   instance void Newtonsoft.Json.Linq.JObject::OnPropertyChanging(string)
    IL_001b:  ldarg.0
    IL_001c:  ldarg.1
    IL_001d:  ldarg.2
    IL_001e:  call       instance void Newtonsoft.Json.Linq.JObject::Add(string,
                                                                         class Newtonsoft.Json.Linq.JToken)
    IL_0023:  ldarg.0
    IL_0024:  ldarg.1
    IL_0025:  callvirt   instance void Newtonsoft.Json.Linq.JObject::OnPropertyChanged(string)
    IL_002a:  ret
  } // end of method JObject::set_Item

JObject.get_Item source code:

https://github.com/jilleJr/Newtonsoft.Json-for-Unity/blob/dcc556f12e7663526356c828da9736f69048bbf0/Src/Newtonsoft.Json/Linq/JObject.cs#L352-L382

Error message on build:

Failed running C:\Program Files\Unity\Hub\Editor\2019.3.3f1\Editor\Data\il2cpp\build/deploy/net471/UnityLinker.exe -out="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed/tempStrip" -x="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed/TypesInScenes.xml" -x="C:/dev/JsonNet-for-Unity #52/Assets/link.xml" -d="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed" --include-unity-root-assembly="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed/Assembly-CSharp.dll" --dotnetruntime=il2cpp --dotnetprofile=unityaot --use-editor-options --include-directory="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed" --editor-settings-flag=Development --rule-set=Experimental --editor-data-file="C:/dev/JsonNet-for-Unity #52/Temp/StagingArea/Data/Managed/EditorToUnityLinkerData.json" --platform=WindowsDesktop --engine-modules-asset-file="C:/Program Files/Unity/Hub/Editor/2019.3.3f1/Editor/Data/PlaybackEngines/WindowsStandaloneSupport/Whitelists/../modules.asset"

stdout:
Fatal error in Unity CIL Linker
System.ArgumentException: Member 'System.Void System.Runtime.CompilerServices.NullableAttribute::.ctor(System.Byte)' is declared in another module and needs to be imported
   at Mono.Cecil.MetadataBuilder.LookupToken(IMetadataTokenProvider provider)
   at Mono.Cecil.MetadataBuilder.AddCustomAttributes(ICustomAttributeProvider owner)
   at Mono.Cecil.MetadataBuilder.AddConstraints(GenericParameter generic_parameter, GenericParamConstraintTable table)
   at Mono.Cecil.MetadataBuilder.AddGenericParameters()
   at Mono.Cecil.MetadataBuilder.BuildModule()
   at Mono.Cecil.MetadataBuilder.BuildMetadata()
   at Mono.Cecil.ModuleWriter.<>c.<BuildMetadata>b__2_0(MetadataBuilder builder, MetadataReader _)
   at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
   at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
   at Mono.Linker.Steps.OutputStep.WriteAssembly(AssemblyDefinition assembly, String directory, WriterParameters writerParameters)
   at Unity.Linker.Steps.UnityOutputStep.WriteAssembly(AssemblyDefinition assembly, String directory, WriterParameters writerParameters)
   at Mono.Linker.Steps.OutputStep.OutputAssembly(AssemblyDefinition assembly)
   at Mono.Linker.Steps.BaseStep.Process(LinkContext context)
   at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step)
   at Unity.Linker.UnityPipeline.ProcessStep(LinkContext context, IStep step)
   at Mono.Linker.Pipeline.Process(LinkContext context)
   at Unity.Linker.UnityDriver.Run()
   at Unity.Linker.UnityDriver.RunDriverWithoutErrorHandling()
   at Unity.Linker.UnityDriver.RunDriver()
stderr:

UnityEngine.Debug:LogError(Object)
UnityEditorInternal.Runner:RunProgram(Program, String, String, String, CompilerOutputParserBase)
UnityEditorInternal.Runner:RunManagedProgram(String, String, String, CompilerOutputParserBase, Action`1)
UnityEditorInternal.AssemblyStripper:RunAssemblyLinker(IEnumerable`1, String&, String&, String, String)
UnityEditorInternal.AssemblyStripper:StripAssembliesTo(String, String&, String&, IEnumerable`1, UnityLinkerRunInformation)
UnityEditorInternal.AssemblyStripper:RunAssemblyStripper(UnityLinkerRunInformation)
UnityEditorInternal.AssemblyStripper:StripAssemblies(String, BaseUnityLinkerPlatformProvider, IIl2CppPlatformProvider, RuntimeClassRegistry, ManagedStrippingLevel)
UnityEditorInternal.IL2CPPBuilder:Run()
UnityEditorInternal.IL2CPPUtils:RunIl2Cpp(String, IIl2CppPlatformProvider, Action`1, RuntimeClassRegistry)
DesktopStandalonePostProcessor:SetupStagingArea(BuildPostProcessArgs, HashSet`1)
DesktopStandalonePostProcessor:PostProcess(BuildPostProcessArgs)
UnityEditor.EditorApplication:Internal_CallGlobalEventHandler()

I also ran into this and your workaround works for me too! Looking around for the error initially, I also found a post on the unity forum of the "same" issue:

https://forum.unity.com/threads/fatal-error-in-unity-cil-linker-2017-2-0f3.500439/page-2#post-5737972

Unfortunately it looks like the guy didn't follow-up after Unity asked for bug report.

@timheijden Hey good find! I can try do a repro and post it in the same thread as the one you linked. Nice

@timheijden I was not able to correlate this issue with the ones mentioned in the forum thread you linked. I was however able to find a different workaround to get these link.xml changes embedded into the package and I've written about it here: https://forum.unity.com/threads/while-custom-package-need-a-link-xml.727460/#post-6708610