cpp

gypでdebugとrelease設定を分ける
gypでdebugとrelease設定を分ける gypでvc2010向けのプロジェクトが生成できたので、 実用に向けて設定のテンプレート的なものを準備する。 ビルドオートメーションツールGYPを使おう https://code.google.com/p/gyp/source/browse/trunk/test/win/linker-flags/pdb-output.gyp?spec=svn1832&r=1832 を参考に設定を追加。 Debug, Release設定の追加 main.cpp projects.gyp common.gypi > gyp projects.gyp --depth . とりあえずDebugでステップ実行できた。 こりゃ、よく使うパターンの雛形を揃えるまでは苦しいですな。 premake4, cmakeもそうだった。

python製のビルドツールgypを使ってみる
python製のビルドツールgypを使ってみる gyp(Generate Your Projects) は、 pythonで記述されたプロジェクト生成ツールで設定からVC向けプロジェクトや、GCC向けMakefileを生成するツールである。 chromeやnode.jsのビルドツールとして採用されているそうな。 機能的にはpremake4やcmakeと同じ範囲をカバーするがそれぞれ以下のような問題があった。 premake4はわりと気に入っているのだが布教困難。luaで宣言的に記述するのが分かりづらい cmakeはcmake語が解読不能でちょっとしたプロジェクトのカスタマイズが困難すぎる(OpenCVとかのことだ) そこで、python製のgypを試してみた。 gyp導入 環境は、Windows7 + python3。 > python setup.py install : 中略 : SyntaxError: invalid syntax File "c:\python33\lib\site-packages\gyp-0.1-py3.3.egg\gyp\generator\ninja.py", line 475 print "Warning: Actions/rules writing object files don't work with " \ ^ SyntaxError: invalid syntax File "c:\python33\lib\site-packages\gyp-0.1-py3.3.egg\gyp\generator\xcode.py", line 126 except OSError, e: ^ SyntaxError: invalid syntax python3非対応だった。まぁpython2で。 とりあえずc++の”hello world”をビルドするところから hello_gyp + main.cpp + projects.gyp main.cpp projects.gyp

pythonによるビルドスクリプトwafを使い始めた
pythonによるビルドスクリプトwafを使い始めた pythonによるビルドシステムwafを使ってみた。 使ってみた感触ではvcとgcc両方でビルドするとかそういうのに向いていそうなので、要するにわしのニーズに合っているように思える。 https://code.google.com/p/waf/ 前から気にはなっていたのだけれどどうにも取っ付きが悪くて使えるところまでたどりつけていなかったのだが、やっと最初の一歩を踏み出すことができたのでメモを残す。 早速実践から行く。 +hello/ +hello.cpp hello.cpp #include <iostream> int main(int argc, char **argv) { std::cout << "hello waf !" << std::endl; return 0; } というプロジェクトを作ったとする。 https://code.google.com/p/waf/downloads/detail?name=waf-1.7.13 からwaf(python scriptの圧縮されたもの)をダウンロードしてwscriptを記述する。 +hello/ +hello.cpp +waf +wscript wscriptは以下のようにする。 APPNAME='hello' VERSION='1.0.0' def configure(conf): conf.env['MSVC_TARGETS'] = ['x86'] conf.load('msvc') conf.env.CXXFLAGS = ['/nologo', '/EHsc'] def build(bld): bld.program( source='hello.cpp', target=APPNAME ) 初回とwscriptのconfigureを修正する度にconfigureする。 > python waf configure Setting top to : C:\work\_waf\hello Setting out to : C:\work\_waf\hello\build Checking for program CL : C:\Program Files (x86)\Microsoft Visual Studio 9.

wafでdebugとreleaseの設定を記述する(variant)
wafでdebugとreleaseの設定を記述する(variant) wafでdebug版とrelease版の出力を分けるにはvariantなる機能を使う。 +hello +hello.cpp +waf +wscript と前回と同様のプロジェクト。 wscriptを以下のように記述する。 # coding: utf-8 APPNAME='hello' VERSION='1.0.0' def configure(conf): # config 'debug'を作る conf.setenv('debug') # debugの設定 conf.env['MSVC_TARGETS'] = ['x86'] conf.load('msvc') conf.env.CXXFLAGS = ['/nologo', '/EHsc'] # PDBやNDEBUG等の設定をきっちり書く必要がある # config 'release'を作る。debugの設定は引き継がない conf.setenv('release') # releaseの設定 conf.env['MSVC_TARGETS'] = ['x86'] conf.load('msvc') conf.env.CXXFLAGS = ['/nologo', '/EHsc'] # BuildContextの設定 def build(bld): bld.program( source='hello.cpp', target=APPNAME ) from waflib.Build import BuildContext # BuildContextを使うコマンド class BuildDebug(BuildContext): # config 'debug' を使うvariant # 出力ディレクトリがbuild/debugに変わる variant = "debug" # 呼び出しコマンドはbuild_debug cmd = "build_debug" # BuildContextを使うコマンド class BuildRelease(BuildContext): # config 'release' を使うvariant # 出力ディレクトリがbuild/releaseに変わる variant = "release" # 呼び出しコマンドはbuild_release cmd = "build_release" variantという概念を使う。 http://docs.

右辺値の理解
右辺値の理解 そろそろ右辺値を抑えておきたい気がしたのでテストコードを書きながら実験してみた(VC2010 Express Edition)。 http://msdn.microsoft.com/ja-jp/library/vstudio/dd293665.aspx を参考に右辺値実験クラスRightKunを書いた。 コピーコンストラクタと同じくシグニチャは決まったものがあって 右辺値代入演算のオーバーロードとペアになるらしい。 各関数の呼び出しでメッセージを表示するように仕込んだ。 https://gist.github.com/ousttrue/7178535 #include <memory> #include <iostream> class RightKun { public: RightKun() { std::cout << this << ":default constructor" << std::endl; }; ~RightKun() { std::cout << this << ":destructor" << std::endl; } // 左辺値によるコピーコンストラクタ RightKun(const RightKun &src) { std::cout << this << ":copy constructor: "; *this=src; } RightKun &operator=(const RightKun &src) { std::cout << "left value operator= " << &src << std::endl; return *this; } // 右辺値によるムーブコンストラクタ RightKun(RightKun &&src) { std::cout << this << ":move constructor: "; *this=std::move(src); } RightKun &operator=(RightKun &&src) { std::cout << "right value operator= " << &src << std::endl; return *this; } }; とりあえず使ってみる { // default RightKun r1; // copy RightKun r2=r1; } 結果

msgpack-rpc-asioの関数登録と実行
msgpack-rpc-asioの関数登録と実行 msgpack-rpcのリクエストは、によると [type, msgid, method, params] という形式なのでmethod名をstd::stringとしてparamsをstd::tupleとして得られる。 これをサーバ側で如何に呼び出すかについて。 単純な実装だと以下のようにメソッド名をキーにして分岐することになる。 ```c++ int and(int, int); class dispatcher { void dispatch(int msgid, const std::string &method, const msgpack::object &params) { if(method==“add”){ // 引数展開 std::tuple t; params.convert(&t); // 関数実行 int result=add(std::get<0>(t), std::get<1>(t)); // 結果のパッキング // response [type, msgid, error, result] msgpack::sbuffer response; msgpack::packer<msgpack::sbuffer> pk(&response); pk.pack_array(4) pk.pack(1); pk.pack(msgid); pk.pack_nil(); pk.pack(result); // responseを送り返す } else{ throw “unknown func”; } } 引数展開、関数呼び出し、結果のパッキングと一連の操作を定型処理として括りだすと下記のように書ける。c++ // 2引数展開用 class dispatcher { // 実行 void dispatcher::dispatch(int msgid, const std::string &method, const msgpack::object &params) { if(method==“add”){ msgpack::sbuffer response=unpack_exec_pack(msgid, add, params);

可変長テンプレート引数
可変長テンプレート引数 引き続きmsgpack-rpc-asioを実装しているのだが、可変長テンプレート引数(valiadic template)を使うと関数登録のような場合にうまく書けることがわかった。 昨日は関数オブジェクトからstd::functionの型を得るのに下記のようにしていたのだけど、 ```c++ // ret template Ret helper0(Ret (F::*)(Rest…)); template Ret helper0(Ret (F::*)(Rest…) const); // 1 template A1 helper1(Ret (F::*)(A1, Rest…)); template A1 helper1(Ret (F::*)(A1, Rest…) const); // 2 template A2 helper2(Ret (F::*)(A1, A2, Rest…)); template A2 helper2(Ret (F::*)(A1, A2, Rest…) const); template void add_handler(F handler, const std::string &method) { typedef decltype(handler) functor; typedef decltype(helper0(&functor::operator())) R; typedef decltype(helper1(&functor::operator())) A1; typedef decltype(helper2(&functor::operator())) A2; // register function... std::function<R(A1, A2)> func(handler); } 次のように書けた。c++ template void add_handler(F handler, R(C::*)(A1, A2)const) { // register function… std::function func(handler); }

lambdaの引数の型を得たい
lambdaの引数の型を得たい msgpack-rpcの関数登録の都合上、 lambda関数から引数の型を得たい。 下記のような書き方をしたい。 ```c++ template void register_func(const std::stiring &func_name, R(*handler)(A1, A2)) { // 関数登録 } int main() { // errorになる register_func(“add”, [](int%20a,%20int%20b)->int{ return a+b; }); return 0; } ``` 上記の書き方では普通の関数ポインタを受けることはできるのだが、 std::functionとlambdaは受けられない。 std::functionを受けるには下記のようにすることでできた。 c++ template<typename R, typename A1, typename A2> void register_func(const std::string &func_name, std::function<R(A1, A2) handler) { // } 残り、lambdaを受けられる記述方法を知りたいのだがどうしたらよいものか。 下記のような手はうまくいかなかった・・・ c++ template<typename F, typename R, typename A1, typename A2> void add_handler(F handler, const std::string &method) { std::function<R(A1, A2)> f(handler); //add_handler }

msgpack-rpcのasio版を作成中
msgpack-rpcのasio版を作成中 連休から始めていたmsgpack-rpcのバックエンドをasioに置き換えてWindowsでも動くようにする試みがやっと目処が立った。 [https://github.com/ousttrue/msgpack-asiorpc\](https://github.com/ousttrue/msgpack-asiorpc) 改め https://github.com/ousttrue/msgpack-rpc-asio 当初はmsgpack-rpcのバックエンドのmpioにasioのkernelを追加することで乗り切ろうとしたのだが、わりとすぐに頓挫した。 mpioのファイルディスクリプタでIOを管理するAPIがasioと合わないのですな。 次に、msgpack-rpcのmp::wavy::loopをasioをラップしたクラスで置き換える作戦で 進めていたのだがだいぶ改造して構造が見えてきたところで、asioとの設計の違いをラップするのがめんどくさく なってまた頓挫した。 http://dev.activebasic.com/egtra/2011/10/27/449/ を見ると簡単そうに見えるのだが功夫が足らないようだ。 で、上記の反省を踏まえてasioでmsgpack-rpcを自由に実装することにした。 バイナリデータとmsgpack-rpcの変換部分にmsgpack-rpcのコードを借用して、 ネットワーク通信部分はasioで普通に作成した。 だいたいこんな感じのAPIになる予定。 ```c++ #include #include static int server_method(int a, int b) { return a+b; } int main(int argc, char **argv) { int port=18080; // server boost::io_service server_io; msgpack::asiorpc::server s(server_io); s.add_handler(&server_method, "add"); s.start(boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)); boost::thread server_thread([&server_io](){ server_io.run(); } // client boost::io_service client_io; msgpack::asiorpc::session c(server_io); c.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port); boost::thread client_thread([&client_io](){ client_io.run(); } // request auto request=c.call("add", 3, 4); // blocking int result; request.

long型のサイズ
long型のサイズ x86_64ではlong型のサイズが8byteな事を知った。