hack のためのネタ帳, etc,,,

経緯

先週の日曜日(2017-03-18)くらいにちょっと思い立って触ってみてたものの、なかなか上手くいく方法が見つからなかったんだが、ようやく上手くいく方法を見つけたのでメモっておく。

発端は、以下に示す Windows Forms の簡単なサンプルを、MONO でコンパイルするに当たって、コマンドラインに手書きで mcs 呼ぶのは流石に嫌だなと思い、適当な build システムを使いたかったのだが、良い方法が見つからなかった。

GNU Make

最初は簡単に済ませたくて Makefile 書こうとしたんだけれど、C# で $(CC) や $(CXX) に当たるマクロが分からず、調べるのも面倒なので、いきなりさじを投げて CMake を試しにかかった。
しかし、この記事書くに当たって、後から調べてみると、
少なくとも 2018-03-25 現在、GNU make の manual には C# に関する記述は一切ない状況で、
ググってもほとんど情報がみつからない。
MONO の WinForms の ドキュメントの Sample Code で紹介されている ですら、Makefile で mcs 決め打ちしているという状況だった。

CMake

と言うことで、まず、大抵の物は CMake で行けるだろうと見込んで試してみたのだが、Ubuntu 16.04.3 LTS の CMake 3.5.1 では未対応。
一応、CMake 3.8 の New Features で C# が新たに加わって
enable_language(CSharp)
出来るようになっているんだけど、「currently supported by the Visual Studio Generators for VS 2010 and above.」って書いてあるように MONO には対応しておらず、
少なくとも 2018-03-25 時点の最新版である CMake 3.10 でも「C# is currently only supported for Microsoft Visual Studio 2010 and later.」って言われてエラーになる。
と言うことで、CMake もデフォルトのままだと当面使い物にならないと言う結論に至った。

xbuild (MSBuild)

次に、「mono c# buildtool」でググると、 で MONO 版の MSBuild に当たる xbuild があるぞというコメント見つけて使ってみたんだけど、書式が XML なので手書きするにはとても辛い。
手書きの件は、とりあえず、我慢するとして、これで一応、Csc Task 書いとけば、csc ではなく MONO の mcs が呼ばれてコンパイルは一応通る。
しかし、Windows Forms 等を使ったコードの場合、mcs は -pkg:dotnet ってオプションを付けないとコンパイルが通らないのだが、これはどうも MONO 独自で csc には本来ないオプションらしく、Csc Task には、これを指定するためのパラメーターが見当たらない。このため xbuild から mcs を使えるものの Windows Forms を使ったコードをコンパイルすることが出来ないという非常に悩ましい状況で頭を抱えてしまった。

いろいろ、ググって彷徨ってみたところ、 で見つけた
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
は特に効果がなく、 で見つけた
<Reference Include="Windows.Specific.dll" Condition=" '$(OS)' != 'Unix' "/>
<Reference Include="NonWindows.Specific.dll" Condition=" '$(OS)' == 'Unix' "/>
については当初、きちんと理解出来てなかったのだが、
これは、Unix 環境か否かで、Include する dll を選択する例示であり、
"Windows.Specific.dll" と "NonWindows.Specific.dll" は具体的に実在する dll ではなく、
環境により適宜選択すべき dll に変更しろって意味だということにようやく気がついたのは、
以下で参考に挙げた2つの記事を読んだ後だった。

決め手としては、man mcs して見つけた以下の記述。
...
       The  Mono  C#  compiler  by  default  only references three assemblies:
       mscorlib.dll, System.dll and System.Xml.dll.   If you want to reference
       extra  libraries you must manually specify them using the -pkg: command
       line option or the -r: command line option.  Alternatively if you  want
       to get all of the System libraries, you can use the -pkg:dotnet command
       line option.
...
              -pkg:dotnet
                     This will instruct the compiler to reference the System.*
                     libraries available on a typical dotnet framework instal‐
                     lation, notice that this does not include all of the Mono
                     libraries,  only the System.* ones.  This is a convenient
                     shortcut for those porting code.
...
つまり -pkg:dotnet は System.* を全部 -r で指定するためのショートカットなので、mcs の -r オプションで必要な dll を適宜与えてやれば良いということである。
従って Csc Task の References パラメーターに必要な dll (つまりここでは System.Windows.Forms.dll) を与えれば良いことが分かった。
実際、試して見たところ、これで上手く行った。
また、与える際 .dll は省略可能で、複数の dll を与える場合は「,」で列挙すれば良かった。
つまり、例えば、System.Windows.Forms と System.Drawing を与えたければ以下のようにすれば良い。
<Csc
  References="System.Windows.Forms,System.Drawing"
  ...
/>
また、Csc Task に与える References パラメータは ItemGroup 要素 内で Reference 要素として複数個設定した物を「@(Reference)」で参照出来らしく、以下のように書くことも出来た。
...
<ItemGroup>
<Reference Include="System.Windows.Forms"/>
<Reference Include="System.Drawing"/>
</ItemGroup>
...
<Target>
<Csc
  References="@(Reference)"
  ...
 />
</Target>
...

と言うことで、現状だと .csproj に <Reference include=""/> を書いて xbuild で build するのが、portable な build スクリプトと言う意味では一番無難な線のようである。

参考:

Autotools

Autotools に関しては、以下に sample "skeleton" application の例示を見つけた。
  • Mono / Docs / Getting Started /Application Deployment # Auto-tools
  • GitHub / mono / old-code / acceptance-tests-ifolder / monoskel
ただし、上で挙げられている GitHub のコードは old-code と付いているようにどうも古いコードっぽい。
一応、リポジトリを漁ると というのも存在するのだが、
old-code が Latest commit 7050a81 on 28 Apr 2010 であるのに対して、
こちらは、Latest commit 526bc51 on 13 May 2008 と逆に古くなるし、
どちらも8年以上前のコードなので、現行と言って良いのかどうか迷うところ。
内容的にはかなり異なっていて、後者の方が細かい調整までやってる雰囲気があるが、どちらもモジュール化まではされておらず、configure.in に直書きされているので、ちょっと使い勝手が良くない。

これはこれで UNIX の標準の踏襲と言う意味では悪くないのだが、良くも悪くも Autotools なので、.NET Framework のコンパイル環境ではちょっと使い辛い。

とりあえず、/usr/share/autoconf/autoconf/*.m4 を参考に、AC_PROG_CS マクロを定義する .m4 ファイルを試作してみたのだが、C# のコンパイラって、object file の出力オプションがなく、従来の一般的な分割コンパイルについて考慮されていない模様。
このため、分割しようとすると基本的に module (.netmodule) か library (.dll) にして -addmodule か -reference で取り込むしかないんだけど、最低でも1つは .cs がないと exe や winexe が出来ない。
そして、Autotools は object file を生成して linker でまとめる方法が前提になってるんだけど、.cs から直接 object file をすっ飛ばして .exe を生成するルールを書く方法がよくわらないので、上手くルールが動いてくれない。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます