もんりぃ is undefined.

育児ネタとか、技術ネタとか。

Utf8Json を macOS で動作させるまでの記録

前置き

  • Utf8Json とは、私が尊敬して止まない @neuecc さん *1 が作った C# で動作する高速な JSONリアライザのコトです。
  • 私の頭脳で理解出来た範囲で仕組みを掻い摘まむと、以下のような特徴があります。
    • 専用のコードジェネレータが、任意のディレクトリ以下にあるクラスのシリアライズ・デシリアライズのルールを C# のコードとして生成
    • ランタイムで用いられる Utf8Json.JsonSerializer.Serialize(), Utf8Json.JsonSerializer.Deserialize<T>() メソッドは、そのルールに基づいてシリアライズ・デシリアライズを行う
    • Unity でも動く!IL2CPP 環境でも動く!
      • JsonUtility でええやん」という声が聞こえた気がしますが、アイツは Dictionary のシリアライズが出来なかったり、ネストした ScriptableObject のシリアライズが出来なかったりと、色々と制約が大きいのです。
  • 何で速いのか?とかは README を読むと良いんじゃないかな?
  • で、この Utf8Json のルール定義コードを生成するジェネレータが .NET Core 2.1 な macOS 上で動作しない *2 コトが判明したので、その辺どうにかするために格闘した記録をここに綴ります。

.NET Core is 何?

  • .NET のオープンソース実装の一つです。
  • .NET Standard を使用した .NET 実装であり、Windows, macOS, Linux の何れの環境でも動作するコンソールアプリケーションを作れます。
  • 詳しいことは この記事 を参照すると良いんじゃないでしょうか。
  • まぁ、凄く雑に言えば macOS でも動く .NET です。
  • 私は、.NET 界隈に明るくないので、ググって調べた範囲だとこんな感じっぽいです。

なんで動作しないの?

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'System.Runtime.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
  • README に従って releases ページに添付してある Utf8Json.UniversalCodeGenerator というコードジェネレータのコマンドを叩くと、上記のようなエラーを吐いて落ちてしまいます。
    • dotnet Utf8Json.UniversalCodeGenerator.dll とかやっても同じでした。
    • Utf8Json.UniversalCodeGenerator.runtimeconfig.json の書き換えも試しましたがダメでした。
  • 原因は深追いしてないので不明です。
    • まぁ、エラーを見るに System.Runtime.Extensions.dll 的なモノを参照出来てないんだと思います。
    • 同一ディレクトリに存在してるんですが、それでも読めないのが謎です。.NET のバージョン問題とか?

どうやって解消したの?

  • ローカルの環境でビルドし直しました。
  • 幸いにも、コードジェネレータのソースコードGitHub に上がっているので、そのプロジェクトを JetBrains Rider 上でビルドしました。
  • 手順としては以下の通り。
    1. GitHub から clone したソースの中にあるソリューションファイル Utf8Json.sln を Rider で開く
    2. src 以下にある唯一エラーが出ていない Utf8Json.UniversalCodeGenerator というプロジェクトを選択
    3. メニューなりコンテキストメニューなりからビルド
      f:id:monry84:20180531014541p:plain
    4. src/Utf8Json.UniversalCodeGenerator/bin/Debug/netcoreapp2.0 以下に Utf8Json.UniversalCodeGenerator.dll が出来る
  • このできあがった dll を dotnet コマンド経由で実行したら以下のようにちゃんとコマンドヘルプが出るようになりました!
$ dotnet src/Utf8Json.UniversalCodeGenerator/bin/Debug/netcoreapp2.0/Utf8Json.UniversalCodeGenerator.dll
arguments help:
  -i, --inputFiles=VALUE     [optional]Input path of cs files(',' separated)
  -d, --inputDirs=VALUE      [optional]Input path of dirs(',' separated)
  -o, --output=VALUE         [required]Output file path
  -f, --allowInternal        [optional, default=false]Allow generate internal(
                               friend)
  -c, --conditionalsymbol=VALUE
                             [optional, default=empty]conditional compiler
                               symbol
  -r, --resolvername=VALUE   [optional, default=GeneratedResolver]Set resolver
                               name
  -n, --namespace=VALUE      [optional, default=MessagePack]Set namespace root
                               name

それ欲しいんだけど!

  • 元の Utf8Json が MIT ライセンスなんで多分大丈夫だとは思いますが、ビルド成果物を再配布して良いモノか分からんかったので、一先ず公開とかはしないでおきます。
    • 要望が多ければ @neuecc さんに許可とって、Fork したリポジトリの releases ページにでも添付するかも。

所感

  • 触ったコトない環境でビルドやら何やらやるのは結構骨が折れますね…。
  • アーキテクチャとかの概念がある程度分かっていないとエラーの意味が分からないし、分かっても対処の仕方が思いつかないなぁとか感じました。
  • まぁ、とりあえずやりたいことは達成できたので満足!

*1:@neuecc さんは、かの有名な UniRx の作者さんです。

*2:ちなみに、同じく @neuecc さんが作った MessagePack for C#ZeroFormatter なんかも同じくシリアライザなんですが、こちらはほぼ確実に macOS では動かないっぽい(未検証だけど)ので完全に見送っています。