IT井戸端会議

IT井戸端会議

インフラ、ネットワーク、アプリケーション開発、IT界隈の話等々を東京都千代田区界隈から発信します。

Perlスクリプトの汎用化+GUI化+exe化=アプリ誕生!(3)

みなさまこんにちは。

前回より間があいてしまいましたが、忘れないうちに今回、Perlスクリプトをパッケージ化するお話を書きたいと思います。

 

<今回やること>

■「PAR::Packer」のインストール ■コマンド「pp」によるスクリプトのExe化

まず最初に、結果的に上記2つのために必要だと判明した手順のみ書いておくと、次のようになります。 た っ た 5 行 です。 (ただし、この辺の手順は依存関係にある全てのモジュールのバージョンやメンテナンス状況により変わるため、あくまで参考です)

~~~~ cd C:/perl/bin Set http_proxy=~ cpan install PAR::Packer copy C:/Perl/site/lib/auto/MinGW/bin/windres.exe C:/Perl/site/bin/windres.exe pp -o CiscoCmdTool.exe CiscoCmdTool.pl ~~~~

これまで、ActivePerlの導入からGUIの作成まで、途中で行き詰まったり試行錯誤したりした過程というのはあまり書いてこず、「結果こうなりました」的に、サラッと書いてきました。 まぁ実際、スクリプト自体は割とすんなりと書けましたし、GUI化の時はPerl/Tk以外にGUI::Loftというのも試したけどうまく導入できなかったので結果的にPerl/Tkでイケましたし、Perl/Tkもcpanじゃうまくいかずppmから入れたり、ZooZのインストールも最初はコマンドひとつでは使えなかったのでフォルダコピーして直接実行してみたらイケた、程度の試行錯誤で済んでいました。

ところが今回、パッケージ化用のツールキットである「PAR::Packer」の導入には、相当手こずりました…。 これは「PAR」という単なるアーカイバと、自作スクリプトスタンドアロンなExeとして動作させるのに必要な諸々をやってくれる「PAR::Packer」の両方があって機能します。調べてみるとこれが以前は「PAR」と一緒にインストールされていたものを、現在は分離して個別にインストールしなければならなくなった経緯のあるツールのようでした。 この辺は、使いたいモジュールのメンテナンス状況によっても事情は様々に変化するでしょうし、自分のした苦労が他の人はまったくせずに済むケースもあろうかと思います。 ベースのActivePerlに含まれる諸々のバージョンや、その時にセットアップされていたコンパイラのバージョンとの相性みたいなところもありましたしね。 ただ逆に言えば、もしパッケージ化によるスタンドアロンアプリ化に一度成功してしまえば、いちいち自分のしたような環境構築の苦労をせずに、望む機能だけが使えるようになる…ということでもあります。やってみる価値は充分にあるでしょう。

という訳で、人によっては面白い、人によっては全然面白くもなんともないであろう、苦労話を書いてみます。たまにはこういうのもいいかと。前置きが長くなりましたが、本編も長いです(笑)全八章構成です。 では、行きます。

 

■「PAR::Packer」のインストール

 

~第一章 CPANがNG!?~

 

いつも通り、コマンドプロンプトからcd c:\perl\bin、プロキシ設定の後に

cpan install PAR::Packer

というコマンド一行で済むはず…でした。本来は。 ところが、コマンドプロンプト流れる膨大な量のコンソールログを眺めていると、しばらくして処理が中断しました。 出ていたメッセージは、

~~~~ 'windres' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 ~~~~

今思えば、この意味を素直に解釈していればよかったのですが…。 訳が分からず、何回かコマンドを打ち直してみるも同じ。

 

~第二章 CPANがダメならPPMがあるじゃない~

 

Perl/Tkの時のように、cpanでNGだったのでppmでのインストールを試します。

ppm install PAR-Packer

をやってみました。すると、今度は一発ですんなり入って、ビルド完了してくれました。 「なーんだこっちならよかったのか」とぬか喜びします。浅はかでしたわ…。

早速自作スクリプトを使って、パッケージ化のコマンド

pp -o CiscoCmdTool.exe CiscoCmdTool.pl

と打ち込んでみました。すると

「実行してるPerlのバージョンがちげーよ!」 「おめーのは5.20.2、俺のは5.20.1だよボケェ!」

と怒られます…。 Exe化する仕組みとしては、ppコマンドに指定した自作スクリプト以外に、スクリプトを解釈するPerlインタプリタ、使うモジュール、そのモジュールが依存する別のモジュール…などなどを芋づる式に全部ひっくるめてzip形式で1ファイルに圧縮し、そのバイナリをゴニョゴニョしてブートストラップしてしまうというものです。その辺はExe化の方法を調べた時に知っていたので、 「あーなるほど、インストールしていたActivePerlは最新版だったから、パックするインタプリタの更新が追いついていないんだな」と原因に思い込みあたりをつけます。

 

~第三章 ActivePerl過去版探しの旅~

 

ということで、ActivePerlの過去版を探します。 せっかくここまで構築してきた実行環境を泣く泣くアンインストールし、公式ページから落とした過去版をインストールし直します。

そしてppmからPAR::Packerをインストール。エラーはありません。 ppコマンドを実行してみると、今度も落とした方のバージョンで 「実行してるPerlのバージョンがちげーよ!」 と同じように怒られます…。バージョン末尾の数字がひとつふたつ違うだけなんですが…そんなにPerlってバージョンに厳しいのか? 気を取り直して、さらにActivePerlのアンインストール→別バージョンのインストールを試すも、またも同じく怒られます…。

「そもそもこれ、バージョン一致させるの無理なんじゃね?」 そんな絶望的な想いがよぎり、ActivePerlを再び5.20.2に戻します。

 

~第四章 CPANのメッセージを見つめ直す~

 

さて、戻したはいいものの、状況は変わらない訳です。 ここで、ppmからのインストールとバージョン一致させる線は捨てて、CPANからインストールする線に戻ってみます。

改めてCPANからインストールしてみると、その処理は大きく次のようなステップで行われているようでした。

1.リソースのダウンロード 2.設定されたコンパイラを使ってコンパイル 3.コンパイルした結果のモジュールを動作させてテスト

今回直面しているエラーはこの3で、テスト中に発生しているようです。テストで発生する細かなエラーは、cpanに -f (強制のforce )オプションをつけることで無視してインストールできるらしいことも調べるうちに分かってきましたが、それを試しても、問題は解決しません。問題はテスト結果のエラーではなく、テスト中に使用されているらしい、「windres」コマンドがないこと。 なんとかしてこのコマンドを実行させねばなりません。

 

~第五章 binutils過去版探しの旅~

 

Google大先生によれば、本来windresはコンパイラであるMinGWbinutilsの中にあるものらしい。しかも、最近のバージョンだとwindresが入っていないらしい。なんじゃそりゃ!?と思いながらも、実際ないんだからしょうがない。入れてやるしかない。

でも、どこから?ということで、今度はMinGWbinutilsを探します。

もうこの辺から記憶が曖昧なのですが、MinGWインストーラと思ってダウンロードし実行したものは、実は単なるダウンローダで、そいつ自身がさらにパッケージをダウンロードしようとするも、古いもののせいかどこにもなくてストップする…という悪夢の中でさらに悪夢をみるような思いも味わいます。

 

~第六章 まさに灯台下暗し…~

 

で、絶望に打ちひしがれて、どこにあるんだwindres~と何を思ったかローカルフォルダの中を彷徨いだす自分。あれば苦労はしないはず…なんですが、やぶれかぶれでローカルの中を「windres」で検索してみます。すると!

C:/Perl/site/lib/auto/MinGW/bin

に「windres.exe」というファイルがあるのを発見します! これこれ、これではないですか! で、試しにここのフォルダにPATHを通してみますが症状は変わらず。で、「windres.exe」をC:\Perl\site\binへコピーしたら、今度はインストール成功! 「C:\Perl\site\bin」はActivePerlインストール時に、環境変数へPATHが通してあるので MinGWに入ってたってことは、たぶんPAR::Packerのインストールバッチ、またはテスト用のバッチの中でコピーし忘れたのでしょうかね…?

最初から素直に、エラーメッセージの内容に従ってwindresを探していればよかったのですね…。 膨大な量のテスト項目らしきものが、無事に自動実行完了しました。

 

■コマンド「pp」によるスクリプトのExe化

 

祈るような気持ちで、ppコマンドを実行します。 今度は、バージョンちげーよ!と怒られることもなく、指定したExeファイルが出来上がってくれました。 ついにパッケージ化成功か!?

 

~第七章 ソーススクリプトにモジュール記述追加~

 

祈るような気持ちで、出来上がったExeファイルをダブルクリックします。 すると、コマンドプロンプトらしきウィンドウが一瞬だけ開いては消えました。失敗…。仕方なく、一瞬で消えるメッセージを確認すべく、予め開いておいたコマンドプロンプトから、Exeファイルのフルパスを指定して実行します。 すると今度は、「Win32を配置できねーよ、カス!」とお怒りになっておられました…。

確かに、GUI用にWin32::GUIというモジュールはロードしないといけないものの、そもそもなぜPerlスクリプトとして実行している時には怒らない起こらないことがExeだと怒る起こるのでしょうかね。 とはいえ、ないものは仕方ないので、自作スクリプトにuse Win32を追加してコンパイルし直します。Exe叩くと、また落ちます。またメッセージ確認します。今度は 「Arybaseを配置できねーよ、カス!」と…はいはい。名前からして、配列を扱うモジュールですかね。で、またuse Arybaseを追加してコンパイルし直します。 どうせまた何か言ってくるんだろ…と、思いきや。

 

~第八章 始まりの終わり~

 

ついに起動しました!前回自分の書いたGUI画面が! フォルダ選択ダイアログも、きちんと動きます。 嬉しいはずなんですが、相当長いお使いゲーをクリアしたような、微妙な気分でしたわ、えぇ。

という訳で、この過程で丸2日かけました(笑) 無駄な工数長い長い旅路の果てに、ついにExe化を実現したのでした。 つまり、単なるスクリプトキディが、GUIつきのスタンドアロンアプリ開発者に進化した!! という気分を味わった瞬間です。気分だけ。

めでたし、めでたし?

でもまぁ、動いたら動いたで、また色々と課題は出てくるのです…。