Gauche:StandAloneProgram

Gauche:StandAloneProgram

Shiro(2009/11/20 16:00:16 PST): 時々、「Gaucheでスタンドアロンなバイナリが作れないか」、 という質問があがります。簡単な答えは「作れる」ですが、 私自身、仕事でGaucheプログラムを納入する際にはくつかの方法を使い分けているので、 ここに整理しておきます。そのうちGaucheが安定したら、標準的な方法を提供する ことになるかもしれません。

「スタンドアロン」の意味

「スタンドアロンバイナリ」と言うとバイナリひとつコピーすれば動く、というものを イメージしがちですが、ほとんどの言語によるプログラムはたとえ単一バイナリに コンパイルされていても言語のランタイムを必要とします (組み込み用など 本当に単独バイナリで動くものもありますが、動的リンクが普通になった現代では どちらかというと例外でしょう)。 CやC++でコンパイルしたプログラムがバイナリだけで動くように見えるのは、 単に言語のランタイムがすでにターゲットマシン上にインストールされているからに過ぎません。

そして、Gaucheランタイムが既にインストールされているなら、わざわざコンパイルしないでも goshスクリプトひとつ持ってゆけば動くわけです。 おそらくGaucheプログラムを実行可能バイナリにコンパイルしたい、と言うリクエストの多くは、 実はランタイムを別にインストールすること無しに動かしたい、という目的じゃないかと思います。 けれども、実行ファイルの形態としてバイナリが欲しい、という問題と、 言語のランタイムをどうやってターゲットマシンに持ち込むか、という問題は 直交する話なのです。

ここではそれぞれについていくつかの方法を示します。

ランタイムの導入

Gaucheをインストールしてもらう

ある意味自明な解ですが、昔は例えばjavaプログラムを配布する時は 「ランタイムをインストールしてね」と言ってたわけで、似たような話ではあります。

この方法のメリットには次の点があります。

ただ、たとえ数ヶ月に1度でもランタイムのアップデートがかかると、 その度にインストールしてもらうのはクライアントに負担がかかりますね。 1.0以降はもう少し安定して使える形にしたいとは思うんですが。 複数のGaucheアプリで共有できるというのも、バージョン間の違いがあると 逆に面倒になったりするので、この方法を広く使うのはもっと安定してからですね。

あと、オフィシャルにバイナリインストーラブルなランタイムを配布してない というのも不便な点かも。(昔はrpmを配布してたんですが私がUbuntuに 移行してからrpm使わなくなっちゃったんで止めちゃいました。)

私の仕事では、

といった方法を取ったことがあります。

また、一品ものの製作ではターゲットの環境をある程度指定できることも多いので、 アプリをインストールする際にGaucheも標準パスにインストールしてしまう、 という手も使ったことがあります。ターゲットマシンで他のGaucheプログラムを 使ったりしてると勝手に新しいGaucheが入れられたら困る可能性があるわけですが、 「ターゲットマシンでは他のGaucheアプリを走らせない」と話をつけておけばいいわけです。

アプリにGauche自身を含める

そこまでターゲットの環境を指定できず、またクライアントに手間をかけさせたくない 場合は、アプリにGauche自身を含めてしまうことがあります。 Gauche全体をアプリケーション固有のディレクトリ (例えば /usr/lib/TheAppilcation/ ) 以下に 含めてしまうのです。 アプリケーション自身はそのディレクトリにインストールされたGaucheを使うように、 インストール時にフルパスを埋め込みます。

メリットは:

今のところはこの方法が無難だと思います。

デメリットはアプリ自体が大きくなることの他に、 環境によっては動的リンカが実行時にアプリケーション固有のlibgauche.soではなく /usr/libなどにインストールされたlibgauche.soをリンクしてしまうとか、 アプリで使う拡張モジュールのコンパイル時に/usr/bin/goshではなくアプリ固有の goshの方を見にゆくように気をつかう必要がある、ということがあります。 (Linuxならインストール時に-rpathが適切に設定されるんですが、 *BSD系で-rpathの優先順位が違ってたりとか細かいことでひっかかった覚えが)。

なお、OSXの場合はGaucheをframeworkとしてビルドすれば、 コンパイル済みディレクトリごとappフォルダの中に放り込むだけで良かったはず。

Windowsをターゲットとする仕事は無かったのでやったことがないけれど、 Windowsネイティブ版はlibgauche.dllからの相対ディレクトリでロードパス等が 設定されるので、うまく配置してやればいけるんじゃないかという気がします。

実行可能バイナリの作成

ランタイムはどうにかなったとして、実行ファイルそのものとか、 アプリのロジックを実装しているGaucheモジュールをバイナリにしたい、 という要求があることもあります。最近は制限がゆるくなりましたが、 プラットフォームによってはsuid/sgidプログラムはバイナリ実行形式じゃないとだめ という場合がありました。また、仕事によってはアプリのロジックを 実装したGaucheモジュールのソースを配布したくない、ということもあります。 あと、Windows環境で#!-magicがそもそも使えず、batファイルを配るのもどうか…という 場合とか。

Cプログラムとして書いてlibgaucheをリンクする

Gaucheの本体はlibgaucheにあり、goshは単なる薄いラッパーシェルにすぎないので、 goshの代わりとしてアプリをCで書いてlibgaucheをリンクしてしまえば アプリ自身はバイナリになります。

もちろん全部Cで書くならGaucheを使う意味はないわけですが、アプリの主要部分は Schemeで書いておいて、mainの中からScm_RequireとかScm_Loadとかすればいいわけです。

バイナリのふりをさせる

上のバリエーションですが、簡単なスクリプトだとアプリ本体を別のSchemeファイルとして 用意するのも何なので、Gauche:scm2exeのようなスクリプトを使って アプリ本体のSchemeコードをCのstatic文字列文字列として埋め込んでしまう という手があります。 これだとCコードを手で書く必要もなく、実行可能なSchemeスクリプトをそのまま 実行可能なバイナリに変換できます。

バイナリといっても中身はほとんど文字列なわけですが、suidの制限は回避できます。

プリコンパイルする

ソースを公開したくない、という話は、理想はともかく 現実のしがらみの中ではしばしばあるものです。

まだオフィシャルな方法ではありませんが、Gaucheは いくつかのSchemeモジュールをコンパイルし、まとめて.soにすることができます。

オフィシャルにしてないのは、この方法を使う際にはまだ色々制限があって 通常の実行モード (ソースを読み込んで直ちにコンパイル) と完全互換にならないためです。 が、私の仕事では必要があったのでこの形式で納品したことがあります。

どうしても必要に迫られることがあったらGaucheのビルドプロセスを眺めれば 方法がわかると思います。ただしその方法が今後も同じであるかどうかは保証しません。 At your own riskでどうぞ。

「バイナリひとつコピー」でいけるようにならない?

ほんとうにちょっとしたスクリプトを配布する際には、 「インストール」という手順を踏ませたくない、という場合もあります。 また、インストールしてしまうとあちこちにファイルがばらまかれて 気軽に試しにくい、なんていう心理的障壁があったりすると、 ファイルひとつコピーして実行できるよ、というのは魅力的かもしれません。

個人的にはインストール/アンインストールはそんなに面倒くさくないので 私自身があまり積極的にやろうとは思わないんですが、 Gauche:gauche-statifierのような試みはあります。 ただし、プラットフォーム依存になるのでこれはこれで面倒な問題もあります。

(追記2017/08/05 01:51:22 UTC): 今はスタティックリンクされた単一バイナリを作ることが可能になっています。 https://github.com/shirok/Gauche/blob/master/doc/HOWTO-standalone-gauche.txt

コメント、議論

Post a comment

Name:

More ...