俺のラズパイ3で.NET CoreなF#が動かないわけがない

と、思っていましたが、動きません orz.

dotnet/coreclr:
https://github.com/dotnet/coreclr/
dotnet/cli:
https://github.com/dotnet/cli

.NET Coreをビルドしようと思うと、

な感じで拒否られるし、じゃあ、dotnet コマンドだけでもビルドできないかと思うと、

20160831_06

な感じで、前回ビルド済みの dotnet コマンドを要求されるし、どうにもなりません。

Problem install .Net Core on Raspberry Pi Model B ・ Issue #140 ・ dotnet/core
https://github.com/dotnet/core/issues/140
How to use dotnet cli in debian linux on arm. ・ Issue #3197 ・ dotnet/cli
https://github.com/dotnet/cli/issues/3197

を見る限り、Raspberry Pi で使われてる ARMv7 ではビルドできませんという具合です。.NET CoreのターゲットとしてARMは入っているので、いずれ対応するのかという雰囲気だけはあるんですが、進展はしているのかは不明。

でも、元 dnvm は動いていたよね?

しかし、Raspberry Pi2 に Windows IoT Core がインストールできるわけだし、最初から ARMv7 が開発ターゲットから外されているというのも変名は話なので、いつくか遡ってみると、

Raspberry Pi 2 にインストールした Windows 10 IoT Core 上で DNX と ASP.NET 5 アプリケーションを動かしてみた – しばやん雑記
http://blog.shibayan.jp/entry/20150629/1435546231
How to run .NET Core Application on Pi2 – Win10 IoT Core? – Damir Dobric Posts – developers.de
http://developers.de/blogs/damir_dobric/archive/2015/09/22/how-to-run-net-core-application-on-pi2-win10-iot-core.aspx

を読むと、dotnet コマンドの前身の dnvm コマンドでは Raspberry Pi で(Windows IoT Core限定カモ)動いていた模様です。
「模様」ですというのは、現在、ARMのランタイムを取ろうとすると、エラーが発生します。

dnvm install latest -r coreclr -arch x64 は通るけど、
dnvm install latest -r coreclr -arch ARM は通らなくなっているので、

サーバー自体から消えてしまった感じ。うーん、古いバイナリでよいので残してほしかったのですが、ここが OSS の辛いところ。

ややこしい、3つの Core な関係

でもって、やりたいことは、F# な Web APIアプリをラズパイ上で動かしたいだけなので、別に mono でもいいんだよな、と思い直して .NET Core なところをあれこれと弄っていこうとすると、

– .NET Core なランタイム
– ASP.NET Core
– ASP.NET Core MVC

な、ややこしい関係にぶち当たります。

素直に、.NET Core 環境だけで作るとか、素直に .NET Framework 4.6 な環境で作るとかすればよいのですが、じゃあ、dotnet コマンドは何の環境で動いているのかとか、ASP.NET Core MVC は内部で何がうごいているのかとかとか考えるとややこしいのです。

msbuild に代わるビルド環境としての dotnet コマンドは、dotnet restore してアセンブリを NuGet で取ってきて dotnet run でプロジェクトを実行できます。プロジェクトがある場所に、project.json があって、その中に設定が書いてあるわけですが、この dotnet コマンドが、.NET Core 上なのか .NET Framework 上なのか mono 上なのかが謎です。ただ、dotnet/cli を取って来て Raspi 上でビルドができない(Ubuntu上ではできた)ので、動作はともかくとして、ビルドするのに「動作する dotnet」が必要です。ブートストラップ的になっているの、卵と鶏の関係になっています。

mono 上で動く dotnet コマンドがあればいいのに、と思うんだけど、それがないところみると、たぶん .NET Core 上で動いているんですよね、おそらく。

ASP.NET Core はオープンソースな https://github.com/aspnet/ で開発が進められていますが、内部的に .NET Core 必須なのか?というとそうではなくて、

を見ると、

– ASP.NET Web Application(.NET Frameowork)
– ASP.NET Core Web Application(.NET Core)
– ASP.NET Core Web Application(.NET Framework)

の3種類のASP.NET MVCプロジェクトが作れます。

最初のASP.NETアプリは、従来のASP.NET MVC5とかを作るプロジェクトで .NET Frameworkを使うやつです。
次の、(.NET Core)のほうは、.NET Coreを使っているほうで、dotnet runとかで実行ができるやつです。IISがいらないのでLinuxに移すことができますよね。
じゃあ、最後の「ASP.NET Core Web Application(.NET Framework)」ってのは何でしょう?
.NET Framework上で動く、ASP.NET Core って何?ASP.NET Coreの「Core」って、.NET Coreの「Core」じゃなかったの?と思う訳ですが、どうやら、この2つの Core は違う意味とだということが分かります。どうやら、.NET Framworkを使って、IISのいらない exe ファイルを作って実行することができるですよね。

bin/Dbug/net452/win7-x64 フォルダーにある WebApplication1.exe を実行すると、普通に ASP.NET Core MVC アプリケーションが動きます。

このバイナリをそのまま Raspberry pi に持って行って、mono で動かすと libuv のアセンブリがなくて動きません。Raspberry pi 上に libuv はインストールしたのですが、Linux の動的ライブラリ *.so を探しているかどうかは不明です。

どうやら、ASP.NET MVC のほうは、IIS 上で動いて、
ASP.NET Core MVC のほうは

– Kestrel
– libuv

が肝だということが薄々わかってきました。Kestrel は Webサーバーで、https://github.com/aspnet/KestrelHttpServer からダウンロードが可能です。ただし、これをビルドするときに dotnet コマンドが必要なので、ラズパイ上では頓挫しています。「ASP.NET Core Web Application(.NET Framework)」のプロジェクトが、Kestrel を使っているので、.NET Core 自体は必要ないはずなんですよね(ASP.NET Coreしか必要ない)。
libuv のほうは、Node.js でも使われているクロスプラットフォームな TCP/IP ライブラリです。こっちのほうは、https://github.com/libuv/libuv からダウンロードしてラズパイ上でもビルドができます。

ということは、「dotnet コマンドを使わないでビルドができる Kestrel を .NET Framework 版でビルドすれば、mono 上で動く」ので、ラズパイ上で動くようになるのでは?と思いついたのですがどうでせふ?

オレオレASP.NET Core MVCを作成する

ひとまず、HttpListenerを使ったら mono でも動くので、Raspberry Pi 上に F# な Web APIサーバーが立てられるのではと思って、ちまちまと考えていたり。

type WebHostBuilder() as self =
    let mutable _sv = new System.Net.HttpListener()

    member x.UseStartup() = 
        self
    member x.UseUrls(url) = 
        _sv.Prefixes.Add( url )
        self
    member x.Build() = 
        ()
    member x.Run() =
        if _sv.Prefixes.Count = 0 then
            _sv.Prefixes.Add("http://localhost:5000/")
        _sv.Start()
        while true do
            let cont = _sv.GetContext()
            Console.WriteLine("url: {0}", cont.Request.Url)
            let sw = new System.IO.StreamWriter(cont.Response.OutputStream)
            sw.WriteLine("OK")
            sw.Close()
            cont.Response.Close()
        _sv.Stop()

[<EntryPoint>]
let main argv = 
    printfn "start oreoreHttpServer"

    let host = new WebHostBuilder()
    host.UseStartup()
        .UseUrls("http://+:5000/")
        .Build()
    host.Run()
    0

なんとなく、インターフェースだけ Kestrel に似せています。

カテゴリー: ASP.NET, F#, RaspberryPi パーマリンク