バージョン依存性を解決するための fml ブートローダ &fml8; には、 インストールされている fml のバージョン依存性を解決するために、 本章で述べるブートストラップ過程があります。 fml (libexec/distribute) が boot していく様子 functions class ---------------------------------------- main::Bootstrap() libexec/loader | V main::Bootstrap2() FML::Process::Switch | V ProcessSwitch() FML::Process::Switch | | | switch to ($obj = FML::Process:Distribute) | V ProcessStart($obj,$args) FML::Process::Flow 例: 配送処理の場合 たとえば配送処理の場合、 loader から次々とモジュールが呼ばれていく様子は次のようになります。 /usr/local/libexec/fml/distributre (の実体は /usr/local/libexec/fml/loader) は /usr/local/etc/fml/main.cf を読みこみ、 fml_version 変数から使うべきライブラリのバージョンを決めます。 たとえば fml_vesrion が 8.0.0 となっていれば、 /usr/local/lib/fml/8.0.0/ 以下にあるライブラリを使うといった具合です。 @INC を再設定した後、 loader は FML::Process::Switch をロードし、 $0 (プロセス名)を調べます。 プロセス名から自分の仕事は配送処理なので、 FML::Process::Distribute クラスをロードすればよいことを理解します。 このクラスをロードし、配送処理に移ります。 ここで、プロセス名とロードするべきクラスの対応関係は /usr/local/etc/fml/defaults/バージョン/modules (例 /usr/local/etc/fml/defaults/8.0.0/modules) に定義されています。 こういった処理は、 見かけ上 FML::Process::Flow::ProcessStart() という関数が制御しています。 ProcessStart() が引数として FML::Process::Distribute オブジェクトを渡され、 FML::Process::Distribute オブジェクトを実行していくという流れになります。 FML::Process:: クラスの階層構造 FML::Process::Distribute >-| FML::Process::Command >-|-- FML::Process::Kernel FML::Process::Mead >-| | |-use-a FML::Parse |-use-a FML::Config |-use-a FML::Log |-use-a ... その他 ... プロセス実行時の様子 [/usr/local/libexec/fml/loader (wrapper)の実行] この段階では、まだ &fml8; Perl モジュール群に制御が移っていません。 このプログラムは、loader 内の関数 Bootstrap() を実行します。 distribute など libexec/ 以下にあるプログラム群は、 どれも、この loader へのシンボリックリンクです。 /usr/local/libexec/fml/ 以下を参照してください。 [loader 内 Bootstrap() 関数の実行] /usr/local/etc/fml/main.cf を読み込み、 実行するべき fml のバージョンを知ります。 また、 main.cf の値から @INC (Perl のライブラリサーチパス)を再設定し、 読み込むべきライブラリのバージョン依存性を解決します。 default_config.cf.{ja,en} はバージョン依存ですので、 設定ファイルを読み込む前に、 この段階でバージョンを評価しなければいけません。 @ARGV (実行されたプログラムの引数)を評価し、 どのMLの config.cf (設定ファイル)群を読み込むべきか?を判断します。 このあと、ようやく FML::Process::Switch (バージョン依存)クラスをロードします。 Bootstrap2() および ProcessSwitch() を実行し、 FML::Process::Flow 経由で、 配送用、コマンドメール用などの各プロセスへ制御を移していきます。 この時点で、 どのモジュール(例: FML::Process::Distribute) をロードするのかは分かっています。 FML::Process::Distribute オブジェクトなどは、 FML::Process::Flow の関数を呼び出す際に引数として渡されています。 FML::Process::Flow 経由で、 各モジュール(例: FML::Process::Distribute) のメソッドを呼び出します。 FML::Process::Flow の中には、 どのように &fml8; プロセスを実行するかが規格化/定義されています。 おおむね、どのプロセスも $process = new FML::Process::なになに; $process->prepare($args); $process->verify_request($args); $process->run($args); $process->finish($args); を実行していきます。 のため、各プロセスは、 それぞれについて適当なメソッドを 「FML::Process::なになに」 以下のクラスに用意する必要があります。 ダミーでもいいので、全メソッドの定義が必要です。 議論: ml_name と ml_domain の値はどこで解決するのが正しいか? 現在は 「FML::Process::なになに」 の prepare() メソッドあたりで解決しています。 以下、内部構造についての走り書き/おぼえがきです。 一応、こういった構造を考慮して、 prepare() に持ってきています。 main::Bootstrap() main.cf から fml のバージョン依存性を解く hints を渡す (CGI のみ) ◎ CGI だけ 嘘の入力がありうる そのため、loader に hints として ml_domain や ml_name がハードコードされている。 main::Bootstrap2() ProcessSwitch() 使うモジュール( Process::なんか )を決定する 読み込むべき cf ファイルの決定(なんで?) ライブラリパスの決定や @INC の修正などを行う hints を渡す?使う? (CGI のみ?) ProcessStart($obj, $args) 処理本体のスタート new prepare ml_name と ml_domain の決定 CGI からの入力を解析する hints を使う?(CGI のみ?) 読み込むべき cf ファイルの決定 parse メールを読み込む コマンドラインを解析する