2009年10月21日

boost condition

boostでスレッド間の同期をとる便利クラスconditionを使おうとすると次のエラーで怒られた。

error: `condition' does not name a type

同じソースコードで、ある環境だと問題がないのに別の環境だと怒られる。
#include <boost/thread.hpp>
をしてるのになぁ。

と思ったらboost 1.36からconditionはincludeが変更になったようだorz
持ってるboostの本は1.35準拠なので情報が古いorz
#include <boost/thread/condition.hpp>

マジで1時間ぐらい無駄にした。

2009年04月10日

log4cxx

JavaではロギングにLog4Jを使用している。

現在、Linux上でC++を使用してアプリを書いているが、同じようにリッチな情報でロギングしたい。
と言うことで、同じapacheのLog4cxxを使用する。Log4cppではファイルの行番号などを一緒にログに出すことができないっぽいのでLog4cxxに。

Log4cxxセットアップメモ。

Log4cxxから落とす。
./configure --prefix=hoga
すると次のエラーが。APRが無いと怒られる。
checking for APR... no
configure: error: APR could not be located. Please use the --with-apr option.

仕方ないので入れる。
wget http://www.meisei-u.ac.jp/mirror/apache/dist/apr/apr-1.3.3.tar.gz

./configure --prefix=hoga
make
make install

そしてlog4cxxのconfigure。するとまた怒られる。今度はapr-utilが無いと言われる。
checking for APR-util... configure: error: --with-apr-util requires a directory or file to be provided

仕方ないので入れる。
wget http://www.meisei-u.ac.jp/mirror/apache/dist/apr/apr-util-1.3.4.tar.gz

./configure --prefix=hoga --with-apr=hoga
make && make install
Libraries have been installed in:
hoga

入ったようだ。

今度こそLog4cxxをconfigure。
./configure --prefix=hoga --with-charset=utf-8 --with-logchar=utf-8
make && make install

入った。


では使う。
export LD_LIBRARY_PATH=hoga
LD_LIBRARY_PATHを設定しないと以下のエラーメッセージ。
./a.out: error while loading shared libraries: liblog4cxx.so.10: cannot\
open shared object file: No such file or directory

コンパイル時にもちゃんと教えてあげる。
g++ -I/hoga/include/ -L/hoga/lib -llog4cxx test.cpp

#include <log4cxx/logger.h>
#include <log4cxx/propertyconfigurator.h>

using namespace log4cxx;

LoggerPtr logger = Logger::getLogger("TestCategory" );

int main( int argc , char** args ){
 PropertyConfigurator::configure("test.properties");
 LOG4CXX_DEBUG( logger , "test " << 10 <<"px");
 return 0;
}


以下読み込む設定ファイル。元はLog4cxxと小物ツールから拾ってきた。
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1} %l - %m%n

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=test.log
log4j.appender.file.Apppend=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p %c{1} %l - %m%n

log4j.rootLogger=debug, stdout, file
log4j.debug=false

結果は次のような感じ。
2009-04-10 15:43:15,457 DEBUG TestCategory test.cpp(12) - test 10px

Log4cxxのconfigure時に--with-charset=utf-8 --with-logchar=utf-8を付けないと日本語が文字化けする。

2009年03月05日

gdbメモ segmentation fault編

Linux上でC++でプログラムを作成すると、segmentation faultで落ちてしまうことがある。
Javaと違い、スタックトレースをデフォルトで表示しないため、どこで落ちたのかわかりにくい。

で、そんなときはgdbの出番というわけだ。
gdbは取っつきにくく、デバッグするたびにgdbに関する情報を検索するのでは効率が悪いのでメモに残しておく。

まず実行ファイルにデバッグ情報を付与するためコンパイルオプションを設定。
最適化はO2ぐらいにしとくのが良いらしい。
-O2 -ggdb

そしてgdbから実行。
$ gdb ./exefile

デバッグ対象ファイルの実行はrコマンドで実行。
引数を与える場合は以下のような感じで。
(gdb) r arg1 arg2

こけたらソースコードの位置を教えてくれる。

いちいちgdbから実行するのはめんどくさいよ!と言う人はcoreファイルを使う。
segmentation fault時にcoreを吐かない場合はcoreファイルサイズの最大値に達している可能性がある。
まずcoreファイルサイズの設定。以下みたいな感じでサイズ無制限に。
$ limit coredumpsize unlimited

coreが無事に吐かれたらそれをgdbに食わせる。
$ gdb ./exefile core.1234

するとどのファイルの何行目で落ちたかが表示される。

スタックトレースを表示させる場合はwhereコマンドを使用する。
(gdb) where
するとスタックトレースが表示される。

行番号とか表示されない場合はデバッグ情報が実行ファイルに存在しない可能性がある。

gdbマニュアル日本語版
http://www.asahi-net.or.jp/~wg5k-ickw/html/online/gdb-5.0/gdb-ja_toc.html

それのPDF版
http://www.asahi-net.or.jp/~wg5k-ickw/pdf/gdb/gdb-5.0-pdf-020110.tar.gz

PDF版のマニュアル300ページもありやがるぜ・・・。

2007年07月26日

Log4cxx続き

昨日のAssertionで失敗していたところのコードを見てみたらsedを起動しようとして失敗していたようだ。
と言う事でcygwinをPATHに追加したら成功。ただ、別の箇所でも3箇所ほどテストに失敗していた。

とりあえずbuildしてdllを作成して、includeファイル設定して#pragma comment(lib, "log4cxxd.lib")とかしてDLLを追加したら無事ロギングできるようになった。
ただ、VC++のプロジェクトのプロパティで、「構成プロパティ」-「C/C++」-「ランタイムライブラリ」を「マルチスレッド デバッグ DLL (/MDd)」にしなければコンパイルでエラーになった。
1>libcpmtd.lib(xdebug.obj) : error LNK2019: 未解決の外部シンボル __malloc_dbg が関数 "void * __cdecl operator new(unsigned int,struct std::_DebugHeapTag_t const &,char *,int)" (??2@YAPAXIABU_DebugHeapTag_t@std@@PADH@Z) で参照されました。
1>libcpmtd.lib(xdebug.obj) : error LNK2019: 未解決の外部シンボル __free_dbg が関数 "void __cdecl operator delete(void *,struct std::_DebugHeapTag_t const &,char *,int)" (??3@YAXPAXABU_DebugHeapTag_t@std@@PADH@Z) で参照されました。
1>libcpmtd.lib(stdthrow.obj) : error LNK2019: 未解決の外部シンボル __CrtDbgReportW が関数 "void __cdecl std::_Debug_message(wchar_t const *,wchar_t const *,unsigned int)" (?_Debug_message@std@@YAXPB_W0I@Z) で参照されました。
な感じのエラー。

イマイチVC++がわかっていないのでこのオプションの変更で具体的にどういう変化がありこのエラーが出ているのかはわからない。
とりあえず俺の愛するログ出力ができるようになったので、C++での開発も楽になるだろう。
Javaと違い、ソースコード上の何行目で吐いたログか表示できないようだ・・・と思ったらできた。
 logger->info("てすと");
などのようにするとどのファイルの何行目かと言うのは記録されないが、
 LOG4CXX_INFO(logger, "Entering application.");
のように書くとどのファイルの何行目かが記録される。
たとえば以下のように出る。
 2007-07-26 00:51:48,621 INFO Client(c:\users\長いので省略\test.cpp:40) - Entering application.
見たいな感じで。
Javaだとファイル名だけ出るけどC++版はフルパスで出るんだな。おしり20文字分とかしないと長くなる。

うむ。なんだかモチベーションがあがってきたぞ!

2007年07月24日

Log4cxx

プログラミング時にデバッグ方法はいろいろあるけど、その中でログ出力は一番シンプルかつ重要な方法だ。
バグを追いかけるときに役立つし、その動作の状態がファイルと言う後に残る形式で出力されるからだ。
JavaだとLog4jを使って高機能なロギング機能を使うことができるがC++では・・・。

Log4jをC++に移植したLog4cxxがあるが、なんとググっても日本語での情報が80件しかない。
ふ~む、C++では高機能なロギングは必要とされていないのか?
確かにJavaだとサーバサイドのアプリケーションが多く、そういうアプリケーションにとってはロギングは最重要な関心事だ。致命的なエラー時のログはsyslogに出して担当者にログをメールで送信したり、ログファイルを1日おきとか10Mbyteごとにローテーションしたり。一番重宝するのが"どのファイル"の"何行目"で"どのロギングレベル"でログを出力したかがわかることだ。
C++だとクライアントプログラムが多いからそういう高機能なロギングは必要ないのだろうか。

C++でも「今はこのモジュール開発中だからこのモジュールだけデバッグレベルのログ出力でその他はエラーレベルのログ出力」とかしたいと思うんだけどなぁ。ifdefでデバッグ出力のオンオフは低機能すぎるだろうし、コンパイル時にしかログ出力の設定ができない。

と言う事でとりあえずLog4cxxを使うと言う方向で進めよう。
環境はWindows VistaのVisual Studio 2005 C++

Log4xxの入手は公式サイトで。
ただし、ここにおいてある"最新版"の0.9.7は古すぎる。
CVSリポジトリにある開発版は0.9.7からずいぶん変わっているようだ。0.9.7を使わず、Subversionから最新のソースを取得し、コンパイルする。

コンパイルはビルドツールのantを使う。C++なのにMakefileはもう使わないんだな。Java以外のビルドもantに変わってきているようだ。
INSTALLファイルを参考に、「cpptasks.jar and ant-contrib.jar on CLASSPATH」と「The following files placed in the lib directory: apr-1.2.2.tar.gz apr-util-1.2.2.tar.gz cppunit-1.10.2.gz」をそれぞれダウンロードして指示のとおりにする。

Microsoft Visual C++の場合以下のようにしろと書いてあった。

$> set CLASSPATH=path_to_cpptasks/cpptasks.jar;path_to_antcontrib/ant-contrib.jar
$> path_to_vc\bin\vcvars32
$> ant

1行目のset CLASSPATH=云々はANT_HOMEのlib以下にjarをコピーしたので不要だった。
2行目は最初無視したが、これは無視したらダメで2行目を実行しなかったらコンパイラが不正な処理か何かで強制終了してしまう。
VC++のbin/vcvars32.bat を実行することでコンパイラの環境設定が行われるらしい。vcvars32.batを実行することでLog4jはコンパイルできた。

が、コンパイル後の自動単体テストでAssertion failedになってしまうw
application's support teamにコンタクトを取れと言われるが・・・。

以下のアサーションで失敗している。
Assertion failed: stat == APR_SUCCESS

APRとはApache Portable Runtimeで、WikipediaによるとOSとソフトウェアの間でOSなどの環境の違いを吸収するAPIを提供するとのこと。一応Log4cxxのdllはできているけどAPRのライブラリの使用で落ちているってコトはダメそうな悪寒。

ふいぃ、ロギング環境の構築で今日はギブアップ。もう寝る。

2006年01月13日

Linuxでのファイル権限などの取得

Javaでファイラを作っているがJavaからはLinuxのファイル権限を取得できない。
ファイラでそのあたりの情報を見れないのはちょっと寂しい。

そこでCでLinuxのファイル権限を取得するライブラリを作り、JNIからネイティブなライブラリを呼んで目的の処理を実行する。

とりあえずファイル権限の取得の仕方。
取得にはstatを使う。

Cはもうほとんど忘れているのでトライアンドエラーでとりあえず取得まではできた。
笑われるようなコードかもしれないが気にしない。

これをJNIで使えばJavaからもLinuxのファイル権限が取得できる。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(){
  char *fileName;
  fileName = "FileTest.c";
  struct stat *s ;
  struct stat a;
  s = &a;
  stat( fileName , s );

  if( s->st_mode & 00400 ){
    printf("R_USER\n");
  }
  if( s->st_mode & 00200 ){
    printf("W_USER\n");
  }
  if( s->st_mode & 00100 ){
    printf("X_USER\n");
  }

  if( s->st_mode & 00040 ){
    printf("R_GRP\n");
  }
  if( s->st_mode & 00020 ){
    printf("W_GRP\n");
  }
  if( s->st_mode & 00010 ){
    printf("X_GRP\n");
  }

  if( s->st_mode & 00004 ){
    printf("R_OTH\n");
  }
  if( s->st_mode & 00002 ){
    printf("W_OTH\n");
  }
  if( s->st_mode & 00001 ){
    printf("X_OTH\n");
  }
}

2005年07月11日

DirectX

ちょっとオンラインゲームを作成したくなった。
本格的なモノじゃなくて技術的なテストのために。

Java信者な俺はもちろんJavaで開発をしようと思ったんだけどオンラインゲームで必要な「ゲーム内での日本語変換処理」をJavaで実現できなかった。(Swingでゲーム作るなら可能だったけど)
一応SDLでそれを実現するのはあったのでSDLJavaを使いつつJNI経由でそのライブラリをいじればできるかもしれないけどそこまで根性はなかった・・。

と言っても仕方ないのでDirectXで作成することに。
DirectXのサンプルを見るとDirectXなGUIが使えるフレームワークでちゃんとIMEが使用できるコンポーネントがあった。
さすがDirectX。
このGUIもなかなかかっちょいい。

しかしJavaの命名規則になれるとC++のはソースが読みにくいなぁ。
まぁ慣れだろうからしばらくすると気にならなくなるだろうけど。

DirectXをちょっといじるとなんか使い勝手の悪い部分がある。
特に画面のフルスクリーンを切り替えるといちいちデバイスが消失するからオブジェクトをそのたびにリセットしないとダメな部分が・・・。
一部はDirectXが管理してくれるけど管理してくれない部分は自分で実装しないといけない。
この辺は何とかならないんかな。

画面の描画もなんかめんどくさいのでその辺を簡単にできるスプライト&スプライト管理ライブラリみたいなのから作り始めるか。
SWTで言うImageRegistryみたいな感じで。
C++いじるのは学生時代ぶりなので激しく忘れているのが不安だけど・・・。

・・・なんか肝心のネット部分にたどり着く前に飽きてしまいそうだ。

C++その他のエントリー