Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Hudsonプラグイン使用感その2

タグ: Hudson

Warnings Plugin 3.2
http://wiki.hudson-ci.org/display/HUDSON/Warnings+Plugin

Static Analysis Utilitiesを使ったStatic Code Analysis Plug-insの1つ。
プロジェクトの「設定」で「コンパイラの警告の集計」にチェックを入れておくと、ビルドごとにコンソールログ等を解析し、警告(エラー含む)の集計を行う。
コンソールログだけの状態より警告の概観がずっと楽になる。

以下、使っていて気付いたあれこれ。


Subversion Plugin 1.11
http://wiki.hudson-ci.org/display/HUDSON/Subversion+Plugin

Subversionのリポジトリからファイルをチェックアウトしたり、ビルドに使用したリビジョンに「タグを設定」するプラグイン。
「タグを設定」したビルドは「ビルド履歴」で一望できる。
便利な機能だが、

  • 「タグを設定」時に平常時と異なる認証情報を使うことができるが、この認証が成功した試しがない
  • 「タグを設定」のコメントに日本語を含めると文字化けする

といった問題がある。


Promoted Builds Simple Plugin 1.11
http://wiki.hudson-ci.org/display/HUDSON/Promoted+Builds+Simple+Plugin

Promoted Builds Pluginの簡易版。

  • 成功ビルドを手動で「昇進」させる
    simple_promote.png
  • 昇進にはレベルがあり、レベルごとに任意のアイコンを表示できる(ただしこの設定は全プロジェクト共用)
    qa_build.png
  • 昇進させたものを後から降格できる
  • マルチ構成プロジェクトではマスタービルドだけでなくサブビルドも昇進できる
  • 昇進させたビルドは自動的に「保存」される(サブビルド含め)
  • プラグインを有効にしていなかった時期のビルドは昇進の対象外
  • Promoted Builds Pluginとは違い、失敗ビルドは昇進させられない
  • Promoted Builds Pluginと併用可能

昇進とか考えず、単に「成功ビルドを保存しつつアイコンを付けるプラグイン」と考えると良い。

改行コードがLFなバッチファイル

タグ: Windows
echo foo bar
echo ほげ ふが

Windows XP SP3でこのようなバッチファイルを「文字コードはShift JIS」「改行コードはCRLF」で作って実行すると

C:\>echo foo bar
foo bar

C:\>echo ほげ ふが
ほげ ふが

問題なく動作するが、改行コードをLFにすると

C:\>echo foo bar
foo bar

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

実行時に2バイト文字の数だけ?文字が消失してしまう。

逆にバッチファイルの中身が1バイト文字だけであれば

echo foo bar
echo ホゲ フガ

改行コードがLFでも正常に動作する

C:\>echo foo bar
foo bar

C:\>echo ホゲ フガ
ホゲ フガ

っぽい。

Hudson Warnings PluginとVCBuild /M2

タグ: Hudson VS2005

VCBuild.exeは/Mオプションを使うことでソリューション内の複数のプロジェクトを並行ビルドできる。

C:\temp>VCBuild.exe /M2 test.sln

並行ビルドでは複数のビルドプロセスの診断メッセージが入り交じることになるので、そのメッセージがどのプロセスに属するものかを識別するために、診断メッセージの先頭にはビルドプロセス番号が記される。

1>ビルド 開始: プロジェクト: Hoge、構成: Debug|Win32
2>ビルド 開始: プロジェクト: Fuga、構成: Debug|Win32
1>コンパイルしています...
2>コンパイルしています...
1>hoge.cpp
2>fuga.cpp
1>c:\temp\hoge\hoge.cpp(15) : warning C6386: バッファ オーバーランです:
1>c:\temp\hoge\hoge.cpp(24) : warning C6386: バッファ オーバーランです:
1>c:\temp\hoge\hoge.cpp(34) : warning C6386: バッファ オーバーランです:
1>c:\temp\hoge\hoge.cpp(35) : warning C6386: バッファ オーバーランです:
2>c:\temp\fuga\fuga.cpp(13) : warning C6386: バッファ オーバーランです:
2>c:\temp\fuga\fuga.cpp(36) : warning C6385: 無効なデータです:

しかるにHudson Warnings Plugin 3.2のMSBuildパーサはこのビルドプロセス番号を含む表記に正しく対応しておらず、コンパイラの警告ビューの詳細タブからソースコードを表示させようとしても

Caused by: java.io.FileNotFoundException: 1>c:\temp\hoge\hoge.cpp (No such file or directory)

とエラーになってしまう。
原因はMSBuildパーサがビルドプロセス番号までファイルパスの一部と認識しているからなので、MsBuildParser.javaの正規表現の先頭部分

private static final String MS_BUILD_WARNING_PATTERN = "(?:(?:

にビルドプロセス番号を無視する記述を加えて

private static final String MS_BUILD_WARNING_PATTERN = "(?:\\d+>)?(?:(?:

こうすれば表示できるようになる。

Snow LeopardのAutomatorはBMPを別の形式に変換できない

タグ: Mac SnowLeopard
snow_leopard_bmp_to_.png

Mac OS X 10.6.2での実行結果。
JPEGからBMPへの変換は成功するが、BMPからPNGへの変換は失敗する。
うーん、10.5の頃は問題なく出来ていたと思うのだが……

Apple Discussions - Automator: Change BMP to JPEG files ...

Looks like a Snow bug, see the comments here. It was working for one guy on Leopard, but Snow broke it!

やっぱそうだよねぇ。

Hudson MSBuild Plugin使用感

タグ: Hudson

Hudson MSBuild Plugin 1.3
http://wiki.hudson-ci.org/display/HUDSON/MSBuild+Plugin

Visual Studioのソリューションをビルドするプラグイン。
このプラグインには「システムの設定」でMSBuild.exeのパスを複数設定しておき、「プロジェクトの設定」で任意のパスを選択するという使い方が用意されている。

  • システムの設定
    システムの設定
  • プロジェクトの設定
    プロジェクトの設定

しかしこの機能はスレーブ(というか「Visual StudioがインストールされているWindows」以外のマスター)の存在を考慮にいれていないらしく、マスターにMSBuild.exeがないとビルドに失敗する。

FATAL: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe doesn't exist
Finished: FAILURE

また、このプラグインはビルドに渡したパラメータを勝手にMSBuildのコマンドライン引数に付け加えるため、このようなパラメータを渡すとエラーになる。

target=Clean;Build
[workspace] $ cmd.exe /C MSBuild.exe /p:Configuration=Release /t:%target% -P:target=Clean;Build hoge.sln && exit %%ERRORLEVEL%%
Microsoft(R) Build Engine Version 2.0.50727.3053
[Microsoft .NET Framework, Version 2.0.50727.3603]
Copyright (C) Microsoft Corporation 2005. All rights reserved.

MSBUILD : エラー MSB1006: プロパティが無効です。
スイッチ: Build

結局、単にビルドしたいだけならこのプラグインは使わず、ノードごとに環境変数でパスを通して「Windowsバッチコマンドの実行」で

MSBuild.exe /p:Configuration=Release /t:%target% hoge.sln

こう書いた方が扱いやすい。

C++のキャスト演算子私的使用頻度順位

タグ: C++
  1. static_cast

    言うまでもなく。

  2. reinterpret_cast

    アライメントを揃えた構造体のポインタとchar*を相互変換しながらバイト単位のバイナリ操作を行う時に使う。
    それ以外の用途で使うことはない。

  3. const_cast

    @synchronizedでひっついたvolatileを解除する等、苦し紛れに使うことが多い。
    Boost.Serializationなどはconstの付け外しを前提として設計されているので、このキャストを割と積極的に使うことになる。

  4. dynamic_cast

    そもそもRTTIを使わない。

疑わしきを警告するならその根拠を示せ

タグ: C++ VS2005

Visual Studio Team Editionのコード分析はそこそこ役に立つ機能ではあるが、一部APIにいい加減?な注釈が付いているため、意味の分からない警告を出すことがある。

#include <windows.h>

void hoge()
{
    if (HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4, 0))
    {
        if (void* p = MapViewOfFile(h, FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, 0))
        {
            memset(p, 0, 4);

上記コードでmemset()までたどり着くのは「4バイトのファイルマッピングオブジェクトを生成・マッピングできた」場合のみ。
それなのに、VS2005TEのコード分析は以下のような警告を出す。

(9) : warning C6386: バッファ オーバーランです: '引数 1' へアクセスしています。書き込み可能なサイズは '1*0' バイトですが、'4' バイトを書き込む可能性があります: Lines: 5, 7, 9

なぜ「書き込み可能なサイズは '1*0' バイト」と判定されているのか。
それはMapViewOfFile()の戻り値型「LPVOID」に「_out」の注釈が付いているからだ。

WINBASEAPI
__out
LPVOID
WINAPI
MapViewOfFile(
    __in HANDLE hFileMappingObject,
    __in DWORD dwDesiredAccess,
    __in DWORD dwFileOffsetHigh,
    __in DWORD dwFileOffsetLow,
    __in SIZE_T dwNumberOfBytesToMap
    );

サイズの指定のない「_out」注釈はバッファの長さが1要素分であることを示す。
戻り値型「LPVOID」の要素型は「void」なので、バッファの長さは「1*sizeof(void) = 1*0(便宜上)」バイトということになる。

void *  __cdecl memset(__out_bcount_full_opt(_Size) void * _Dst, __in int _Val, __in size_t _Size);

それに対しmemset()の第1引数_Dstは「NULL以外のポインタを渡されたら(_opt)そのポインタが指す_Sizeバイトのバッファ(_bcount)全体を初期化する(_full)出力属性の引数(_out)」とある。
この2つの注釈を合わせて解釈すると、先の9行目のmemset()呼び出しは「4バイト初期化することを明言している引数に、バッファサイズが0バイトにしかならないMapViewOfFile()の戻り値なんかを渡している」ということになるので、コード分析が警告を出したのである。

このコード分析の判断自体に問題はない。
問題なのは「MapViewOfFile()の戻り値にこの_out注釈を付けている」こと。あるいは「サイズ指定なし=_ecount(1)」という仕様。そしてなによりC6386の解説を読んでも警告されている理由が分からないことである。

配置newとrealloc

タグ: C++ VS2005

mallocで確保し、配置newした領域をreallocして良いか否か。
具体的にコードで示すと

#include <iostream>

class Foo
{
public:
    Foo()
    {
        // 構築時のthisを覚えておく
        _this = this;
    }
    
    bool IamI() const
    {
        // 構築時と同じ記憶域に配置されているか
        return this == _this;
    }
    
private:
    Foo(const Foo&);
    Foo& operator=(const Foo&);

    const Foo* _this;    
};

bool bar()
{
    // Fooオブジェクト2個分のメモリを確保
    Foo* foos = static_cast<Foo*>(malloc(sizeof(Foo) * 2));
    if (! foos)
    {
        return false;
    }

    // 確保したメモリにFooオブジェクトを配置new
    for (int i = 0; i < 2; i++)
    {
        new (foos + i) Foo;
    }

    // Fooオブジェクト1000個分のメモリを再確保
    if (Foo* foos2 = static_cast<Foo*>(realloc(foos, sizeof(Foo) * 1000)))
    {
        foos = foos2;
    }
    else
    {
        for (int i = 0; i < 2; i++)
        {
            foos[i].~Foo();
        }
        free(foos);
        return false;
    }

    // 先頭2個を除いた残りを配置new
    for (int i = 2; i < 1000; i++)
    {
        new (foos + i) Foo;
    }

    // 先頭2個のthisが変化していることを確認
    for(int i = 0; i < 4; i++)
    {
        std::cout << i << ':' << foos[i].IamI() << std::endl;
    }

    // デストラクタを呼び出して解放
    for(int i = 0; i < 1000; i++)
    {
        foos[i].~Foo();
    }
    free(foos);

    return true;
}
0:0
1:0
2:1
3:1

こういった「オブジェクトの記憶域の再配置」は規格で認められているのか否か。
規格書をざっと読んだ限りでは「ダメ」という記述は見当たらないが……オブジェクトが生存している間(=デストラクタが呼ばれていない間)に記憶域を変えるのはなんとなく危険な気がする。

と思ったらVS2005のATL::CArrayはバイト単位のnewと配置newを使ってまさにこんな感じの実装をしていた。
うーん、となるとむしろ「オブジェクトが生成されてから破壊されるまでthisはずっと同じ値を指している」という固定観念を取っ払った方が幸せだろうか。

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。