メモ

プログラムを書いているときに詰まった部分などを備忘録的に書いていきます。

FASTBuild事始め

FASTBuildとはVisualC++で使えるIncrediBuild、distccのようなフリー(というかオープンソース)の分散ビルドツールです。
VisualStudioのプロジェクトも作成できるのでCMakeにも近いかも。 そんなFASTBuildですが日本語で解説しているページを見かけないのでやったことを書いてみることにしました。

FASTBuild自体を以下のページから落としてきます。
FASTBuild - High-Performance Build System
中にFBuild.exeとFBuildWorker.exeにLICENSE.TXTが入っています。
FBuild.exe、FBuildWorker.exeをパスの通るところにおいてください。

こいつでBuildするには定義ファイルを書かないといけないので分散ビルドの前に単純なビルドができるようなシンプルな定義ファイルを書きます。
ちなみに64ビットでの例なので32ビットでやりたい場合はコンパイラのパスを適宜修正してください。
またVCのパスは適宜自分の環境にあったものにしてください。

.VCBasePath = 'C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC'
.Compiler          = "$VCBasePath$\bin\amd64\cl.exe"
.Librarian         = "$VCBasePath$\bin\amd64\lib.exe"
.Linker            = "$VCBasePath$\bin\amd64\link.exe"

; ソースフォルダ、ファイルをここで指定
ObjectList( "hallo_obj" )
{
  .CompilerOptions = '%1 /Fo%2 /nologo /c'
  .CompilerInputPath = "src\"
  .CompilerOutputPath= "obj\"
}

; 実行ファイル定義
Executable( "hallo" )
{
  .LinkerOptions = '/NOLOGO /OUT:%2 %1 /MACHINE:x64 /SUBSYSTEM:CONSOLE'
  .Libraries = { "hallo_obj" }
  .LinkerOutput = "bin/hallo.exe"
}

; 引数省略時に実行される処理
Alias( "all" )
{
  .Targets = { "hallo" }
}

事前にsrcフォルダ、objフォルダが入っているフォルダを用意します。
そこに上記の内容をテキストファイルに書き、fbuild.bffとして保存します。
srcフォルダにはコンパイルしたいソースを入れてください。
以下のような感じです。
・作業フォルダ(自分で作成)
  ┣ srcフォルダ(この中にソースを入れる)
  ┣ objフォルダ
  ┗ fbuild.bffファイル
コマンドプロンプトを開き、上記の作業フォルダに移動

"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" x64 

と入力してください(ダブルクォーテーション含む)
次に

fbuild 

と打ち込むことでビルドが始まります。

注意点として、FASTBuildのSampleを見てみるとLibrary( 'libA' )を使ってますが
これだとlibA.libができてさらにそれをリンクした実行バイナリができてしまいます。
単純な実行バイナリを作りたい場合は上記のObjectListを使います。

UltraVNCでrdr::Exception: rdr::EndOfStreamが出る。

UltraVNCを使用しているとうまくつながらない時があるのでlogを取ってみると
rdr::Exception: rdr::EndOfStream
とのエラーメッセージが出てました。
これを調べても、どうにも解決につながる情報が出てこなかったのですがこの前ようやく上記の症状がでなくなりました。

何をやったかというと、UltraVNCのバージョンをサーバ、クライアント共に最新に更新しただけです。
これだけで結構長期間苦しめられたこの問題があっさり直ってしまいました。 多分サーバ、クライアントのバージョンが合ってなかったのが良くなかったのかと。

困ったときは最新版にしよう、と思った出来事でした。

isnanとisinfが2つ定義されている件

gccでは実はisnanとisinf関数は

と、2つ定義がある。

using std::isinf;
using std::isnan;

上記コードはコンパイルエラーとなる場合があり その場合は以下の記述で回避することができる。

#ifndef __GXX_EXPERIMENTAL_CXX0X__
using std::isinf;
using std::isnan;
#endif

Singletonでのthread終了時にjoinで固まる

VisualStudio環境での話です(VS2012で確認)
gcc(4.9.2)環境では正常に動作します。

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

class Hoge
{
public:

    static Hoge& get()
    {
        static Hoge hoge;
        return hoge;
    };

    void run()
    {
        while( false == m_end )
        {
            sleep(100);
        }
    }

    void stop()
    {
        m_end = true;
    }

    static void sleep(unsigned int ms)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(ms));
    }

private:

    Hoge()
        : m_thread()
        , m_end(false)
    {
        m_thread = std::thread( &Hoge::run, this );
    }

    virtual ~Hoge()
    {
        stop();
        if ( m_thread.joinable() )
        {
            m_thread.join();
        }
        std::cout << "thread end" << std::endl;
    }

    Hoge(const Hoge& rhs);
    Hoge& operator=(const Hoge& rhs);

    std::thread         m_thread;
    std::atomic<bool>    m_end;
};

int main()
{
    Hoge::get();
    Hoge::sleep(100);
    return 0;
}

上記のコードを実行すると終了時に固まります。
何が起こっているかというと多分以下の通り
・mainが終了
Hogeのデストラクタで動かしている子供スレッドの終了指示
・joinで子供スレッドが終わるのを待つ
・run関数自体は終わるが_Cnd_do_Broadcast_at_thread_exitでメインスレッドの終了待ちをしている?
・結果joinとメインスレッド終了待ちでデッドロック
いまのところ、とりあえずjoinをdetachに変えてしのいでます。

     if ( m_thread.joinable() )
        {
#if 0
           m_thread.join();
#else
            m_thread.detach();
#endif
        }

ちなみに_Cnd_do_Broadcast_at_thread_exitを通るのを確認するために
ランタイムライブラリのオプションを/MTdにしてます。