カレーミュージアムが2006年12月21日 13時07分44秒

終わってしまうらしい。。。

Visual C++ 2003/2005 で perl モジュールを nmake できるようにするためのパッチ2006年12月21日 17時20分57秒

こいつの続き。ていうか、すっかり忘れてたw。

ExtUtils::MakeMaker モジュールが Windows 版 ActivePerl 向けに生成する Makefile は、Windows XP (および Windows Server 2003) + Visual C++ 2003/2005 の環境 (いや、実際、VC++ 2003 では試したことないので知らんのですが、システム DLL に Manifest の概念が導入されたのがどうやらこいつかららしいので、多分間違いないかと) で nmake → nmake install しても、use する際に R6034 エラーが発生してモジュールのロードに失敗してしまうという問題があります。

解決策として、ExtUtils::MakeMaker モジュールを構成するサブモジュール ExtUtils::MM_Win32 のモジュールファイル ExtUtils/MM_Win32 の最新版 (v1.13) に対するパッチを書いたので、以下に公開します。

*** MM_Win32.pm.old	Thu Dec 21 16:28:52 2006
--- MM_Win32.pm	Thu Dec 21 16:34:28 2006
***************
*** 37,38 ****
--- 37,39 ----
  my $GCC     = 1 if $Config{'cc'} =~ /^gcc/i;
+ my $VC80    = 1 if $Config{'cc'} =~ /^cl/i && system('mt >nul 2>nul') == 0;
  
***************
*** 340,344 ****
      } else {	# VC
        push(@m,
!        q{	$(LD) -out:$@ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) }
        .q{$(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) -def:$(EXPORT_LIST)});
      }
--- 341,347 ----
      } else {	# VC
+       my $ld_manifest_option = ' -manifest -manifestfile:$@.intermediate.manifest'	if $VC80;
        push(@m,
!        q{	$(LD) -out:$@}.$ld_manifest_option.q{ $(LDDLFLAGS) }.$ldfrom.q{ $(OTHERLDFLAGS) }
        .q{$(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) -def:$(EXPORT_LIST)});
+       push @m, "\n\t", q'mt -outputresource:$@;2 -manifest $@.intermediate.manifest -nologo'	if $VC80;
      }

なお、現行の ActivePerl の最新版では、付属のExtUtils::MM_Win32 モジュールのバージョンは v1.12 となっていて若干古いので、上記のパッチを当てる場合は、まずその前に、最新の ExtUtils::MakeMaker モジュールをインストールしてから行うようにしてください (ExtUtils::MakeMaker モジュール自体はインストール時にコンパイラを必要とはしないので、cpan コマンドから install ExtUtils::MakeMaker してあげればインストールできるはずです)。

ちなみに、上記パッチでやっていることがなんなのかを一応メモしておきます。

  • 何が必要か?
    • 具体的にいうと、いわゆる標準 C ランタイムライブラリ DLL であるところの msvc?XX.dll ファイル (? には m とか p とか r とかが入る) (XX はバージョンを表す番号。v6.0 なら 60 とか) の、リビジョンなどを厳密に管理するようになった為、それに合わせて使用するこれらの DLL のバージョンを判別するような情報 (「マニフェスト manifest」と呼ばれる) を、実行ファイル (.exe ファイルや .dll ファイル) に埋め込んだりする必要が出てきた。
    • マニフェストを埋め込むには、リンク時に XML 形式のマニフェストファイルを生成し、それをマニフェストツール (mt.exe) を呼び出して埋め込む必要がある。つまり、Makefile にその辺の指示内容を含める必要がある。
    • この対応が必要なのは、C ランタイムライブラリのバージョンが v8.0 以降のもの (つまり、msvc?80.dll 以降のシリーズ) のみ。それ以前の CRT ライブラリを使用するバージョンの VC++ 環境には、そもそもリンカにマニフェストを生成する為のオプションが存在しないし、mt.exe 自体存在しない。つまり、これらのバージョンの切り分けも必要になる。
  • 実際にパッチで行っていることは何か?
    1. VC++ の (CRT ライブラリの) バージョンが 8.0 以上であることの確認 - コンパイラコマンドのコマンド名が "cl" であり、且つ、mt.exe コマンドが存在する (実際に mt を呼んでみて、コマンドの戻り値が 0 である) ならば、VC++ v8.0 以降である、とみなす。
    2. Makefile に吐き出す内容の変更 - dynamic_lib セクションにて、かつて以下のような内容が書き出されていたのを、
      $(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
      	$(LD) -out:$@ $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) $(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) -def:$(EXPORT_LIST)
      	$(CHMOD) $(PERM_RWX) $@
      
      以下のような内容で書き出されるように変更した。
      $(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
      	$(LD) -out:$@ -manifest -manifestfile:$@.intermediate.manifest $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) $(MYEXTLIB) $(PERL_ARCHIVE) $(LDLOADLIBS) -def:$(EXPORT_LIST)
      	mt -outputresource:$@;2 -manifest $@.intermediate.manifest -nologo
      	$(CHMOD) $(PERM_RWX) $@
      
      ちゃんと解説すると、よーするに、以下の変更を加えている。
      • link コマンドに、マニフェストを生成する為のオプション -manifest-manifestfile:(ファイル名) を追加。
      • link コマンドを呼んだ直後に、mt コマンドを呼ぶ。オプションの -outputresource:(ファイル名);(リソース番号) は、ファイル名のオブジェクトにマニフェストをリソースとして埋め込む、という意味。リソース番号は DLL の場合は常に 2 となる。
  • 何ができるようになるか?
    • 無料配布されている VC++ 2005 ExpressPlatform SDK を用いて、ActivePerl 環境向けに Perl モジュールをビルド (nmake) することが出来るようになる。
    • すなわち、これまでは不可能だった、Win32 版 ActivePerl 向けのモジュール開発・テスト環境をタダで構築するということが可能になる。

ちうわけで。。。おいらエーゴわかんないから誰か連絡してあげて~\(^O^)/