やりたいこと
VisualStudioでビルドしたものと、dotnet publishでビルドしたものの、どちらを最終成果物として使えばよいか?がわかならなかった。
Microsoftの公式ページを見ても、はっきりわかる情報が見つけられないので、いろいろ試してなんとなくどれ使うかを納得したうえで決めたい。
とりあえず、VSでビルドしたときにできるものは、csprojの中に書いてある設定が反映されていて、dotnet publishで出来上がるものにはそれに渡したオプションが反映されてるっぽいので、その2つをいろいろ試してみる。
csprojの各種項目
まず、VisualStudio2022でDebugビルドをしたときに、bin\x64\Debug
の下になにができるかを見てみる。
実験で、nugetのMicrosoft.Toolkit.Uwp.Notifications
のパッケージを使い、トーストを出すアプリを使ったので、ターゲットフレームワークにWindowsのバージョンが指定されている。(その状態を、今回の標準とする。)
標準
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
ビルドすると、
こういうフォルダとなかみができる
└─net6.0-windows10.0.17763.0 │ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ ├─ref │ ConsoleApp1.dll │ └─runtimes ├─unix │ └─lib │ └─netcoreapp3.0 │ System.Drawing.Common.dll │ └─win └─lib └─netcoreapp3.0 Microsoft.Win32.SystemEvents.dll System.Drawing.Common.dll
RuntimeIdentifierを指定
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> ★<SelfContained>false</SelfContained> ★<RuntimeIdentifier>win-x64</RuntimeIdentifier> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
RuntimeIdentifierを書くと、こうなる。
※RuntimeIdentifierをtrueにすると、デフォでSelfContainedがtrueになるので、手動でSelfContainedはfalseにして試した
→成果物がRIDフォルダの下に入って、
runtimeフォルダがなくなる(RID指定したからruntime不要になったということか)
├─net6.0-windows10.0.17763.0 │ └─win-x64 │ │ ConsoleApp1.deps.json │ │ ConsoleApp1.dll │ │ ConsoleApp1.exe │ │ ConsoleApp1.pdb │ │ ConsoleApp1.runtimeconfig.json │ │ Microsoft.Toolkit.Uwp.Notifications.dll │ │ Microsoft.Win32.SystemEvents.dll │ │ Microsoft.Windows.SDK.NET.dll │ │ System.Drawing.Common.dll │ │ UnitTestJikken.dll │ │ UnitTestJikken.pdb │ │ WinRT.Runtime.dll │ │ │ └─ref │ ConsoleApp1.dll
RuntimeIdentifierを指定、SelfContainedも指定
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> <SelfContained>true</SelfContained> <RuntimeIdentifier>win-x64</RuntimeIdentifier> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
SelfContainedを指定すると、.net6のランタイム(PCにランタイムがなくても動けるようにするためのもの)のファイル一式が入る。
├─net6.0-windows10.0.17763.0 │ └─win-x64 │ │ api-ms-win-core-console-l1-1-0.dll │ │ api-ms-win-core-console-l1-2-0.dll │ │ api-ms-win-core-datetime-l1-1-0.dll │ │ api-ms-win-core-debug-l1-1-0.dll │ │ api-ms-win-core-errorhandling-l1-1-0.dll │ │ api-ms-win-core-file-l1-1-0.dll │ │ api-ms-win-core-file-l1-2-0.dll │ │ api-ms-win-core-file-l2-1-0.dll │ │ api-ms-win-core-handle-l1-1-0.dll │ │ api-ms-win-core-heap-l1-1-0.dll │ │ api-ms-win-core-interlocked-l1-1-0.dll │ │ api-ms-win-core-libraryloader-l1-1-0.dll │ │ api-ms-win-core-localization-l1-2-0.dll │ │ api-ms-win-core-memory-l1-1-0.dll │ │ api-ms-win-core-namedpipe-l1-1-0.dll │ │ api-ms-win-core-processenvironment-l1-1-0.dll │ │ api-ms-win-core-processthreads-l1-1-0.dll │ │ api-ms-win-core-processthreads-l1-1-1.dll │ │ api-ms-win-core-profile-l1-1-0.dll │ │ api-ms-win-core-rtlsupport-l1-1-0.dll │ │ api-ms-win-core-string-l1-1-0.dll │ │ api-ms-win-core-synch-l1-1-0.dll │ │ api-ms-win-core-synch-l1-2-0.dll │ │ api-ms-win-core-sysinfo-l1-1-0.dll │ │ api-ms-win-core-timezone-l1-1-0.dll │ │ api-ms-win-core-util-l1-1-0.dll │ │ api-ms-win-crt-conio-l1-1-0.dll │ │ api-ms-win-crt-convert-l1-1-0.dll │ │ api-ms-win-crt-environment-l1-1-0.dll │ │ api-ms-win-crt-filesystem-l1-1-0.dll │ │ api-ms-win-crt-heap-l1-1-0.dll │ │ api-ms-win-crt-locale-l1-1-0.dll │ │ api-ms-win-crt-math-l1-1-0.dll │ │ api-ms-win-crt-multibyte-l1-1-0.dll │ │ api-ms-win-crt-private-l1-1-0.dll │ │ api-ms-win-crt-process-l1-1-0.dll │ │ api-ms-win-crt-runtime-l1-1-0.dll │ │ api-ms-win-crt-stdio-l1-1-0.dll │ │ api-ms-win-crt-string-l1-1-0.dll │ │ api-ms-win-crt-time-l1-1-0.dll │ │ api-ms-win-crt-utility-l1-1-0.dll │ │ clretwrc.dll │ │ clrjit.dll │ │ ConsoleApp1.deps.json │ │ ConsoleApp1.dll │ │ ConsoleApp1.exe │ │ ConsoleApp1.pdb │ │ ConsoleApp1.runtimeconfig.json │ │ coreclr.dll │ │ createdump.exe │ │ dbgshim.dll │ │ hostfxr.dll │ │ hostpolicy.dll │ │ Microsoft.CSharp.dll │ │ Microsoft.DiaSymReader.Native.amd64.dll │ │ Microsoft.Toolkit.Uwp.Notifications.dll │ │ Microsoft.VisualBasic.Core.dll │ │ Microsoft.VisualBasic.dll │ │ Microsoft.Win32.Primitives.dll │ │ Microsoft.Win32.Registry.dll │ │ Microsoft.Win32.SystemEvents.dll │ │ Microsoft.Windows.SDK.NET.dll │ │ mscordaccore.dll │ │ mscordaccore_amd64_amd64_6.0.21.52210.dll │ │ mscordbi.dll │ │ mscorlib.dll │ │ mscorrc.dll │ │ msquic.dll │ │ netstandard.dll │ │ System.AppContext.dll │ │ System.Buffers.dll │ │ System.Collections.Concurrent.dll │ │ System.Collections.dll │ │ System.Collections.Immutable.dll │ │ System.Collections.NonGeneric.dll │ │ System.Collections.Specialized.dll │ │ System.ComponentModel.Annotations.dll │ │ System.ComponentModel.DataAnnotations.dll │ │ System.ComponentModel.dll │ │ System.ComponentModel.EventBasedAsync.dll │ │ System.ComponentModel.Primitives.dll │ │ System.ComponentModel.TypeConverter.dll │ │ System.Configuration.dll │ │ System.Console.dll │ │ System.Core.dll │ │ System.Data.Common.dll │ │ System.Data.DataSetExtensions.dll │ │ System.Data.dll │ │ System.Diagnostics.Contracts.dll │ │ System.Diagnostics.Debug.dll │ │ System.Diagnostics.DiagnosticSource.dll │ │ System.Diagnostics.FileVersionInfo.dll │ │ System.Diagnostics.Process.dll │ │ System.Diagnostics.StackTrace.dll │ │ System.Diagnostics.TextWriterTraceListener.dll │ │ System.Diagnostics.Tools.dll │ │ System.Diagnostics.TraceSource.dll │ │ System.Diagnostics.Tracing.dll │ │ System.dll │ │ System.Drawing.Common.dll │ │ System.Drawing.dll │ │ System.Drawing.Primitives.dll │ │ System.Dynamic.Runtime.dll │ │ System.Formats.Asn1.dll │ │ System.Globalization.Calendars.dll │ │ System.Globalization.dll │ │ System.Globalization.Extensions.dll │ │ System.IO.Compression.Brotli.dll │ │ System.IO.Compression.dll │ │ System.IO.Compression.FileSystem.dll │ │ System.IO.Compression.Native.dll │ │ System.IO.Compression.ZipFile.dll │ │ System.IO.dll │ │ System.IO.FileSystem.AccessControl.dll │ │ System.IO.FileSystem.dll │ │ System.IO.FileSystem.DriveInfo.dll │ │ System.IO.FileSystem.Primitives.dll │ │ System.IO.FileSystem.Watcher.dll │ │ System.IO.IsolatedStorage.dll │ │ System.IO.MemoryMappedFiles.dll │ │ System.IO.Pipes.AccessControl.dll │ │ System.IO.Pipes.dll │ │ System.IO.UnmanagedMemoryStream.dll │ │ System.Linq.dll │ │ System.Linq.Expressions.dll │ │ System.Linq.Parallel.dll │ │ System.Linq.Queryable.dll │ │ System.Memory.dll │ │ System.Net.dll │ │ System.Net.Http.dll │ │ System.Net.Http.Json.dll │ │ System.Net.HttpListener.dll │ │ System.Net.Mail.dll │ │ System.Net.NameResolution.dll │ │ System.Net.NetworkInformation.dll │ │ System.Net.Ping.dll │ │ System.Net.Primitives.dll │ │ System.Net.Quic.dll │ │ System.Net.Requests.dll │ │ System.Net.Security.dll │ │ System.Net.ServicePoint.dll │ │ System.Net.Sockets.dll │ │ System.Net.WebClient.dll │ │ System.Net.WebHeaderCollection.dll │ │ System.Net.WebProxy.dll │ │ System.Net.WebSockets.Client.dll │ │ System.Net.WebSockets.dll │ │ System.Numerics.dll │ │ System.Numerics.Vectors.dll │ │ System.ObjectModel.dll │ │ System.Private.CoreLib.dll │ │ System.Private.DataContractSerialization.dll │ │ System.Private.Uri.dll │ │ System.Private.Xml.dll │ │ System.Private.Xml.Linq.dll │ │ System.Reflection.DispatchProxy.dll │ │ System.Reflection.dll │ │ System.Reflection.Emit.dll │ │ System.Reflection.Emit.ILGeneration.dll │ │ System.Reflection.Emit.Lightweight.dll │ │ System.Reflection.Extensions.dll │ │ System.Reflection.Metadata.dll │ │ System.Reflection.Primitives.dll │ │ System.Reflection.TypeExtensions.dll │ │ System.Resources.Reader.dll │ │ System.Resources.ResourceManager.dll │ │ System.Resources.Writer.dll │ │ System.Runtime.CompilerServices.Unsafe.dll │ │ System.Runtime.CompilerServices.VisualC.dll │ │ System.Runtime.dll │ │ System.Runtime.Extensions.dll │ │ System.Runtime.Handles.dll │ │ System.Runtime.InteropServices.dll │ │ System.Runtime.InteropServices.RuntimeInformation.dll │ │ System.Runtime.Intrinsics.dll │ │ System.Runtime.Loader.dll │ │ System.Runtime.Numerics.dll │ │ System.Runtime.Serialization.dll │ │ System.Runtime.Serialization.Formatters.dll │ │ System.Runtime.Serialization.Json.dll │ │ System.Runtime.Serialization.Primitives.dll │ │ System.Runtime.Serialization.Xml.dll │ │ System.Security.AccessControl.dll │ │ System.Security.Claims.dll │ │ System.Security.Cryptography.Algorithms.dll │ │ System.Security.Cryptography.Cng.dll │ │ System.Security.Cryptography.Csp.dll │ │ System.Security.Cryptography.Encoding.dll │ │ System.Security.Cryptography.OpenSsl.dll │ │ System.Security.Cryptography.Primitives.dll │ │ System.Security.Cryptography.X509Certificates.dll │ │ System.Security.dll │ │ System.Security.Principal.dll │ │ System.Security.Principal.Windows.dll │ │ System.Security.SecureString.dll │ │ System.ServiceModel.Web.dll │ │ System.ServiceProcess.dll │ │ System.Text.Encoding.CodePages.dll │ │ System.Text.Encoding.dll │ │ System.Text.Encoding.Extensions.dll │ │ System.Text.Encodings.Web.dll │ │ System.Text.Json.dll │ │ System.Text.RegularExpressions.dll │ │ System.Threading.Channels.dll │ │ System.Threading.dll │ │ System.Threading.Overlapped.dll │ │ System.Threading.Tasks.Dataflow.dll │ │ System.Threading.Tasks.dll │ │ System.Threading.Tasks.Extensions.dll │ │ System.Threading.Tasks.Parallel.dll │ │ System.Threading.Thread.dll │ │ System.Threading.ThreadPool.dll │ │ System.Threading.Timer.dll │ │ System.Transactions.dll │ │ System.Transactions.Local.dll │ │ System.ValueTuple.dll │ │ System.Web.dll │ │ System.Web.HttpUtility.dll │ │ System.Windows.dll │ │ System.Xml.dll │ │ System.Xml.Linq.dll │ │ System.Xml.ReaderWriter.dll │ │ System.Xml.Serialization.dll │ │ System.Xml.XDocument.dll │ │ System.Xml.XmlDocument.dll │ │ System.Xml.XmlSerializer.dll │ │ System.Xml.XPath.dll │ │ System.Xml.XPath.XDocument.dll │ │ ucrtbase.dll │ │ UnitTestJikken.dll │ │ UnitTestJikken.pdb │ │ WindowsBase.dll │ │ WinRT.Runtime.dll │ │ │ └─ref │ ConsoleApp1.dll
RuntimeIdentifierは指定せず、SelfContainedだけ指定
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> <SelfContained>true</SelfContained> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
SelfContainedはRuntimeIdentifierを指定していないと設定できない。(エラーになる)
どの環境(Windows?Linux?)がわからないと、なんのランタイムを含めて良いかがわからない、ということか。
ProduceReferenceAssembly をfalseにする
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> <ProduceReferenceAssembly>false</ProduceReferenceAssembly> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
ProduceReferenceAssembly
falseにすると、falseにしてないとき(標準の時)に出力先にできていた、ref
フォルダができなくなる。
└─net6.0-windows10.0.17763.0 │ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ └─runtimes ├─unix │ └─lib │ └─netcoreapp3.0 │ System.Drawing.Common.dll │ └─win └─lib └─netcoreapp3.0 Microsoft.Win32.SystemEvents.dll System.Drawing.Common.dll
refフォルダに入っているのは、参照アセンブリ
というものらしい。
そういうものがあると知らなかったが、簡単に言うと「publicなクラスやメソッドのインターフェースだけあって中身の実装のない、そのアセンブリを使う側が実装に使えるもの」らしい。
詳しくはMS公式を参照。
MSBuildに使うProduceReferenceAssemblyオプション
C# コンパイラ オプション - 出力オプション | Microsoft Docs
参照アセンブリとは何か?
docs.microsoft.com
dotnet publish をやってみる
コマンドプロンプトでソリューションファイルと同じ階層にcdして、下記コマンドをうつ。
dotnet publish --no-self-contained
そのとき、csprojファイルは、下記のような内容にしていた。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.17763.0</TargetFramework> <Platforms>x64</Platforms> <SelfContained>true</SelfContained> <RuntimeIdentifier>win-x64</RuntimeIdentifier> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\UnitTestJikken\UnitTestJikken.csproj" /> </ItemGroup> </Project>
そうすると、下記のようなものが出力される。
└─net6.0-windows10.0.17763.0 └─win-x64 │ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ ├─publish │ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ └─ref ConsoleApp1.dll
csprojでは、<SelfContained>true</SelfContained>
にして、dotnetコマンドでは--no-self-contained
にした。 その結果、self-contained(自己完結)がfalseの成果物が作成された。
→csprojの設定は、dotnet publishしたときのオプション設定で上書きされるっぽい。
(すべての設定がそうなるかどうかは不明)
dotnet publish で --outputで出力先フォルダを指定する
dotnet publish でoutputフォルダを指定しなかった場合、csprojの標準の出力先フォルダに「publish」フォルダができて、そこにpublishの出力が行われるっぽい。
--output を使って、dotnet publish の出力先を指定できる模様。
下記のコマンドを実行した。(csprojの設定は、上のと同じ)
dotnet publish --no-self-contained --output C:\Users\masa\Desktop\jikken
結果、デスクトップのjikken
フォルダに、下記のような出力がされる。
│ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.deps.json │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ └─runtimes ├─unix │ └─lib │ └─netcoreapp3.0 │ System.Drawing.Common.dll │ └─win └─lib └─netcoreapp3.0 Microsoft.Win32.SystemEvents.dll System.Drawing.Common.dll
csprojの出力先にも、下記のようなものが出来上がっている。
└─net6.0-windows10.0.17763.0 └─win-x64 │ ConsoleApp1.deps.json │ ConsoleApp1.dll │ ConsoleApp1.exe │ ConsoleApp1.pdb │ ConsoleApp1.runtimeconfig.json │ Microsoft.Toolkit.Uwp.Notifications.dll │ Microsoft.Win32.SystemEvents.dll │ Microsoft.Windows.SDK.NET.dll │ System.Drawing.Common.dll │ UnitTestJikken.dll │ UnitTestJikken.pdb │ WinRT.Runtime.dll │ └─ref ConsoleApp1.dll
2つのフォルダの中の、同じファイル名のものは同じバイナリになってる。
ただ、csprojの出力先のほうにはruntimes
フォルダがないが、dotnet publish
の出力先フォルダのほうにはある。
→おそらく、csprojの方ではRuntimeIdentifier
フォルダにwin-x64
を指定していたのでruntimes
フォルダはできなかったが、dotnet publish
のほうではRuntimeIDを指定しなかったので、runtimes
フォルダができたのだと思われる。
⇒csprojとdotnet publish
で同じ設定をしたらdotnetの方が優先だが、csprojの方にだけ設定してると、dotnet publish
のほうでは、設定しなかった場合のデフォルト値が使われるっぽい。
VSでビルドしたときとdotnet puslishしたときで出来るバイナリは異なるのか?
異ならない。同じバイナリができてる。
左:VisualStdio2022でDebugビルドしたもの。
(<SelfContained>false</SelfContained>
だけ指定)
右:dotnet publish --no-self-contained
を実行したもの。
結局、最終成果物として使うのはどの方法でビルドしたものを使うべきなのか?
試した結果、個々のファイルは同じものができてるので、究極どちらを使ってもよさそう。(同じ設定をしたときには、違いはrefフォルダができるかできないかくらいっぽい。)
今一度MS公式を見ると、
dotnet-publish
コマンドのMS公式説明に、下記のようなものがある。
アプリの正式な展開方法はこれだけ、という記述があるので、VisualStudioでリリースビルドしたフォルダの中身を使うよりも、dotnet publish
で出力したものを使うべきなのだと思われる。
その際、(csprojファイルにどんな設定をしていても)、dotnet publish
コマンドに、作ったコードの対象となる環境に適したすべてのオプションを設定してやれば、そこで動くものが出来上がるよ、ということか。
思ったこと
dotnet publishを使えばよい、で納得した気がするが、
たぶんコードを書いている最中はVisualStudioでビルドするのでcsprojの設定が生きてるが、最後、最終版を作ってテストするときにはdotnet publishとかになりそうな気がする。
そうなると、最後の最後でcsprojとdotnet publishに渡すオプションが違ってしまい、今までOKだったのに最終テストではなんか違う動きする、ということがあり得そう。
そこは要注意だなと感じた。
備考
dotnet publishでは、VSからビルドしたときにできていたref
フォルダが作成されない。
たぶん、refはその中にあるdllを、そのdllを使う側がライブラリとして使用するためのものなので、「publish = 動かす環境に配置」するときには、そんな参照アセンブリは不要、ということで出来ないのだと思われる。
参考
.NET SDK プロジェクトの MSBuild リファレンス docs.microsoft.com
MSBuild コマンド ライン リファレンス docs.microsoft.com
単一ファイルの発行関連パラメータの説明 単一ファイル アプリケーション - .NET | Microsoft Docs
dotnet-publishコマンド docs.microsoft.com
"win-x64"などの表記を「RID(ランタイムID)」という
docs.microsoft.com
refフォルダがなにか? docs.microsoft.com