C#
MacOSX
mono
Xamarin

コンソールプログラムをMonoインストールなしで実行する

More than 5 years have passed since last update.


Problem

コンソールプログラムをXamarin Studioで作ってコンパイルすると出来上がるのは.exeです。Windowsならそのまま,OSXやLinuxなら mono xxx.exe として実行することとなります。

Monoインストール環境ならシェルスクリプトでラップしてあげればいいですが,業務アプリとかはなかなかそういうわけにはいかなかったり。

検証はOSX10.8, 10.9で行っています。


Solution

まずは mkbundle です。こんな感じで実行します。DLLを使ったりするときは別にオプションが必要ですがそこはGoogle先生に…

mkbundle -o [output] [source.exe] --deps

事前にお膳立てが必要で,以下のような環境変数が必要です(Mac)。

export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/pkgconfig

export AS="as -arch i386"
export CC="clang -arch i386 -mmacosx-version-min=10.6"

exeを投入してmkbundleを実行すると,clangやらなんやら実行されてUnix Executableが出来上がります。これを otool -L します。出力はプログラムによりますが以下のような感じです。

% otool -L test

test:
/Library/Frameworks/Mono.framework/Versions/3.2.5/lib/libmonoboehm-2.0.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

本当は mkbundle --static があるんですが,どうにもうまく動かない。挙げ句mkbundle.csを修正して再コンパイルしろと言われる始末。それはちょっと手間だし,静的リンクさせてしまうとLGPLが強制されて困る場面も多々ありそう。

そこで実行ファイルと同じフォルダからdylibを読み込むように設定します。install-name-tool です。こうです。

install_name_tool -change /Library/Frameworks/Mono.framework/Versions/3.2.5/lib/libmonoboehm-2.0.1.dylib @executable_path/libmonoboehm-2.0.1.dylib [source]

これでもう一度 otool -L すると参照先が変わっているかと思います。実行ファイルと同じフォルダにdylibをコピーして配布すれば動く,はずです。


A bit more...

それなりに簡単に単体実行ファイルを作り出すことができます。Windowsでも同じように.NET Frameworkのない環境で動作するファイルを作れますが,そんな環境はあるのでしょうか。考えなくともよさそうです。

Xamarin Studioでビルド時にこの動作を行うように設定しておくとそれなりに便利です。こんな感じです。

Screen Shot 2014-01-27 at 18.26.34.png

mkbundle -o ${ProjectName} --deps -z ${TargetFile};

install_name_tool -change /Library/Frameworks/Mono.framework/Versions/3.2.5/lib/libmonoboehm-2.0.1.dylib

@executable_path/libmonoboehm-2.0.1.dylib ${ProjectName}


Conclusion

mkbundle, otools, install_name_tool でなんとかなります。