2011年8月13日土曜日

SSCLI2.0 ビルド戦記 - Battle Against Makefile -

Win XP(x86) + VS2008 でビルドしようなんて思うから…。

アンマネージ API を使いたい時に困るのがサンプルコードの探しにくさ。日本語の情報はもちろん絶望的だし、本家 MSDN にあるリファレンス も、I/F の簡単な説明しかない…。まずは、"Hello, world!!" から始めたくても、一連の流れがわかるのは .NET Framework SDK Version 1.1 についてくる Metadata Dump Utility や SMC - Simple Managed Compiler Sample が、唯一の頼みの綱という状態。…かと言って、これらでも全ての API 網羅してるわけではないわけで。

発端は、SMC のコードを追っていて。
SMC って、MethodBody の RVA についての計算と領域の確保を手動でやってるんです。あれ?アンマネージ API リファレンスに ICeeGen::AllocateMethodBuffer ってあるけど、これは使わないの?と。grep すると案の定どこからも呼ばれていない。一縷の望みにかけて Google 先生にお伺いすると…。




うわあああああああ知らなかった \(^o^)/『Download Details - Microsoft Download Center - Shared Source Common Language Infrastructu… http://bit.ly/qgLBod』
Microsoft 謹製の CLI リファレンス実装があったなんて!なんといういい仕事!これを参考にせず何を参考にするのか!

まあソースコードを動かしながら参照しようにも、やはり日本語のビルド手順はないですし、以前の『うらぶろぐ @urasandesu: Windows で AVRDUDE ビルド』でハマったように、低レイヤ開発環境ビルドの難しさは知っていました。
ですが、図書館で調べながら設計や実装を進められたり、持ち出して人に現状を見ていただき意見や感想をいただける利点が捨てがたく、何とかいつも使っているノート PC で動くようにした顛末です。


こちらのページ/ソフトウェアを参考に/使用させていただきました!偉大な先人の方々に感謝です。
Download Details - Microsoft Download Center - Shared Source Common Language Infrastructure 2.0 Release
Download Details - Microsoft Download Center - .NET Framework Software Development Kit Version 1.1
Cygwin
ActivePerl is Perl for Windows, Mac, Linux, AIX, HP-UX & Solaris | ActiveState
SSCLI 2.0 and Visual Studio 2008 - Jeremy Kuhne's Blog - Site Home - MSDN Blogs
Shared Source Common Language Infrastructure 2.0 - Memo+
- 自動化のための nmake 入門講座
A Night with Rotor and Rotor Resources : Sam Gentile's Blog
8.3形式の短いファイル名を生成しないようにする - @IT
普通のpatchコマンドで取り込めるdiffファイルをgitで作成する - kanonjiの日記



とりあえず結果から
Jeremy Kuhne さんのブログ ですが、結構 typo とかあるのでパッチを作りました。運が良ければ当てて終わりです!

sscli20_WinXPx86_VS2008_JP.patch (11 KB) - Google Docs

1. SSCLI2.0 をダウンロード、解凍。必要ソフトをインストール。
Download Details - Microsoft Download Center - Shared Source Common Language Infrastructure 2.0 Release から、ソースコードがまとまった sscli20_20060311.tgz をダウンロードし、解凍する(ここでは、C:\sscli20_20060311 へ)。Active PerlCygwin 等、必要なツールをインストール。

2. Cygwin を起動し、パッチ当て
ダウンロードした sscli20_WinXPx86_VS2008_JP.patch を解凍したフォルダ(ここでは、C:\sscli20_20060311)に置き、Cygwin で以下のようにコマンドを実行、パッチを当てる。

user@COMPUTER ~
$ cd /cygdrive/c/sscli20_20060311/

user@COMPUTER /cygdrive/c/sscli20_20060311
$ ls
sscli20  sscli20_WinXPx86_VS2008_JP.patch

user@COMPUTER /cygdrive/c/sscli20_20060311
$ patch --dry-run -p0 -i sscli20_WinXPx86_VS2008_JP.patch
patching file sscli20/clr/src/classlibnative/float/sources.inc
patching file sscli20/clr/src/classlibnative/float/wks/sources
patching file sscli20/clr/src/classlibnative/nls/sources.inc
~(中略)~
patching file sscli20/tools/cppmunge/sources
patching file sscli20/tools/resourcecompiler/sources
patching file sscli20/win.env.bat

user@COMPUTER /cygdrive/c/sscli20_20060311
$ patch -p0 -i sscli20_WinXPx86_VS2008_JP.patch
patching file sscli20/clr/src/classlibnative/float/sources.inc
patching file sscli20/clr/src/classlibnative/float/wks/sources
patching file sscli20/clr/src/classlibnative/nls/sources.inc
~(中略)~
patching file sscli20/tools/cppmunge/sources
patching file sscli20/tools/resourcecompiler/sources
patching file sscli20/win.env.bat



3. コマンドプロンプトを起動し、ビルド
後は通常の手順である readfirst.html(ここでは、C:\sscli20_20060311\sscli20\readfirst.html) の Building and Running Code を参考にビルドする。

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\user>cd C:\sscli20_20060311\sscli20

C:\sscli20_20060311\sscli20>env
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
32-bit build
Checked Environment
Building for Operating System - NT32
             Processor Family - x86
                    Processor - i386
                   Build Type - chk

C:\sscli20_20060311\sscli20>buildall

--- Copy prebuilt files ---

C:\sscli20_20060311\sscli20\prebuilt\idl\clrdata.h
~(中略)~
C:\sscli20_20060311\sscli20\prebuilt\yacc\asmparse.c
        1 個のファイルをコピーしました。

--- Building the PAL ---

Build successful.

--- Building the binplace tool ---

Build successful.

--- Building the build tool ---

Build successful.

--- Building the cppmunge tool ---

Build successful.

--- Building Resource Compiler ---

BUILD: Using 2 child processes
~(中略)~
1>Linking Executable - objc\rotor_x86\resourcecompiler.exe for i386
BUILD: Done

    1 executable built
    1 browse database built

--- Building PAL RT ---

BUILD: Using 2 child processes
~(中略)~
b\chk\rotor_x86\rotor_palrt.lib for all platforms
BUILD: Done

    1 file compiled -     5 LPS
    4 libraries built
    3 executables built
    4 browse databases built
    70 files binplaced

--- Building C# compiler ---

BUILD: Using 2 child processes
~(中略)~
2>Linking Executable - scc\pkg\objc\rotor_x86\csc.exe for i386
BUILD: Done

    4 files compiled -     8 LPS
    5 libraries built
    4 executables built
    5 browse databases built
    6 files binplaced

--- Building CLR ---

BUILD: Using 2 child processes
~(中略)~
BUILD: Examining C:\sscli20_20060311\sscli20\clr\src directory tree for files to compile.
    C:\sscli20_20060311\sscli20\clr\src
BUILD: Done

    30 files compiled
    44 libraries built
    25 executables built
    48 browse databases built
    225 files binplaced

--- Building FX - pass1 only ---

BUILD: Using 2 child processes
~(中略)~
    C:\sscli20_20060311\sscli20\fx\src
BUILD: Done

    10 files compiled
    1 file binplaced

--- Building Remoting - pass1 only ---

BUILD: Using 2 child processes
~(中略)~
    C:\sscli20_20060311\sscli20\clr\src\managedlibraries
BUILD: Done

    4 files compiled

--- Building JScript - pass1 only ---

BUILD: Using 2 child processes
~(中略)~
    C:\sscli20_20060311\sscli20\jscript
BUILD: Done

    4 files compiled

--- Building FX - System.dll ---

BUILD: Using 2 child processes
~(中略)~
BUILD: Done

    1 file compiled
    1 executable built
    1 file binplaced

--- Setting up System.dll ---


--- Building FX ---

BUILD: Using 2 child processes
~(中略)~
    C:\sscli20_20060311\sscli20\fx\src
BUILD: Done

    3 files compiled
    5 executables built
    5 files binplaced

--- Setting up System.Configuration.dll ---


--- Setting up System.Configuration.dll ---


--- Setting up System.Xml.dll ---


--- Setting up System.Data.SqlXml.dll ---


--- Building FX - Misc ---

BUILD: Using 2 child processes
~(中略)~
BUILD: Done

    1 file binplaced

--- Building Remoting ---

BUILD: Using 2 child processes
~(中略)~
BUILD: Done

    2 files compiled
    2 executables built
    2 files binplaced

--- Building JScript ---

BUILD: Using 2 child processes
~(中略)~
    C:\sscli20_20060311\sscli20\jscript
BUILD: Done

    2 files compiled
    3 executables built
    3 files binplaced

--- Building dactablegen ---

BUILD: Using 2 child processes
~(中略)~
BUILD: Done

    1 executable built
    1 file binplaced

--- Building dacupdatedll ---

BUILD: Using 2 child processes
~(中略)~
1>Binplacing - objc\rotor_x86\daccess.i for rotor_x86
BUILD: Done

    1 file binplaced

--- Building strike dll ---

BUILD: Using 2 child processes
~(中略)~
1>Binplacing - sos_stacktrace.h for i386
BUILD: Done

    1 file compiled -     1 LPS
    1 library built
    1 executable built
    1 browse database built
    5 files binplaced

--- Setting up everything ---


--- Building samples ---

BUILD: Using 2 child processes
~(中略)~
1>Linking Executable - pigui\pigpad\@objc\rotor_x86\csc.rsp for all platforms
BUILD: Done

    35 executables built
    78 files binplaced

--- Building pdb to ildb Tool ---

BUILD: Using 2 child processes
~(中略)~
1>Linking Executable - objc\rotor_x86\ildbconv.exe for i386
BUILD: Done

    1 executable built
    1 browse database built
    1 file binplaced

C:\sscli20_20060311\sscli20>




だめだった人ー?
(・∀・)人(・∀・)ナカーマ

残念ですが…。もし、エラー内容が以下のような雰囲気であれば、私と同じような感じで行けるかもしれません。
  • 「*** Error while building C:\sscli20_20060311\sscli20\pal\win32 Open C:\sscli20_20060311\sscli20\pal\win32\buildc.log to see the error log.」ってエラーメッセージが出た。
  • 言われた通り、buildc.log を見ると「.\rotor_pal.rc(15) : fatal error RC1015: cannot open include file 'ntverp.h'.」ってエラーメッセージが出てる。
  • 最初の env コマンドで環境変数設定されてるんじゃないの?と思って set | more で環境変数確認すると…!? INCLUDE が定義されてない???
  • buildc.log でエラー吐いてる「Microsoft (R) Windows (R) Resource Compiler」は、INCLUDE 環境変数使わないのかな?と思って、MSDN で確認すると、やっぱり使うことがわかる
  • /\binclude\b\s*=/i で grep してみる。結果を分類すると、それっぽいのが十数個見つかる。…★
  • rc 実行する箇所も探してみる。/\brc\b/i で grep 。結果を分類すると、★とファイルが重複するものが見つかる(devdiv.def、ここでは C:\sscli20_20060311_\sscli20\env\bin\devdiv.def)。怪しい。…★★
  • ビルドスクリプトで、いつこれが呼ばれるのかわからない。buildall.cmd(ここでは、C:\sscli20_20060311_\sscli20\buildall.cmd)を読んでみる。
  • 1 行目に「@if "%_echo%"=="" echo off」ってある。ほむほむ。set _echo=1 で buildall 2>&1 > buildall.log してみる。
  • echo でデバッグプリント。INCLUDE 環境変数に変化なし。Makefile 内が怪しい。
  • 問題の Makefile (ここでは、C:\sscli20_20060311_\sscli20\pal\win32\makefile)を確認してみると…先頭で「!INCLUDE $(NTMAKEENV)\devdiv.def」してる!★★と繋がった!
  • devdiv.def がビルドスクリプトからそのまま呼ばれるのがわかったので、ここでもデバッグプリントを順に埋め込んでみる。最初 @echo で出力させようとして半日ハマる(!MESSAGE プリプロセッサを使わないといけないという罠。マクロは、コマンドの前に評価されるのになかなか気づかず…orz)。
  • あー、C:\PROGRA~1\Microsoft SDKs\Windows\v6.0A\include が「INCLUDES = $(INCLUDES: =)」の処理でスペース除去されちゃうんだ…。
  • でも、C:\Program Files が C:\PROGRA~1 になってるんだから、Microsoft SDKs も短縮されていいはずなのに…。意味がわかりません (((・・;)
  • 「.\rotor_pal.rc(15) : fatal error RC1015: cannot open include file 'ntverp.h'.」でググってみる。
  • む? short filename が作られていない?またまたそんな…と、C:\Program Files に移動しコマンドを叩く。

  • C:\Program Files>dir /x "Microsoft SDKs*"
     ドライブ C のボリューム ラベルは S3A4509D001 です
     ボリューム シリアル番号は 758E-2116 です

     C:\Program Files のディレクトリ

    2009/05/14  20:50    <DIR>                       Microsoft SDKs
                   0 個のファイル                   0 バイト
                   1 個のディレクトリ  25,656,471,552 バイトの空き領域

    C:\Program Files>

    ( ゚д゚ )
  • どうしてこんなことに…。しかたないので、@IT にある記事の通り fsutil を実行して再度 short filename を有効に。まだプチフリをよく起こす SSD 使ってたころの設定、そのまま持ってきちゃったのかな...( = =)
  • フォルダを再作成し、中身をごっそりコピー。
  • そして今一度 buildall・・・!行った!おめでとー!

普段 Visual Studio を利用している開発者にとって、Makefile のデバッグは慣れなくて大変だと思います。ですが、各コマンドのリファレンスを片手に、!MESSAGE プリプロセッサと grep で上手く絞り込んで行ければ、それほど時間はかからないでしょう。



お次は念願の "Hello, world!!" ?
少しずつ近づいている気はするのですが、なかなか辿り着かないこの入り口。勉強会等々で、もっと情報交換できるといいのだけれど。英語がんばるのも、これからの課題ですね。