2014年11月14日金曜日

proxygenビルド

今話題のproxygenをビルドしてみました。

ちなみに、proxygenってのは、たとえばSourceForgeの記事によれば
米Facebookは11月5日、C++向けのHTTPライブラリ「Proxygen」を発表した。サーバーやクライアント向けコードが含まれており、HTTPを利用したC++プログラムのやりとりを改善し、HTTPを利用するアプリケーションの構築を容易にするという。
Proxygenは、HTTPライブラリとシンプルなWebサーバーを組み合わせたソフトウェアフレームワークで、Facebook社内においてHTTPサーバーやプロキシ、クライアントなどを構築する際に利用されている。Proxygenの公開の目的として、高性能なHTTPサービスの開発と実装を支援するとしている。サーバーとクライアントコードを含み、既存のアプリケーションと容易に統合できる高性能のHTTPフレームワークを目指しているという。
という、素敵なサムシング なわけです。GitHubで公開されているソースコードをざっと見たところ、綺麗な構造で、期待が高まります。

で、ビルドです。基本的にhttps://github.com/facebook/proxygenに書いてあるのに従えばOK。ubuntu環境を用意するところから始めました。"Support for Mac OSX is incomplete."とか書いてありますけど、依存するfollyやらfbthriftやらをどうやって用意するんだ、という問題があるので、まあ、現時点ではちと難しいんではないでしょうか(homebrewでfolly入れてみなよ、みたいなことがGoogle Groupの方で書かれていましたが…)。

1. OSインストール編

1-1. まず、VMware Fusion 6でインスタンスを作りました。ubuntu 64ビット用テンプレートを使って 、ディスク20GB、メモリ2560MB(2.5GB)、1 CPU(古いiMacなもんで)でセットアップ。なお、メモリは最低2GB必要とのこと。
1-2. http://www.ubuntu.com/download/desktop からubuntu 14.04.01 desktopのisoファイルをダウンロード。14.04.xxだったら何でもいいんじゃないでしょうかね。
1-3. ダウンロードしてきたisoファイルをVMゲストの光学ドライブに接続して起動。言われるがままにインストール。OSのアップデート、再起動など勧められるがままに従う。

2. ubuntu上での準備編

$ sudo apt-get install git
$ mkdir git && cd git
$ git clone https://github.com/facebook/proxygen.git

3. ライブラリビルド編

$ cd proxygen
$ export SRC_HEAD=`pwd`   ##これ、後で使う。
$ cd proxygen
$ ./deps.sh

4. サンプルサーバビルド編

$ cd httpserver/samples/echo
$ g++ -std=c++11 -o my_echo EchoServer.cpp EchoHandler.cpp -lproxygenhttpserver -lfolly -lglog -lgflags -pthread -I$SRC_HEAD -I$SRC_HEAD/proxygen/fbthrift/thrift/folly -I$SRC_HEAD/proxygen/fbthrift -L$SRC_HEAD/proxygen/httpserver/.libs -L$SRC_HEAD/proxygen/fbthrift/thrift/folly/folly/.libs

## https://github.com/facebook/proxygenに書いてあるまんま(g++ -std=c++11 -o my_echo EchoServer.cpp EchoHandler.cpp -lproxygenhttpserver -lfolly -lglog -lgflags -pthread)だとエラーが出るので、-Iと-Lを指定。

5. サンプルサーバ動作確認編

$ sudo apt-get install curl
$ curl -v http://localhost:11000/
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 11000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:11000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Request-Number: 1
< Date: Fri, 14 Nov 2014 13:13:31 GMT
< Connection: keep-alive
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

以上。何も戸惑う箇所はありません。ライブラリのビルドに時間がかかるものの、手間もかかりません。

そして、気になるHTTP/2。
Proxygen: Facebook's C++ HTTP LibrariesThis project comprises the core C++ HTTP abstractions used at Facebook. Internally, it is used as the basis for building many HTTP servers, proxies, and clients. This release focuses on the common HTTP abstractions and our simple HTTPServer framework. Future releases will provide simple client APIs as well. The framework supports HTTP/1.1, SPDY/3, and SPDY/3.1. HTTP/2 support is in progress. The goal is to provide a simple, performant, and modern C++ HTTP library.
FacebookがHTTP/2対応版を出してくるのを 待つか(それって、でも、来年2月とかになるのかな)、独自にSPDY用のコードをごにょごにょしてHTTP/2対応させてみるか…。はてさて。

2014年11月8日土曜日

SKProductsRequestでハマった。抜け出したけど。

前回に引き続き、iOSアプリの開発ネタです。初めてっていうのは、いろいろな問題にぶち当たりますな。

原因不明でアプリがクラッシュすることが何度かあり、どうやら、アプリ内課金の関係で、Appleのサーバに問い合わせに行っている最中に、「遅い!もういいよ!」みたいな感じで画面遷移(具体的には、ナビゲーションの「戻る」を押す)をしてしまうと、ごく稀にこの問題が発生する、ということまで絞り込むことができた。
ごく稀にというのが、まあ、厄介なところ。

ちなみに、アプリがクラッシュした時のXcode(ちなみにバージョンは6.1)の表示はこんな感じ。

コードがこれ↓


スタックがこれ↓


これだけだと、さっぱり、意味がわからない。

"Enqueued from com.apple.root.default-qos"と"EXC_BAD_ACCESS"とかでググっても、なかなかこれというのが見つからないし、なんと言っても、"Enqueued from com.apple.root.default-qos"と"SKProductsRequest"の組み合わせで検索結果がゼロというのに参った。
SKProductsRequestのstartメソッド呼ばない限りクラッシュしないので、この関係だってことは間違い無いと思うんだけど…。

そして、結局、自分で、何が原因なのかわかりました。ので、情報共有です。

こんなコードを書いていたんですよ。どこかで見たコードのコピペですけど。
- (void)startRequest
{
    SKProductsRequest* productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
    productRequest.delegate = self;
    [productRequest start];
}
これだと、サーバからのレスポンスを受け取った時に、selfがdeallocateされてしまった後だと、まずいことになるんですよね。productRequestの後始末が考慮されていない。

というわけで、僕が採った解決法はこれ。
まず、ヘッダファイルでこんな宣言。
@property (nonatomic, strong) SKProductsRequest *productRequest;
そして、本体コードでは、
- (void)startRequest
{
    _productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
    _productRequest.delegate = self;
    [_productRequest start];
}


これに加えて、viewWillDisappearで、delegateを無効化してやる処理を加えました。
- (void)viewWillDisappear:(BOOL)animated { _productRequest.delegate = nil; [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; }


そしたら、(今のところ?)ばっちり、っぽいです。なんか自信なさげな書き方で恐縮ですが。いかんせん、稀にしか起こらない問題なので断言が難しいのです。

iOSアプリでの各国語対応。なるほど、そうだったのか。

久しぶりにブログ書きます。
ちなみに、会社で、仕事の一環として、時々英語でブログ書かされたりしてるんですが、なんていうか、仕事で書くのって気が重いですね。ま、それはさておき。

実は、内緒にしていましたが、ここ最近、iOSアプリを作ってたんです。初めての。
それで、一応、大した手間じゃないので、各国語対応させてみよう、と、ということで、ベース言語(実際は英語で記述)、それに加えて日本語用の文字列ファイルを用意しました。

今まで、「iPhoneの使用言語」として日本語と英語を設定してそれぞれでの表示を試してみては、ふむふむ、うまくいっておるわい、と思っていたのですが、先ほど、iPhoneの使用言語をイタリア語に設定してみると、期待に反してなんと日本語の文字列が表示されてしまうではないですか。
うーむ、何か間違った設定をしているのだろうかと軽くググってみたけれども、うまく期待する答えにたどり着けない。

結局、自分で原因がわかって全て丸く収まりました。
こういうことです。↓

設定言語を、英語⇒日本語⇒イタリア語、という順で変更すると、「使用する言語の優先順位」(設定アプリの「一般>言語と地域」の中にある)が

  1. イタリア語
  2. 日本語
  3. 英語

となってしまうんですね。自動で。

この状況で、アプリがイタリア語にローカライズされていないからアプリのベース言語(つまり英語)が選ばれるかと予想していたのですが、そうではなく、英語よりも高い優先度で日本語を使う設定に(iOSの判断によって)なっているので、日本語が表示される、と。そういうことでした。
つまり、「iPhoneの使用言語」よりも「使用する言語の優先順位」のほうが意味がある、と。

ここで、仮に、日本語(と英語の両方)が「使用する言語の優先順位」に含まれていない場合、ベース言語(つまり英語)が表示されるんでしょうね。
試してみたいのですが、「使用する言語の優先順位」は手動で編集できないので、残念です。

ところで15年ぐらい前はローカライズを"l10n"、国際化を"i18n"とか表記してたんですけど、これって今の若い人にも通じるんでしょうかね。逆に、今では別の表記をしているなら、それを知りたい。
ちなみに由来は
"localization"⇒"lxxxxxxxxxxn"(LとNの間に10文字)⇒"l10n"
"internationalization"⇒"ixxxxxxxxxxxxxxxxxxn"(IとNの間に18文字)⇒"i18n"
なので、表記が"l10n"や"i18n"であっても、「えるじゅーえぬ」「あいじゅーはちえぬ」などと読むことはなく、よみがなとしてはやはり「ろーからいぜーしょん」「いんたーなしょならいぜーしょん」でした。少なくとも僕の周辺では。

2014年3月12日水曜日

VMwareが重すぎるのでなんとかしたメモ


これまでVMware Fusion 6 + Windows 8の上で動作させていたMeta Trader 4が、(Mavericksインストール以降)もう、とにかく遅すぎて苦痛だったのでなんとかしました。同じお悩みを抱えた方の参考になれば、と思い情報を共有します。

といっても、先人により提供された有用な情報がweb上のあちこちにありますので、付加情報を中心に。

まず、Meta Trader 4をVMwareなしで(しかも無料で)マック上で動かす方法はこれ。

  1. 最新のXQuartzをインストール。僕がインストールしたのはv2.7.5。超簡単。説明不要。
  2. 最新のPlayOnMacをインストール。僕がインストールしたのはv4.2.2。超簡単。説明不要。
  3. MT4をインストール。Windowsでインストールしたことがあれば迷うこと無し。インストール後に言語設定をEnglishにしておくのが吉。
  4. THVをインストール。あ、必要なければインストール不要ですけど。MT4のディストリビューションによっては、インストールされたファイルを再配置する必要あり。その場合、ターミナルでゴニョゴニョする必要があるので、ターミナルの扱いになれていない人には勧められません。 
すみません。簡単すぎて、全然説明する必要なかった。

で、とりあえずうまく動作するようになった後の話。…ここから先が少しは新鮮な情報かも。

最初にインストールした(マックの)アカウントとは別のアカウントでもMT4 on PlayOnMacを使いたい場合にどうするか。つまり、同じMT4環境を妻にも使わせたいが、自分のマックのアカウントのパスワードを教えたくはない、というような場合。

こういう場合、THVをインストールしたり、いろいろ独自の設定を加えて使いやすくした環境を、まるごとコピーしてしまえばよいのです。

まず、PlayOnMac自体を、インストールしたユーザ以外のアカウントからも使えるようにする。他のバージョンではどうなっているか知らないけれど、v4.2.2の場合は、これをしないとPlayOnMacが起動に失敗する。

$ chmod -R a+rx /Applications/PlayOnMac.app/Contents/Frameworks/Python.framework

僕の場合これだけでうまくいったけど、それでもうまく行かない場合は、コマンドラインからPlayOnMacを起動(↓)してやると、エラーメッセージなんかが読めて問題解決が期待できる。かも。

$ cd /Applications/PlayOnMac.app/Contents/MacOS
$ ./playonmac



で、いよいよ、MT4環境を他のアカウント用にもコピーする方法。
ここでは、自分のアカウントがuserA、追加するアカウントがuserBと仮定。userBは制限付きアカウントでOK。
ちなみに、それぞれのマックアカウントでMT4を起動して同時に同じMT4アカウントを使用しても問題なさそうです(責任はとれませんが)。

userAアカウントでは全てのセットアップが完了していて、PlayOnMacのMT4のための仮想ドライブのパスは

/Users/userA/Library/PlayOnMac/wineprefix/vDriveForMT4

であると仮定して話を進めます。

別のアカウントでログインして、PlayOnMacを起動してMT4をインストールする。仮想ドライブのパスは

/Users/userB/Library/PlayOnMac/wineprefix/vDriveForMT4

にした、と仮定。

そこまで済んだら、それぞれのMT4 on PlayOnMacを終了させておく。

ここから先は、ターミナルでの操作。繰り返しますが、ターミナルでの操作に自信のない人にはおすすめしません。というか、僕は責任とれないので、全て自己責任でどうぞ。

あ、そうそう、ここではFXCMのMT4を使っているので、他社の提供するMT4の場合はパスおよびディレクトリ名を実際のものに置き換えて考える必要があるでしょうね、もちろん。

PlayOnMacの仮想ドライブ内のMT4フォルダを/tmpにコピーしてパーミションを変更。

userA $ cd ~
userA $ cd "Library/PlayOnMac/wineprefix/vDriveForMT4/drive_c/Program Files"
userA $ cp -r "FXCM MetaTrader 4" /tmp/
userA $ chmod -R a+rx "/tmp/FXCM MetaTrader 4"


userBのPlayOnMacの仮想ドライブ内のMT4フォルダをバックアップ(名前変更)した上で、/tmp以下からMT4ディレクトリをコピーしてくる。

userB $ cd ~
userB $ cd "Library/PlayOnMac/wineprefix/vDriveForMT4/drive_c/Program Files"
userB $ mv "FXCM MetaTrader 4" "_FXCM MetaTrader 4_"
userB $ cp -r "/tmp/FXCM MetaTrader 4" ./


ここまでできたら起動確認。

うまくいったら、バックアップしておいたフォルダを削除

userA $ rm -rf "/tmp/FXCM MetaTrader 4"
userB $ cd ~

userB $ cd "Library/PlayOnMac/wineprefix/vDriveForMT4/drive_c/Program Files"
userB $ rm -rf "_FXCM MetaTrader 4_"


ところで、我が家では、MT4をMacBookAirで動作させておき、それをiMac(ちょっと古くて性能はへぼいが画面は大きくて快適)からリモート操作する、という運用をしている。初代アルミiMacでOSX Mavericks + VMware Fusion 6 + Windows 8 + MT4 + THVは動作が重すぎて、どうしようもなくなってしまったのだ。

ついでなので、この運用についても情報共有を。

Apple Remote Desktopという、素敵な、しかし現時点で7800円もする、Apple謹製のソフトがあるわけだけど…。高いよ!

というわけで、VNCという枯れた技術を使うことにします。

MacBookAir側でVNCサーバの設定:「システム環境設定>共有」で「リモートマネジメント」にチェックを入れ、「コンピュータ設定…」内のチェックボックスを3つともチェックし、パスワードを設定しておく。アクセスを許可するユーザを限定するのが、まあ、普通はよいでしょう。

iMac側でVNCクライアントの設定:Chicken ( http://sourceforge.net/projects/chicken/ )をインストールする。設定は難しくないのでそれ以上は省略。ちなみに、僕はここ数年JollysFastVNC (Home edition)という有償VNCクライアントを使っていたのだけれど、JollysFastではOSXの提供するVNCには接続ができなかった。どういうわけか。

以上です。説明上、MacBookAirだiMacだと書いていますが、機種は関係ないです。Mavericks(あるいは最近のOSX)が入ったマック同士が同じサブネットにつながっていれば同じことができるはず。