global.jsonと.NET SDKのバージョン指定とロールフォワードについて

global.jsonで、.NET CLIが利用する.NETのSDKバージョンを指定する方法と、バージョン指定の際のロールフォワードについて説明します。

global.json

global.jsonファイルを配置すると、そのフォルダ以下で.NET CLIが利用する.NET SDKのバージョンを指定することができます。

global.jsonファイルが存在しない場合は、.NET CLIはインストールされている中で最新バージョンのSDKを利用します。

作成方法

dotnetコマンド経由で作成することができます。

dotnet new globaljson

成功すると下記のメッセージが出力されます。

The template "global.json file" was created successfully.

作成されるglobal.jsonで指定されるバージョンは、デフォルトでインストールされている中で最新のバージョンが指定されます。

$ cat global.json
{
  "sdk": {
    "version": "6.0.100-preview.2.21155.3"
  }
}

SDKのバージョンを指定するには--sdk-versionオプションを指定します。

$ dotnet new globaljson --sdk-version 5.0.100
The template "global.json file" was created successfully.
$ cat global.json 
{
  "sdk": {
    "version": "5.0.100"
  }
}

global.jsonのスキーマ

global.jsonでは下記の3つのプロパティが指定できます。

{
    "sdk": {
        "version": "5.0.202",
        "allowPrerelease": true,
        "rollForward": "latestFeature"
    }
}
  • version: 選択するSDKのバージョンを指定
  • allowPrerelease: プレリリースバージョン(プレビューリリースなど)の利用を許容するかどうかを指定
  • rollForward: ロールフォワードポリシーを指定

versionは文字通りSDKのバージョンを指定するプロパティ、allowPrereleaseはプレビュー版などプレリリースバージョンの利用を許容するかどうかを指定するプロパティです。

ロールフォワード

global.jsonによるSDKのバージョン指定はデフォルトでversionによるバージョンの完全マッチです。例えば5.0.202を指定した場合には、同バージョンのSDKが存在する必要があります。

例えば、インストール済みのSDKは下記とします。

# 下記コマンドにより、インストール済みの
# SDK一覧が確認可能
$ dotnet --list-sdks
2.1.300 [/usr/local/share/dotnet/sdk]
3.0.100 [/usr/local/share/dotnet/sdk]
3.0.103 [/usr/local/share/dotnet/sdk]
3.1.113 [/usr/local/share/dotnet/sdk]
3.1.115 [/usr/local/share/dotnet/sdk]
3.1.403 [/usr/local/share/dotnet/sdk]
3.1.407 [/usr/local/share/dotnet/sdk]
5.0.100 [/usr/local/share/dotnet/sdk]
5.0.202 [/usr/local/share/dotnet/sdk]
6.0.100-preview.2.21155.3 [/usr/local/share/dotnet/sdk]

また、global.jsonでは5.0.202が指定されているとします。

$ cat global.json
{
  "sdk": {
    "version": "5.0.202"
  }
}

この状態でdotnet runを実行してみます。すると互換性のあるバージョンのSDKが存在しない旨のメッセージが表示され、dotnet runが失敗します。

$ dotnet run
Could not execute because the application was not found or a compatible .NET SDK is not installed.
Possible reasons for this include:
  * You intended to execute a .NET program:
      The application 'run' does not exist.
  * You intended to execute a .NET SDK command:
      A compatible installed .NET SDK for global.json version [5.0.300] from [/Users/yucchiy/.ghq/github.com/yucchiy/memo-cli/global.json] was not found.
      Install the [5.0.300] .NET SDK or update [/Users/yucchiy/.ghq/github.com/yucchiy/memo-cli/global.json] with an installed .NET SDK:
        2.1.300 [/usr/local/share/dotnet/sdk]
        3.0.100 [/usr/local/share/dotnet/sdk]
        3.1.403 [/usr/local/share/dotnet/sdk]
        5.0.100 [/usr/local/share/dotnet/sdk]
        5.0.202 [/usr/local/share/dotnet/sdk]
        6.0.100-preview.2.21155.3 [/usr/local/share/dotnet/sdk]

これだと少し不便なのですが、(.NET Core 3.0 SDKから)フォールバックによるバージョン指定をrollForwardプロパティによりその動作を決めることができます。

ロールフォワードではフォールバックで利用されるバージョンを、そのバージョンよりも新しいバージョンから照合します。

例えば、先程のSDKのインストール状況でsdk5.0.200を、rollForwardlatestPatchで指定すると、5.0.202が選択されます

$ cat global.json
{
  "sdk": {
    "version": "5.0.200",
    "rollForward": "latestPatch"
  }
}
$ dotnet --version
5.0.202

latestPatchが指定されるとバージョンが存在しない場合に、指定されたバージョンと同様のメジャー・マイナー・フィーチャーバージョンで、最新のパッチバージョンが指定されます。(つまり、5.0.2xxというバージョンの中からxxが最新のものが選択されます)

.NET SDKのバージョニング

ロールフォワードの動作を理解するためには、.NET SDKのバージョンがどのように構成されているかを知っておく必要があります。

.NETのSDKのバージョニングについては、下記ドキュメントに詳細が記載されています。

How the .NET Runtime and SDK are versioned - .NET | Microsoft Docs

.NET SDKのバージョンは、下記の4セクションで構成されます。

.NET SDKのバージョンの構成

.NET SDKのバージョンの構成

例えば、5.0.202の場合はメジャーバージョンが5、マイナーバージョンが0、フィーチャーバージョンが2、パッチバージョンが02となります。

ロールフォワードの挙動について理解する

rollForwardには下記の9つの値からどれか1つを選択します。9つの値は大きく分けて3つのカテゴリに分類されます。

  • ロールフォワードの無効化
    • disable: ロールフォワードを利用しない。バージョンの完全一致。
  • 保守的なロールフォワード: 指定バージョンにより近いものを利用するポリシー
    • patch
    • feature
    • minor
    • major
  • 最新版へのロールフォワード: 常に新しいバージョンのSDKを利用するポリシー
    • latestPatch
    • latestFeature
    • latestMinor
    • latestMajor

ロールフォワードの無効化

disableを指定するとロールフォワードが無効化されます。指定されたSDKバージョンが存在しない場合は失敗とします。

保守的なロールフォワード

patchfeatureminormajorは指定されたバージョンから、より近いものにロールフォワードします。

具体的にはpatchを指定した場合、指定バージョンが存在しない場合にはmajorminorfeatureが同じ、最新のpatchバージョンを選択します。もし存在しない場合は失敗します。

featureを指定した場合、(指定バージョンの存在有無に関わらず)majorminorfeatureが同じ最新のpatchバージョンを選択します。もし存在しない場合は失敗します。

3.0.100
3.0.102
3.1.113
3.1.115
3.1.403
3.1.407
5.0.100
5.0.202
6.0.100-preview.2.21155.3 

例えばSDKバージョンが3.0.100が選択される場合、patchの場合は3.0.100がインストール済みため3.0.100が選択されます。featureの場合は3.0.1帯の最新パッチバージョンが選択されるため、3.0.102となります。

minorが指定されるとまずpatchが適用されます。patchが適用された場合に該当バージョンが見つからない場合は、上位のマイナーバージョンのうち最新のパッチバージョンが適用されます。

majorが指定されるとまずpatchが適用され、存在しない場合はminorを適用し、さらに存在しない場合は上位のメジャーおよびマイナー、フィーチャーバージョンの最新パッチバージョンが適用されます。

そのためSDKバージョンに3.0.100が指定されている場合は、minormajorを指定しても(featureルール適用の結果、3.0.102が適用されているため)3.0.102が選択されます。

まとめると下記の表のとおりです。

ロールフォワード 選択されるSDKバージョン 備考
patch 3.0.100 完全一致するバージョンが存在するため
feature 3.0.102 3.0.1帯の最新のパッチバージョンが適用されるため
minor 3.0.102 featureでバージョンが見つかったため
major 3.0.102 featureでバージョンが見つかったため

ちなみに、下記のようにSDKバージョンに3.0.300が指定される場合は、patchおよびfeatureでは失敗し、minor及びmajorでは3.1.115が選択されます。 (featureで失敗するのでminorで上位のマイナーの最新パッチバージョンが適用され、3.1.115となります。)

{
  "sdk": {
    "version": "3.0.300",
    "rollForward": "feature"
  }
}
ロールフォワード 選択されるSDKバージョン 備考
patch fail
feature fail
minor 3.0.115 上位マイナーバージョン 3.1.1の最新パッチが適用されるため
major 3.0.115 minorでバージョンが見つかったため

このように保守的なロールフォワードが指定される場合は、SDKバージョンが小さい順(パッチバージョン、マイナーバージョン、メジャーバージョンの順)に検索されて、あればそれが利用されるためにより近いバージョンが選択されます。

最新版へのロールフォワード

最新版へのロールフォワードは、指定されたバージョン以上の最新のバージョンへロールフォワードします。

latestPatchでは指定バージョンの最新パッチが、latestFeatureでは指定バージョンのうちの最新フィーチャーおよびパッチバージョンが、latestMinorでは最新マイナーおよびフィーチャー、パッチバージョンが、latestMajorでは最新メジャーおよびマイナー、フィーチャー、パッチバージョンが適用されます。

例えば、SDKバージョンに3.1.100が指定された場合はそれぞれ下記のとおりです。

ロールフォワード 選択されるSDKバージョン 備考
latestPatch 3.0.115 最新パッチバージョンが適用される。
latestFeature 3.1.407 最新フィーチャーおよびパッチが適用される
latestMinor 3.1.407 最新マイナーバージョンは3.1なのでlatestFeatureと結果が同様
latestMajor 6.0.100-preview.2.21155.3 最新のメジャーバージョンが適用される

ちなみに.NET CLIではデフォルトがallowPrereleasetrueなのでlatestMajorではプレビュー版がも選択対象になります。allowPrereleasefalseにすると5.0.202が選択されます。

Reference