Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

F#で遊んでみる(2)

だいぶ長い間、インストールだけして放置してた。まあ、よくあること。

さて、まずはインタラクティブシェルの使い方。インタラクティブシェルはfsiという名前で、dotnetコマンドを使って起動する

> dotnet fsi

Microsoft (R) F# インタラクティブ バージョン F# 5.0 のための 11.0.0.0
Copyright (C) Microsoft Corporation. All rights reserved.

ヘルプを表示するには次を入力してください: #help;;

^dで抜けられる。

lonideプラグインを入れたVSCだと、関数全体をエディタで選択した状態でOption+Enterすると その関数を読み込んだ状態でfsiが起動する。便利。

では、これを他のマシンでも動く実行ファイルにするにはどうしたらいいのだろうか。 ここを参考にしてみよう。

www.buildinsider.net

どうやら、dotnet publishコマンドを実行することになるようだ。 しかも普通にクロスコンパイル出来るらしい(私はmacOSで遊んでいる)

(1)で作ったfs_studyというプロジェクトのプロジェクトファイルfs_study.fsprojはこんな感じになっている

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>


  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>

</Project>

これにRID(RuntimeIdentifiers)を足せばいいのかな? サジェスチョンされるがままに、win10を選んでみる。

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
  </PropertyGroup>

これで、ビルドしてみよう

> dotnet publish -c Release -r win10-x64
.NET 向け Microsoft (R) Build Engine バージョン 16.8.3+39993bd9d
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.App.Host.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.AspNetCore.App.Runtime.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.App.Runtime.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
  /Users/tambara/study/fs_study/fs_study.fsproj を復元しました (33 sec)。
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.App.Host.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.AspNetCore.App.Runtime.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.App.Runtime.win-x64 5.0.2': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
  fs_study -> /Users/tambara/study/fs_study/bin/Release/net5.0/win10-x64/fs_study.dll
  fs_study -> /Users/tambara/study/fs_study/bin/Release/net5.0/win10-x64/publish/

なんか途中でちょっと怒られているけど、一応ファイルは出来たみたい。

ここで出来たfs_study.exeをWIndows11マシンに持っていて実行してみると、fs_study.dllがないと怒られる。 fs_study.dllをexeと同じトコロにおいても、別のdllで怒られる。

PS C:\Users\tmbrm\Desktop> .\fs_study.exe apple banana
A fatal error occurred. The required library hostfxr.dll could not be found.
If this is a self-contained application, that library should exist in [C:\Users\tmbrm\Desktop\].
If this is a framework-dependent application, install the runtime in the global location [C:\Program Files\dotnet] or use the DOTNET_ROOT environment variable to specify the runtime location or register the runtime location in [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x64\InstallLocation].

The .NET runtime can be found at:
  - https://aka.ms/dotnet-core-applaunch?missing_runtime=true&arch=x64&rid=win10-x64&apphost_version=5.0.2

あれ?そもそも.net5は普通にWindowsに入っているモノかな?このWindowsマシンはほぼ買ってWin10を11に上げただけのもので、特別に何かは入れてない。少なくともC:\Program Files\dotnetはない。Windows10で標準の.NetFrameworkのバージョンは4.6らしい。何が入ってるのかはどうやって確認すればいいのかと思って以下のページをみたが、さっぱりわからなかった。

docs.microsoft.com

とりあえず、TargetFrameworkをnet46にしてビルドしてみる

> dotnet publish -c Release -r win10-x64
.NET 向け Microsoft (R) Build Engine バージョン 16.8.3+39993bd9d
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'System.ValueTuple 4.4.0': リポジトリのプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'System.ValueTuple 4.4.0': リポジトリのプライマリ署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies.net46 1.0.0': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies.net46 1.0.0': 作成者のプライマリ署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies.net46 1.0.0': リポジトリ副署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies.net46 1.0.0': リポジトリ副署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies 1.0.0': 作成者のプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies 1.0.0': 作成者のプライマリ署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies 1.0.0': リポジトリ副署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETFramework.ReferenceAssemblies 1.0.0': リポジトリ副署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : error NU1202: パッケージ FSharp.Core 5.0.0 は net46 (.NETFramework,Version=v4.6) と互換性がありません。 パッケージ FSharp.Core 5.0.0 がサポートするもの: netstandard2.0 (.NETStandard,Version=v2.0)
/Users/tambara/study/fs_study/fs_study.fsproj : error NU1202: パッケージ FSharp.Core 5.0.0 は net46 (.NETFramework,Version=v4.6) / win10-x64 と互換性がありません。 パッケージ FSharp.Core 5.0.0 がサポートするもの: netstandard2.0 (.NETStandard,Version=v2.0)
  /Users/tambara/study/fs_study/fs_study.fsproj を復元できませんでした (52.33 sec)。

net46はサポートされないと言われる。代わりにnetstandard2.0を使えと。書き換えてみた。

> dotnet publish -c Release -r win10-x64
.NET 向け Microsoft (R) Build Engine バージョン 16.8.3+39993bd9d
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.Platforms 1.1.0': リポジトリのプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : warning NU3028: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'NETStandard.Library 2.0.3': リポジトリのプライマリ署名 のタイムスタンプによってチェーン構築の問題が見つかりました: ExplicitDistrust: The trust setting for this policy was set to Deny.
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'Microsoft.NETCore.Platforms 1.1.0': リポジトリのプライマリ署名 の有効期限が切れています。
/Users/tambara/study/fs_study/fs_study.fsproj : error NU3037: ソース 'https://api.nuget.org/v3/index.json' からのパッケージ 'NETStandard.Library 2.0.3': リポジトリのプライマリ署名 の有効期限が切れています。
  /Users/tambara/study/fs_study/fs_study.fsproj を復元できませんでした (4.62 sec)。

エラーですよ。でも、NuGetの認証でミスっているような感じ。もしかして、SDKをアップデートすればいいのかな?

.net5もアップデートされているっぽいけど、もう.net6が出ているのでサクッとインストールしてみる。普通にまたインストーラーを起動したら、特に何を聞かれるでもなく完了。これでアップデートされたのかなあ?

> dotnet help

.NET 6.0 へようこそ!
---------------------
SDK バージョン: 6.0.200

(以下略)

されてるね。

というわけで、もう一回やってみよう。

> dotnet publish -c Release -r win10-x64
.NET 向け Microsoft (R) Build Engine バージョン 17.1.0+ae57d105c
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  /Users/tambara/study/fs_study/fs_study.fsproj を復元しました (3.23 sec)。
  fs_study -> /Users/tambara/study/fs_study/bin/Release/netstandard2.0/win10-x64/fs_study.dll
  fs_study -> /Users/tambara/study/fs_study/bin/Release/netstandard2.0/win10-x64/publish/

warningも消えた

しかし、今度はexeが出来ない。これはどうも目的のものではなさそうだ。

netcoreapp3.1を指定すると、exeは出来る。でも、net5.0を指定したのと同じ状況になる。 バージョンを下げていってもあまり状況は変わらない。

で、結局、net48を指定すると、fs_study.dllも生成されず、fs_study.exeが出来た。 これを実行すると、

PS C:\Users\tmbrm\Desktop> .\fs_study.exe apple banana

ハンドルされていない例外: System.IO.FileNotFoundException: ファイルまたはアセンブリ 'FSharp.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つ かりません。
   場所 Program.main(String[] argv)

そこで、publish 以下に置かれているFSharp.Core.dllも一緒においてやると

PS C:\Users\tmbrm\Desktop> .\fs_study.exe apple banana
apple in Pig Latin is: appleyay
banana in Pig Latin is: ananabay

動いた!

バージョンが高いからダメなのかと思ってCドライブ全体でFSharp.Core.dllを探してみたけど、入ってないみたい。ええー・・・

しかし、Macで動かすのはコレではダメだ。Windowsにはあらかじめ.netFrameworkが入っていることが期待出来るけど、Macはそうではないから。

で、いろいろググっていたら、シングルファイルにするためのパラメータがあることがわかった。

qiita.com

これでいいみたい。TargetFrameworkをnetcoreapp3.1にして、以下を試してみた。

> dotnet publish -c Release -r osx-x64 -p:PublishSingleFile=true --self-contained
.NET 向け Microsoft (R) Build Engine バージョン 17.1.0+ae57d105c
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です。
  fs_study -> /Users/tambara/study/fs_study/bin/Release/netcoreapp3.1/osx-x64/fs_study.dll
  fs_study -> /Users/tambara/study/fs_study/bin/Release/netcoreapp3.1/osx-x64/publish/

これで、80MB弱のシングルバイナリのfs_studyが出来ている。でっかいけど、まあ、イマドキこのぐらいの大きさは許してもらおう。やったね!

同じようにwin10-x64に対してもやってみると、同じように80MB弱のfs_study.exeが出来る。 net48をターゲットにした場合は、9KBのexeファイルとFSharp.Core.dllが3MBで済んだので、Windowsをターゲットにするのであれば、こっちがいいのかもしれない。