noxi雑記

.NET、Angularまわりの小ネタブログ

.NET CoreのSingle Fileを試す

.NET Core 3.0 で標準機能として実装された単一ファイル実行モード。リリースからはや9ヶ月、既に .NET 5 の足音が聞こえ始めており今更感が拭えませんが、単一ファイルにするとどうなるのか、どう実行されるのか、色々試してみたメモです。

docs.microsoft.com



環境

単一ファイルで発行する

単一ファイルに関する公式なドキュメントは参考 1 2 にリンクがあります。今回試したのは .NET 3 のみです。

.NET Core で単一ファイル発行を行うには、発行時に PublishSingleFile フラグを設定します。単一ファイルで発行する場合は実行環境にインストールされているランタイムを使用するモードは使用できず、自己完結型となるように実行先の OS 指定( runtime identifier の指定)が必要です。単一ファイルで発行すると特に指定が無い限り発行先のディレクトリに exe ファイルと pdb ファイルがそれぞれ1つずつ出力されます。

フラグを設定する方法は3つあるので、順に説明していきます。

Visual Studio の発行を使用する

最初は Visual Studio の発行機能で exe ファイルを出力する際に単一ファイルで出力する方法です。発行オプションでターゲットランタイムの設定をクリックし、配置モードを「自己完結」に変更すると単一ファイル出力を行う為の設定が表示されるようになります。

f:id:noxi515:20200607193841p:plain
ターゲットランタイムの設定をクリック

f:id:noxi515:20200607194209p:plain
プロファイル設定で配置モードと単一ファイル出力の設定

csproj でフラグを設定する

続いてプロジェクトの csproj ファイルに PublishSingleFile フラグを記述する方法です。自己完結型で出力せねばならないため、同時に RuntimeIdentifier も指定します。 RuntimeIdentifier はこのカタログ 3 の中から指定します。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>

    <!-- 単一ファイルで発行 -->
    <PublishSingleFile>true</PublishSingleFile>

    <!-- 実行環境の指定 -->
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>

  </PropertyGroup>

</Project>

そして発行コマンド dotnet publish を実行すると単一ファイルが出力されます。なお RuntimeIdentifier は csproj ファイルに記述せずに -r または --runtime-identifier コマンドオプションで指定することもできます。その場合 dotnet publish -r win-x64 となります。

コマンドオプションでフラグ指定する

最後に dotnet publish コマンド実行時に PublishSingleFile をオプションで指定する方法です。指定するオプションは -p:PublishSingleFile で、 dotnet publish -r win-x64 -p:PublishSingleFile=true と実行します。

単一ファイルを実行する

単一 exe ファイルが発行できたら次は実行です。
単一ファイルとして発行された exe の実行は exe ファイルの中身が直接メモリー上に展開されて実行されるのでは無く、ディスク上の TEMP 領域に中身が1回展開された後に実行されます。この中身の展開は同じ exe ファイルを複数回実行しても1回のみ行われます。

ファイル展開先の TEMP 領域は次のようになります。

  • DOTNET_BUNDLE_EXTRACT_BASE_DIR 環境変数
  • Windows の場合 %TEMP%\.net
  • Unix の場合 ${TMPDIR}/.net/${UID} または /var/tmp/.net/${UID} または /tmp/.net/${UID}

このディレクトリーに更に単一ファイルのファイル名とバンドル ID がネストしたディレクトリー作成されます。例えば ConsoleApp1.exe という単一ファイルを実行すると筆者の Windows 環境では C:\Users\noxi\AppData\Local\Temp\.net\ConsoleApp1\rk1zyyxi.zp1 に単一ファイルの中身が展開されました。展開されたファイルは単一ファイルを指定せずに発行した場合の出力結果と比較すると、単一ファイルから展開された方には ConsoleApp1.exeConsoleApp1.pdb ファイルが存在しないことを除いて同一です。

PS C:\Users\noxi\AppData\Local\Temp\.net\ConsoleApp1\rk1zyyxi.zp1> ls


    Directory: C:\Users\noxi\AppData\Local\Temp\.net\ConsoleApp1\rk1zyyxi.zp1

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2020/06/08     9:15          19208 api-ms-win-core-console-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-datetime-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-debug-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-errorhandling-l1-1-0.dll
-a---          2020/06/08     9:15          22280 api-ms-win-core-file-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-file-l1-2-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-file-l2-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-handle-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-heap-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-interlocked-l1-1-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-core-libraryloader-l1-1-0.dll
-a---          2020/06/08     9:15          21256 api-ms-win-core-localization-l1-2-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-memory-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-namedpipe-l1-1-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-core-processenvironment-l1-1-0.dll
-a---          2020/06/08     9:15          20744 api-ms-win-core-processthreads-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-processthreads-l1-1-1.dll
-a---          2020/06/08     9:15          18184 api-ms-win-core-profile-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-rtlsupport-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-string-l1-1-0.dll
-a---          2020/06/08     9:15          20744 api-ms-win-core-synch-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-synch-l1-2-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-core-sysinfo-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-core-timezone-l1-1-0.dll
-a---          2020/06/08     9:15          18696 api-ms-win-core-util-l1-1-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-crt-conio-l1-1-0.dll
-a---          2020/06/08     9:15          22792 api-ms-win-crt-convert-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-crt-environment-l1-1-0.dll
-a---          2020/06/08     9:15          20744 api-ms-win-crt-filesystem-l1-1-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-crt-heap-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-crt-locale-l1-1-0.dll
-a---          2020/06/08     9:15          27912 api-ms-win-crt-math-l1-1-0.dll
-a---          2020/06/08     9:15          26888 api-ms-win-crt-multibyte-l1-1-0.dll
-a---          2020/06/08     9:15          71432 api-ms-win-crt-private-l1-1-0.dll
-a---          2020/06/08     9:15          19720 api-ms-win-crt-process-l1-1-0.dll
-a---          2020/06/08     9:15          23304 api-ms-win-crt-runtime-l1-1-0.dll
-a---          2020/06/08     9:15          24840 api-ms-win-crt-stdio-l1-1-0.dll
-a---          2020/06/08     9:15          24840 api-ms-win-crt-string-l1-1-0.dll
-a---          2020/06/08     9:15          21256 api-ms-win-crt-time-l1-1-0.dll
-a---          2020/06/08     9:15          19208 api-ms-win-crt-utility-l1-1-0.dll
-a---          2020/06/08     9:15         747392 clrcompression.dll
-a---          2020/06/08     9:15         243592 clretwrc.dll
-a---          2020/06/08     9:15        1304456 clrjit.dll
-a---          2020/06/08     9:15          33131 ConsoleApp1.deps.json
-a---          2020/06/08     9:15           4096 ConsoleApp1.dll
-a---          2020/06/08     9:15            185 ConsoleApp1.runtimeconfig.json
-a---          2020/06/08     9:15        5588872 coreclr.dll
-a---          2020/06/08     9:15         136072 dbgshim.dll
-a---          2020/06/08     9:15         599632 hostfxr.dll
-a---          2020/06/08     9:15         590928 hostpolicy.dll
-a---          2020/06/08     9:15         797576 Microsoft.CSharp.dll
-a---          2020/06/08     9:15        1495800 Microsoft.DiaSymReader.Native.amd64.dll
-a---          2020/06/08     9:15        1209936 Microsoft.VisualBasic.Core.dll
-a---          2020/06/08     9:15          16464 Microsoft.VisualBasic.dll
-a---          2020/06/08     9:15          21584 Microsoft.Win32.Primitives.dll
-a---          2020/06/08     9:15          83024 Microsoft.Win32.Registry.dll
-a---          2020/06/08     9:15        1263480 mscordaccore.dll
-a---          2020/06/08     9:15        1263480 mscordaccore_amd64_amd64_4.700.20.20201.dll
-a---          2020/06/08     9:15        1318280 mscordbi.dll
-a---          2020/06/08     9:15          57208 mscorlib.dll
-a---          2020/06/08     9:15         178568 mscorrc.debug.dll
-a---          2020/06/08     9:15          13192 mscorrc.dll
-a---          2020/06/08     9:15         114256 netstandard.dll
-a---          2020/06/08     9:15            277 SOS_README.md
-a---          2020/06/08     9:15          13904 System.AppContext.dll
-a---          2020/06/08     9:15          14416 System.Buffers.dll
-a---          2020/06/08     9:15         189032 System.Collections.Concurrent.dll
-a---          2020/06/08     9:15         331344 System.Collections.dll
-a---          2020/06/08     9:15         648296 System.Collections.Immutable.dll
-a---          2020/06/08     9:15          96848 System.Collections.NonGeneric.dll
-a---          2020/06/08     9:15          90192 System.Collections.Specialized.dll
-a---          2020/06/08     9:15         162384 System.ComponentModel.Annotations.dll
-a---          2020/06/08     9:15          15952 System.ComponentModel.DataAnnotations.dll
-a---          2020/06/08     9:15          15952 System.ComponentModel.dll
-a---          2020/06/08     9:15          34384 System.ComponentModel.EventBasedAsync.dll
-a---          2020/06/08     9:15          53328 System.ComponentModel.Primitives.dll
-a---          2020/06/08     9:15         707152 System.ComponentModel.TypeConverter.dll
-a---          2020/06/08     9:15          18512 System.Configuration.dll
-a---          2020/06/08     9:15         153168 System.Console.dll
-a---          2020/06/08     9:15          23632 System.Core.dll
-a---          2020/06/08     9:15        2912648 System.Data.Common.dll
-a---          2020/06/08     9:15          14416 System.Data.DataSetExtensions.dll
-a---          2020/06/08     9:15          25680 System.Data.dll
-a---          2020/06/08     9:15          14928 System.Diagnostics.Contracts.dll
-a---          2020/06/08     9:15          14416 System.Diagnostics.Debug.dll
-a---          2020/06/08     9:15          99408 System.Diagnostics.DiagnosticSource.dll
-a---          2020/06/08     9:15          29264 System.Diagnostics.FileVersionInfo.dll
-a---          2020/06/08     9:15         257104 System.Diagnostics.Process.dll
-a---          2020/06/08     9:15          35408 System.Diagnostics.StackTrace.dll
-a---          2020/06/08     9:15          55888 System.Diagnostics.TextWriterTraceListener.dll
-a---          2020/06/08     9:15          16976 System.Diagnostics.Tools.dll
-a---          2020/06/08     9:15         125520 System.Diagnostics.TraceSource.dll
-a---          2020/06/08     9:15          15440 System.Diagnostics.Tracing.dll
-a---          2020/06/08     9:15          54352 System.dll
-a---          2020/06/08     9:15          20048 System.Drawing.dll
-a---          2020/06/08     9:15         123984 System.Drawing.Primitives.dll
-a---          2020/06/08     9:15          15464 System.Dynamic.Runtime.dll
-a---          2020/06/08     9:15          14928 System.Globalization.Calendars.dll
-a---          2020/06/08     9:15          14416 System.Globalization.dll
-a---          2020/06/08     9:15          14928 System.Globalization.Extensions.dll
-a---          2020/06/08     9:15          69712 System.IO.Compression.Brotli.dll
-a---          2020/06/08     9:15         247376 System.IO.Compression.dll
-a---          2020/06/08     9:15          14416 System.IO.Compression.FileSystem.dll
-a---          2020/06/08     9:15          34384 System.IO.Compression.ZipFile.dll
-a---          2020/06/08     9:15          14416 System.IO.dll
-a---          2020/06/08     9:15          87120 System.IO.FileSystem.AccessControl.dll
-a---          2020/06/08     9:15         217704 System.IO.FileSystem.dll
-a---          2020/06/08     9:15          37968 System.IO.FileSystem.DriveInfo.dll
-a---          2020/06/08     9:15          14416 System.IO.FileSystem.Primitives.dll
-a---          2020/06/08     9:15          69200 System.IO.FileSystem.Watcher.dll
-a---          2020/06/08     9:15          79440 System.IO.IsolatedStorage.dll
-a---          2020/06/08     9:15          63568 System.IO.MemoryMappedFiles.dll
-a---          2020/06/08     9:15          14416 System.IO.Pipes.AccessControl.dll
-a---          2020/06/08     9:15         130440 System.IO.Pipes.dll
-a---          2020/06/08     9:15          14440 System.IO.UnmanagedMemoryStream.dll
-a---          2020/06/08     9:15         420744 System.Linq.dll
-a---          2020/06/08     9:15        5256584 System.Linq.Expressions.dll
-a---          2020/06/08     9:15        1310600 System.Linq.Parallel.dll
-a---          2020/06/08     9:15         177544 System.Linq.Queryable.dll
-a---          2020/06/08     9:15         180104 System.Memory.dll
-a---          2020/06/08     9:15          16488 System.Net.dll
-a---          2020/06/08     9:15        1477000 System.Net.Http.dll
-a---          2020/06/08     9:15         653704 System.Net.HttpListener.dll
-a---          2020/06/08     9:15         545160 System.Net.Mail.dll
-a---          2020/06/08     9:15          86408 System.Net.NameResolution.dll
-a---          2020/06/08     9:15         174984 System.Net.NetworkInformation.dll
-a---          2020/06/08     9:15          97872 System.Net.Ping.dll
-a---          2020/06/08     9:15         212872 System.Net.Primitives.dll
-a---          2020/06/08     9:15         346704 System.Net.Requests.dll
-a---          2020/06/08     9:15         574544 System.Net.Security.dll
-a---          2020/06/08     9:15          33360 System.Net.ServicePoint.dll
-a---          2020/06/08     9:15         540552 System.Net.Sockets.dll
-a---          2020/06/08     9:15         158800 System.Net.WebClient.dll
-a---          2020/06/08     9:15          66640 System.Net.WebHeaderCollection.dll
-a---          2020/06/08     9:15          25992 System.Net.WebProxy.dll
-a---          2020/06/08     9:15          71248 System.Net.WebSockets.Client.dll
-a---          2020/06/08     9:15         140880 System.Net.WebSockets.dll
-a---          2020/06/08     9:15          14440 System.Numerics.dll
-a---          2020/06/08     9:15         149584 System.Numerics.Vectors.dll
-a---          2020/06/08     9:15          87632 System.ObjectModel.dll
-a---          2020/06/08     9:15        9556872 System.Private.CoreLib.dll
-a---          2020/06/08     9:15        2060368 System.Private.DataContractSerialization.dll
-a---          2020/06/08     9:15         242768 System.Private.Uri.dll
-a---          2020/06/08     9:15        8423816 System.Private.Xml.dll
-a---          2020/06/08     9:15         370768 System.Private.Xml.Linq.dll
-a---          2020/06/08     9:15          69200 System.Reflection.DispatchProxy.dll
-a---          2020/06/08     9:15          15440 System.Reflection.dll
-a---          2020/06/08     9:15          14416 System.Reflection.Emit.dll
-a---          2020/06/08     9:15          14440 System.Reflection.Emit.ILGeneration.dll
-a---          2020/06/08     9:15          14440 System.Reflection.Emit.Lightweight.dll
-a---          2020/06/08     9:15          14416 System.Reflection.Extensions.dll
-a---          2020/06/08     9:15        1071184 System.Reflection.Metadata.dll
-a---          2020/06/08     9:15          14928 System.Reflection.Primitives.dll
-a---          2020/06/08     9:15          28552 System.Reflection.TypeExtensions.dll
-a---          2020/06/08     9:15          14416 System.Resources.Reader.dll
-a---          2020/06/08     9:15          14728 System.Resources.ResourceManager.dll
-a---          2020/06/08     9:15          42064 System.Resources.Writer.dll
-a---          2020/06/08     9:15          19024 System.Runtime.CompilerServices.Unsafe.dll
-a---          2020/06/08     9:15          17488 System.Runtime.CompilerServices.VisualC.dll
-a---          2020/06/08     9:15          53328 System.Runtime.dll
-a---          2020/06/08     9:15         206416 System.Runtime.Extensions.dll
-a---          2020/06/08     9:15          14440 System.Runtime.Handles.dll
-a---          2020/06/08     9:15          53328 System.Runtime.InteropServices.dll
-a---          2020/06/08     9:15          27216 System.Runtime.InteropServices.RuntimeInformation.dll
-a---          2020/06/08     9:15          15440 System.Runtime.InteropServices.WindowsRuntime.dll
-a---          2020/06/08     9:15          14928 System.Runtime.Intrinsics.dll
-a---          2020/06/08     9:15          14416 System.Runtime.Loader.dll
-a---          2020/06/08     9:15         196688 System.Runtime.Numerics.dll
-a---          2020/06/08     9:15          15952 System.Runtime.Serialization.dll
-a---          2020/06/08     9:15         308816 System.Runtime.Serialization.Formatters.dll
-a---          2020/06/08     9:15          14928 System.Runtime.Serialization.Json.dll
-a---          2020/06/08     9:15          25680 System.Runtime.Serialization.Primitives.dll
-a---          2020/06/08     9:15          15440 System.Runtime.Serialization.Xml.dll
-a---          2020/06/08     9:15         355408 System.Runtime.WindowsRuntime.dll
-a---          2020/06/08     9:15          75344 System.Runtime.WindowsRuntime.UI.Xaml.dll
-a---          2020/06/08     9:15         211560 System.Security.AccessControl.dll
-a---          2020/06/08     9:15          89168 System.Security.Claims.dll
-a---          2020/06/08     9:15         691280 System.Security.Cryptography.Algorithms.dll
-a---          2020/06/08     9:15         432008 System.Security.Cryptography.Cng.dll
-a---          2020/06/08     9:15         177744 System.Security.Cryptography.Csp.dll
-a---          2020/06/08     9:15          70736 System.Security.Cryptography.Encoding.dll
-a---          2020/06/08     9:15          32848 System.Security.Cryptography.OpenSsl.dll
-a---          2020/06/08     9:15         101992 System.Security.Cryptography.Primitives.dll
-a---          2020/06/08     9:15         464464 System.Security.Cryptography.X509Certificates.dll
-a---          2020/06/08     9:15          17488 System.Security.dll
-a---          2020/06/08     9:15          14416 System.Security.Principal.dll
-a---          2020/06/08     9:15         144976 System.Security.Principal.Windows.dll
-a---          2020/06/08     9:15          14416 System.Security.SecureString.dll
-a---          2020/06/08     9:15          15952 System.ServiceModel.Web.dll
-a---          2020/06/08     9:15          14928 System.ServiceProcess.dll
-a---          2020/06/08     9:15         858504 System.Text.Encoding.CodePages.dll
-a---          2020/06/08     9:15          14928 System.Text.Encoding.dll
-a---          2020/06/08     9:15          14216 System.Text.Encoding.Extensions.dll
-a---          2020/06/08     9:15          99208 System.Text.Encodings.Web.dll
-a---          2020/06/08     9:15         826960 System.Text.Json.dll
-a---          2020/06/08     9:15         393808 System.Text.RegularExpressions.dll
-a---          2020/06/08     9:15         111696 System.Threading.Channels.dll
-a---          2020/06/08     9:15          76680 System.Threading.dll
-a---          2020/06/08     9:15          15440 System.Threading.Overlapped.dll
-a---          2020/06/08     9:15         478824 System.Threading.Tasks.Dataflow.dll
-a---          2020/06/08     9:15          15752 System.Threading.Tasks.dll
-a---          2020/06/08     9:15          14928 System.Threading.Tasks.Extensions.dll
-a---          2020/06/08     9:15         107912 System.Threading.Tasks.Parallel.dll
-a---          2020/06/08     9:15          16776 System.Threading.Thread.dll
-a---          2020/06/08     9:15          14416 System.Threading.ThreadPool.dll
-a---          2020/06/08     9:15          14416 System.Threading.Timer.dll
-a---          2020/06/08     9:15          15440 System.Transactions.dll
-a---          2020/06/08     9:15         348240 System.Transactions.Local.dll
-a---          2020/06/08     9:15          14416 System.ValueTuple.dll
-a---          2020/06/08     9:15          13904 System.Web.dll
-a---          2020/06/08     9:15          45136 System.Web.HttpUtility.dll
-a---          2020/06/08     9:15          14416 System.Windows.dll
-a---          2020/06/08     9:15          24144 System.Xml.dll
-a---          2020/06/08     9:15          14928 System.Xml.Linq.dll
-a---          2020/06/08     9:15          21584 System.Xml.ReaderWriter.dll
-a---          2020/06/08     9:15          14928 System.Xml.Serialization.dll
-a---          2020/06/08     9:15          14928 System.Xml.XDocument.dll
-a---          2020/06/08     9:15          14728 System.Xml.XmlDocument.dll
-a---          2020/06/08     9:15          17000 System.Xml.XmlSerializer.dll
-a---          2020/06/08     9:15          14440 System.Xml.XPath.dll
-a---          2020/06/08     9:15          15952 System.Xml.XPath.XDocument.dll
-a---          2020/06/08     9:15        1016584 ucrtbase.dll
-a---          2020/06/08     9:15          15440 WindowsBase.dll

実行時に設定を上書きする

単一ファイルとして発行すると設定ファイルを含めて1つのファイルになってしまいますので、よくある、配置した後に設定ファイルを更新する運用ができなくなります。この場合に設定値を更新するには環境変数を利用します。
.NET の設定ライブラリー( Microsoft.Extensions.Configuration )には環境変数を設定値としてマッピングする機能があります。 Host.CreateDefaultBuilder を使用してコンソールアプリを実行している場合には自動で環境変数の設定値マッピングは含まれているため、特に何もせずとも利用できます。