もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
以前の記事で、「dotnet publish
コマンドだと、どうやってもPubishSingleFileがうまくいかない(exeが1個だけ出力されてほしいのに、依存dll類が全部出てきてしまう)」ということを書いた。
が、そんなわけない、コマンドで出来るはずと思うので、もう一回tryしたい。
前提
下記のアプリで実験した。
結論
やっぱりdotnet publish
でもうまくいった。
前回うまくいかなかったのは、
- 実は単一ファイル出力がうまくいっていたのに、
- binフォルダ以下の出力先フォルダに、一旦出力された沢山のファイルをみて、単一ファイル化できてないと思い込んでいたが、
- 実はその中に「publish」フォルダが出来上がっていて、その中には単一ファイルがちゃんと出力されていた
という顛末だった。(実はうまくいっていた。下図のように埋もれて見えていただけだった)
やったこと
なので、うまくいったコマンドをまとめておく。
ついでに、PublishSingleFile
以外にも、なにが出力ファイルとして出てくるかに大きくかかわるパラメータ(-p:IncludeNativeLibrariesForSelfExtract
)があったのでメモっておく。
①基本のdotnet publishコマンド
以下の前提である場合は、
- windows11で動作する
- 64bit
- Releaseビルド
- self-containedなアプリにして、.net8ランタイムがインストールされてなくても動くようにする
- バッチと同じフォルダに成果物フォルダを作成する
(前みたいに多数のファイルに埋もれないように出力先を指定する)
下記のコマンドが基本になると思う。
dotnet publish -c Release -r win-x64 --output .\publish_1 --self-contained -p:RuntimeIdentifier=win-x64 -p:Platform=x64
これに、単一ファイル出力するためのパラメータなどを付け足していく。
このコマンドで出力した一式の一部がこちら。(ランタイム一式を含むので、ファイルがたくさんある)
②-p:PublishSingleFile=true(単一ファイル出力)を追加
-p:PublishSingleFile=true
を付けた。
dotnet publish -c Release -r win-x64 --output .\publish_2 --self-contained -p:RuntimeIdentifier=win-x64 -p:Platform=x64 -p:PublishSingleFile=true
このコマンドを実行したときの出力ファイルがこちら。
(7ファイルのみになった)
③--self-containedを削除
②から、--self-containedのパラメータを抜いた。
(PublishSingleFile を true にすると、--self-contained は自動でtrueになるので、削除した。)
dotnet publish -c Release -r win-x64 --output .\publish_3 -p:RuntimeIdentifier=win-x64 -p:Platform=x64 -p:PublishSingleFile=true
出力されたものは、容量を比較しても②と同じに見える。
バイナリレベルでも一緒だった。
④-p:IncludeNativeLibrariesForSelfExtract=true を追加
前提の- self-containedなアプリにして、.net8ランタイムがインストールされてなくても動くようにする
から外れてしまうのだが、--self-contained=trueを外して、-p:IncludeNativeLibrariesForSelfExtract=true
をした。
dotnet publish -c Release -r win-x64 --output .\publish_4 -p:RuntimeIdentifier=win-x64 -p:Platform=x64 -p:IncludeNativeLibrariesForSelfExtract=true
結果、Nativeっぽいファイルは出力されなくなった。
色々試したところ、この④出力成果物と、self-containedしない(--self-contained=false)下記のdotnet publishの出力成果物は、バイナリレベルで一緒だった。
dotnet publish -c Release -r win-x64 --output .\publish_10 -p:RuntimeIdentifier=win-x64 -p:Platform=x64
なので、-p:IncludeNativeLibrariesForSelfExtract=true
は、self-contained して初めて効果が出るパラメータと思われる。
(self-containedしたうえで、ネイティブのdllもexeに取り込むか?取り込まないか?の設定だと思われる。)
(それで、取り込んだら⑤のように、ネイティブdllは一時ファイルとして吐かれる。↓⑤参照)
⑤-p:PublishSingleFile=true かつ -p:IncludeNativeLibrariesForSelfExtract=true
これで出力されたexeを実行時、%Temp%\.net\アプリ名\ランダムな文字列\
フォルダの中に、下記のようなフォルダとファイルができた。
exe動作時には、メインのexeに抱え込んだネイティブなdllがここに吐き出される様子。
※今回は試せてないが、自作のネイティブdllを使用している場合も、ここに吐き出されるのか? (未検証) もしそうであれば、メインのdllに組み込む前にそのネイティブdllも署名等を済ませておかないといけないっぽいと思った。
%Temp%.net\ にネイティブdllが吐かれるのは⑤だけだった
今回試したパターンだと、ネイティブdllが吐かれるのは⑤だけだった。
publishしたときに1ファイルになってくれるのは分かりやすくて良いが、⑤のところに書いた懸念(自作ネイティブを使うときにもtempに吐かれたら...?)とかが心配なので、見えないところであれこれされることの少なさを考えると、④が一番良いのかな、と思った。
参考
dotnet publish コマンド
https://learn.microsoft.com/ja-jp/dotnet/core/tools/dotnet-publish
IncludeNativeLibrariesForSelfExtract の説明
.NET6の「単一ファイル」
https://qiita.com/up-hash/items/39fa0671bf390147eca9
.NET CoreのSingle Fileを試す
-p:IncludeNativeLibrariesForSelfExtract=trueのときのネイティブdllの吐き出し先をここで知った