mozcのかな入力で、はまった。
実際は、mozcの問題というよりもキーボード設定の問題だと思うんだけど、入力できない文字があって困った。
例えば、自分の場合、macbookからvncを通して、Ubuntu12.04のmozcでかな入力しようとするとどうしても小さい「ゃ」が打てなくて大きい「や」になってしまう。「ゅ」「ょ」はOKなのにである。
ちなみにシングルクォーテーションはちゃんと入力できる。
{むむぅ。随分、微妙な症状だなぁ・・・}
もちろん、ぐぐっても微妙すぎて解決法どころか同じ症状すら出てこない。
キーボードの設定を調べたが、すぐにわからなかったのと、
・ ディストリとかが違うとどうせ設定も違う。
・ vncを通すので問題がややこしい。
・ macからもwindowsからも操作したりするのでややこしい。
ので、
{追いかけるのも面倒だぞ、これは。}
と思い、頭に来たので、禁断の
ローマ字テーブル「かな」化作戦!!
を決行することにした。ダメ作戦と思いきや、意外に快適になったので、ローマ字テーブルをmozc設定画面からexportしたファイルをリンクしておきます。
そのままmozc設定画面からimportして使用できます。
使用時に注意するところは、
・ aを叩くと「ち」ではなく「a」と表示されるが変換するとちゃんと「ち」で変換できるので気にしないこと。(他のキーも同様)
・ 「0」のshiftは登録できないので、「を」を出すのは「ほ」のshiftになっている。
・ 自分の環境だと漢字入力モードでも、¥キーだけ押すと直接¥になってしまったので、「ー」は、shift+¥になっている。
・ 「」をshiftなし、『』をshift付きで出したいのだが「む」とバッティングするので、「」とセットで打ち込んだ時に「」が表示されるようになっている。
くらいかなー。
これを元に、好きにカスタマイズするといいかもしれません。
この方法で結構良かったのは、キーボードの微妙なカスタマイズが、ローマ字変換テーブルの調整でできちゃうところで、自分の環境にあわせて作れます。
また、ローマ字変換テーブルには、かなり複雑な入力パターンも登録できるので、IMEのカスタマイズとしても変な使い方が出来そうです。
2013年11月21日木曜日
2013年10月24日木曜日
[c++11] finallyみたいなことしたいけど、専用のRAIIクラス作るの嫌なんだけど・・・
c++には、javaみたいなfinallyがないんだけど、あーゆーの欲しいなーとおもって調べてみると、結局、
・ RAII用のクラス作れよ
・ boost/scope_exit使えよ
ということのようだ、前者はそれ用のクラス毎回作るのもなんだかなーだし、後者はちょっとぐじゃぐじゃしてて嫌だった。
頭に来たので、RAII用にshared_ptrを流用することにしたので、以下にメモっておく。
あ、c++11必須ね。
注意点は、FINALLYを解放したいリソースの宣言と例外が出る可能性のある場所の「間」に入れるところです。
こう見ると、shared_ptrのカスタムデリーターって、いろんなことに流用できそうですね。ちゃんとカウント取ってるからそこの一部のスコープだけに限らず使えるし。
後処理という発想だけでなく、なんかのトリガー的なことに使うと面白そう。
・ RAII用のクラス作れよ
・ boost/scope_exit使えよ
ということのようだ、前者はそれ用のクラス毎回作るのもなんだかなーだし、後者はちょっとぐじゃぐじゃしてて嫌だった。
頭に来たので、RAII用にshared_ptrを流用することにしたので、以下にメモっておく。
あ、c++11必須ね。
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
using namespace std;
#define FINALLY(CLAUSE) shared_ptr<void> f_i_n_a_l_l_y(nullptr, [&](void*){CLAUSE});
class SomeResource {
public:
void open() {cout << "some resource open." << endl;}
void close() {cout << "some resource close." << endl;}
};
int main() {
try {
SomeResource res;
FINALLY(
res.close();
)
res.open();
cout << "before throw exception." << endl;
throw runtime_error("xxx error.");
cout << "end of try block." << endl;
} catch (runtime_error &e) {
cout << "Error: " << e.what() << endl;
}
cout << "out of try block." << endl;
}
実行した結果は、
some resource open. before throw exception. some resource close. Error: xxx error. out of try block.マクロ使って少し見やすくしました。
注意点は、FINALLYを解放したいリソースの宣言と例外が出る可能性のある場所の「間」に入れるところです。
こう見ると、shared_ptrのカスタムデリーターって、いろんなことに流用できそうですね。ちゃんとカウント取ってるからそこの一部のスコープだけに限らず使えるし。
後処理という発想だけでなく、なんかのトリガー的なことに使うと面白そう。
2013年9月12日木曜日
scalaで調子に乗ってfuture{でスレッド量産してたらはまった
注・この記事は、scala2.10を使用しています。
scalaで、
import ExecutionContext.Implicits.global
とfuture使ってて、
「あれ? futureで作った別スレッドの処理がなんか始まらないことがあるんだけど・・・」
ということがある人のための記事です。
scala使ってて便利なのにスレッドを超簡単に作れるってのがあるんだけど、
ただ単に、future{やると、エラーが出るんで、いろんなサイトのサンプル(こことかこことかここ。みんな良サイト) を参考に、先にimportしてscalaが持ってるデフォルトのExecutionContextであるExecutionContext.Implicits.global を利用するようにしてた。
ところが、調子に乗ってメインのスレッドでやりたくないことをfuture{でがんがん切り離して処理したんだけど、そのプログラムをコア数1のマシンで動かそうとしたら動かない。コア数2のマシンで動かしたらなんか動くけど、プログラムがよく固まる。
固まった状態ではほとんどCPUは食っていない。
ちなみに自分の開発マシンは、4core&ハイパースレッドで8スレッドだったのでその現象は出なかった。
{うげー、マルチスレッド周りの問題は追いかけにくくて嫌だなー・・・}
と思ったのだが、printlnとか入れてみるとどうやら処理がfutureの中身に来ていないようだ。
仕方ないのでサンプルを書いて自機(8スレマシン)で実験してみた。
sleepしたからって、次のthreadを処理してくれる訳じゃなく御丁寧にsleepが終わるまで次のスレッドを処理しないで待ってるではないか!
で、どうやらこの同時に動けるfutureの数がマシンのコア数によって変るので、コア数の少ないマシンで自分のプログラムを動かしてた時にfutureで切り離したthreadが実行されなかった模様。
何か他のやり方ないかな、と探していたら、spawnというものがあるようなのでこんなふうに変えてみたら
仕方ないのでもう少し調べてみると、ちゃんと理解せずに使っていた、
import ExecutionContext.Implicits.global
が元のスレッドの動作を制御していたようで、こいつを変更する必要があった。 しかし、ここで活躍するのが何とjavaのスレッド管理機能であるExecutorsってやつだった。(わかりやすい解説)
で、変更したコードがこれ
Executor辺りのことは、上で紹介したサイトにも書いてあったのだが、そこを読んだときは、ExecutionContext.Implicits.globalで動くんだからいいじゃん。とちゃんと理解してなかった。
ちなみにPlayFrameworkとかいじっててakkaが使える状態のときは、javaのExecutorsを呼ばずに
scalaで、
import ExecutionContext.Implicits.global
とfuture使ってて、
「あれ? futureで作った別スレッドの処理がなんか始まらないことがあるんだけど・・・」
ということがある人のための記事です。
scala使ってて便利なのにスレッドを超簡単に作れるってのがあるんだけど、
import ExecutionContext.Implicits.global // どこか上の方でimport
future {
・ なんかいろいろ
・ なんかいろいろ
}
こんな感じね。ただ単に、future{やると、エラーが出るんで、いろんなサイトのサンプル(こことかこことかここ。みんな良サイト) を参考に、先にimportしてscalaが持ってるデフォルトのExecutionContextであるExecutionContext.Implicits.global を利用するようにしてた。
ところが、調子に乗ってメインのスレッドでやりたくないことをfuture{でがんがん切り離して処理したんだけど、そのプログラムをコア数1のマシンで動かそうとしたら動かない。コア数2のマシンで動かしたらなんか動くけど、プログラムがよく固まる。
固まった状態ではほとんどCPUは食っていない。
ちなみに自分の開発マシンは、4core&ハイパースレッドで8スレッドだったのでその現象は出なかった。
{うげー、マルチスレッド周りの問題は追いかけにくくて嫌だなー・・・}
と思ったのだが、printlnとか入れてみるとどうやら処理がfutureの中身に来ていないようだ。
仕方ないのでサンプルを書いて自機(8スレマシン)で実験してみた。
import scala.concurrent._
import ExecutionContext.Implicits.global
object ThreadSample {
def main(args: Array[String]) {
val startTime = System.currentTimeMillis()
for (idx <- 1 to 24) {
future {
println(f"idx = $idx%2d, time = ${System.currentTimeMillis() - startTime}%4d ms")
Thread.sleep(1000)
}
}
Thread.sleep(3000)
println(s"end of main. ${System.currentTimeMillis() - startTime} ms")
}
}
実行結果
idx = 1, time = 73 ms idx = 3, time = 73 ms idx = 8, time = 73 ms idx = 2, time = 73 ms idx = 7, time = 73 ms idx = 4, time = 73 ms idx = 5, time = 73 ms idx = 6, time = 73 ms idx = 13, time = 1099 ms idx = 16, time = 1099 ms idx = 15, time = 1099 ms idx = 10, time = 1099 ms idx = 9, time = 1099 ms idx = 14, time = 1099 ms idx = 11, time = 1099 ms idx = 12, time = 1099 ms idx = 21, time = 2100 ms idx = 23, time = 2100 ms idx = 20, time = 2100 ms idx = 19, time = 2100 ms idx = 18, time = 2100 ms idx = 17, time = 2100 ms idx = 22, time = 2100 ms idx = 24, time = 2100 ms end of main. 3074 ms{なんじゃこりゃ、8個ずつしか動いてないじゃん。}
sleepしたからって、次のthreadを処理してくれる訳じゃなく御丁寧にsleepが終わるまで次のスレッドを処理しないで待ってるではないか!
で、どうやらこの同時に動けるfutureの数がマシンのコア数によって変るので、コア数の少ないマシンで自分のプログラムを動かしてた時にfutureで切り離したthreadが実行されなかった模様。
何か他のやり方ないかな、と探していたら、spawnというものがあるようなのでこんなふうに変えてみたら
import scala.concurrent._
import scala.concurrent.ops.spawn
object ThreadSample {
def main(args: Array[String]) {
val startTime = System.currentTimeMillis()
for (idx <- 1 to 24) {
spawn {
println(f"idx = $idx%2d, time = ${System.currentTimeMillis() - startTime}%4d ms")
Thread.sleep(1000)
}
}
Thread.sleep(3000)
println(s"end of main. ${System.currentTimeMillis() - startTime} ms")
}
}
実行結果
idx = 16, time = 56 ms idx = 23, time = 57 ms idx = 7, time = 55 ms idx = 8, time = 55 ms idx = 21, time = 56 ms idx = 12, time = 56 ms idx = 14, time = 56 ms idx = 5, time = 55 ms idx = 15, time = 56 ms idx = 20, time = 56 ms idx = 19, time = 56 ms idx = 11, time = 56 ms idx = 3, time = 55 ms idx = 13, time = 56 ms idx = 2, time = 55 ms idx = 10, time = 55 ms idx = 1, time = 55 ms idx = 17, time = 56 ms idx = 4, time = 55 ms idx = 18, time = 56 ms idx = 24, time = 57 ms idx = 9, time = 55 ms idx = 22, time = 57 ms idx = 6, time = 55 ms end of main. 3058 ms欲しかった結果になった。しかしコンパイル時に、こんな警告が出た。
[warn] /Users/xxx.scala:97: object ops in package concurrent is deprecated: Use `Future` instead.
[warn] spawn {
[warn] ^
{なにー、future使えだとー!?}
仕方ないのでもう少し調べてみると、ちゃんと理解せずに使っていた、
import ExecutionContext.Implicits.global
が元のスレッドの動作を制御していたようで、こいつを変更する必要があった。 しかし、ここで活躍するのが何とjavaのスレッド管理機能であるExecutorsってやつだった。(わかりやすい解説)
で、変更したコードがこれ
import scala.concurrent._
import java.util.concurrent.Executors
object ThreadSample {
def main(args: Array[String]) {
val startTime = System.currentTimeMillis()
val pool = Executors.newCachedThreadPool()
implicit val execctx = ExecutionContext.fromExecutorService(pool)
for (idx <- 1 to 24) {
future {
println(f"idx = $idx%2d, time = ${System.currentTimeMillis() - startTime}%4d ms")
Thread.sleep(1000)
}
}
Thread.sleep(3000)
println(s"end of main. ${System.currentTimeMillis() - startTime} ms")
}
}
実行結果
idx = 18, time = 60 ms idx = 6, time = 59 ms idx = 5, time = 59 ms idx = 2, time = 59 ms idx = 10, time = 59 ms idx = 13, time = 60 ms idx = 11, time = 60 ms idx = 7, time = 59 ms idx = 8, time = 59 ms idx = 9, time = 59 ms idx = 4, time = 59 ms idx = 3, time = 59 ms idx = 17, time = 60 ms idx = 19, time = 60 ms idx = 15, time = 60 ms idx = 21, time = 60 ms idx = 22, time = 61 ms idx = 12, time = 60 ms idx = 16, time = 60 ms idx = 24, time = 61 ms idx = 23, time = 61 ms idx = 20, time = 60 ms idx = 1, time = 59 ms idx = 14, time = 60 ms end of main. 3062 msで、うまくいった。
Executor辺りのことは、上で紹介したサイトにも書いてあったのだが、そこを読んだときは、ExecutionContext.Implicits.globalで動くんだからいいじゃん。とちゃんと理解してなかった。
ちなみにPlayFrameworkとかいじっててakkaが使える状態のときは、javaのExecutorsを呼ばずに
val system = ActorSystem("xxxxx")
import system.dispatcher
future {
・ なんかいろいろ
・ なんかいろいろ
}
で、ActorSystemのdispatcherをインポートしてあげれば、ExecutionContext.Implicits.globalを使わないでいい感じになった。
2013年7月18日木曜日
mac版 gnucash日本語入力への道 (gtkimcocoa使用)
この記事の情報は古くなっています。
2013/7当時は、普通にダウンロードしたgnucashでは、日本語入力できませんでしたが、2014/12現在の版(Ver. 2.6.5)では、何も考えずに普通に日本語入力できました。
(OSX Yosemite 10.10.1使用。OSX標準とgoogleの日本語入力で確認。)
最近macを使いだしたので、gnucashをmacにも入れて、どのマシンからでもgnucashからdropboxに置いたデータを更新できたら便利だなと思って、公式のmac用バイナリをインストールしてみた。
いろいろ調べてみると、
だ、そうだ。おいおい。
そんな状況なのだが、gtk+にパッチを当てて、日本語入力できるようにした人もいるらしい。
それをやってみようとも思ったが、後でgtk+のバージョンが上がったときに、もしパッチが当てられなくなったら手も足も出なくなりそうなのでパッチは嫌だなーと二の足を踏んでいたら、gtk+にパッチを当てなくても、偉い人がgtkimcocoaというgtk+のアドイン?を作っていて、これを使うと日本語入力できるらしいことを発見。
それを利用して、なんとか日本語入力できるところまで行ったので、後でもう一回出来るように記録を残します。
ただ、かなりややこしかったので、このページに検索で迷い込んできた人は、以下の俺のスペックを参考にやってみるか決めてください。
・ macを使い始めたばかりで、mac特有の仕組み等は全然わからない。
・ GTK+の仕組みについては全く知らない。
・ もちろん、GTK+の日本語入力の仕組みも知らない。
・ ソースをダウンロードしてビルドしてインストールとかは、変なオプションを駆使したりしないケースならできる。(./configure; make; make install; 位で勘弁してくれるeasyなケースね)
・ configureやmakeの途中でエラーで止まったりしたときは、エラーを見て足らないファイルをどこかから探して持ってくる位は出来ることが多い。
・ configureでエラーが出た時に、configure.acとかconfigure.inをいじってみたりすると、失敗することの方が多い。← configureについてちゃんと理解してない。
スペックを見て、こいつに出来るなら大丈夫そうだな等の参考にしてください。
ただ、なんのことやらわからない人は、手を出さない方がいいでしょう。
☆出会ったトラブルと対処
・ libffiのインストール時に、必要なダウンロードサイトがダウン(?)していてエラーで止まったが、エラー後のメニューで[4]を選択しjhbuildのシェルに入って、失敗したcurlコマンドのURLをググって他のサイトに変更しダウンロードする。ダウンロード後、そのshellでexitすると、先ほどのエラーメニューに戻るので[1]を選択すると次のステージに進む。
・ gettextのインストール(たぶん)で、autopointコマンドのエラーで止まったが、[4]shellから
autopoint --force
で切り抜ける。参考URL:http://lists.sourceforge.jp/mailman/archives/scim-imengine-dev/2007-March.txt
またexit→[1] で続行。
・ どこかで、configureの無限ループに落ち入るが、いっぺんctrl+cで強制終了して、もう一度
$ ~/.local/bin/jhbuild build meta-gtk-osx-core
の実行でなぜか切り抜ける。
gtkimcocoaが正しくインストールされていると、バイナリ配布のGTK+使用アプリでも日本語入力可になるはずらしいのだが、この時点でバイナリ配布のgnucashを動かしても日本語入力がされなかった。
バイナリ配布のgnucashが32bitコンパイルされているのが原因かもしれない。ここで、GTK+を32bitでコンパイルして試すか、gnucashを64bitでコンパイルするかの選択を迫られるが、前者の方が大変そうな予感がするので、gnucashのコンパイルに賭けることにした。
◎ gnucash-unstableのビルド・インストール
☆出会ったトラブルと対処
・ 何度も
AM_CONFIG_HEADER を使うな AC_CONFIG_HEADER を使え!というエラーに遭遇して止まるので、その度に[4]shellからconfigure.acまたはconfigure.inのAM_CONFIG_HEADERをAC_CONFIG_HEADERに変更する。
・ gmpのconfigureで、OS or マシンのarchitecture の認識がうまくいかなくて止まる。オプションでarchitectureを指定してもconfigureは通るがmakeで止まるので、gmpのコンパイルをあきらめる。
gmpは、brew install gmp でインストールしてskip連打で次に進んだ。
本来ここで入るgmpとバージョンも結構違うのでどうかと思ったが、後でこれが問題になることはなく最後まで行った。
・ どこかで、configureの無限ループに落ち入るが、いっぺんctrl+cで強制終了して、もう一度
$ ~/.local/bin/jhbuild build
の実行でなぜか切り抜ける。
・ ビルド中に何度かエラーで止まって冷や汗をかくが、なぜかいっぺんctrl+cで強制終了して、また
$ ~/.local/bin/jhbuild build
の再実行で、止まらずに次に行けるという現象と数回遭遇する。
◎ gnucashの環境でもgtkimcocoaをインストール
◎ GnuCashで日本語入力確認
日本語入力できることを確認した。
うへー、結構長い道のりだった。
証拠写真は、これ。
ただし、まだ日本語入力周りが原因で落ちることがあるようですので、こまめに記録を取った方がいいでしょう。
2013/7当時は、普通にダウンロードしたgnucashでは、日本語入力できませんでしたが、2014/12現在の版(Ver. 2.6.5)では、何も考えずに普通に日本語入力できました。
(OSX Yosemite 10.10.1使用。OSX標準とgoogleの日本語入力で確認。)
最近macを使いだしたので、gnucashをmacにも入れて、どのマシンからでもgnucashからdropboxに置いたデータを更新できたら便利だなと思って、公式のmac用バイナリをインストールしてみた。
で、レシートそろえて「いざ入力!」と勇んでみたが、なんと日本語の入力が出来ない。
{まじすかーーっ!?}
MacのGnucashでGoogle日本語入力を使えるようにしてくれたら3000円くらいあげたい。
— ma3kik (@ma3kik) March 14, 2012
だ、そうだ。おいおい。
そんな状況なのだが、gtk+にパッチを当てて、日本語入力できるようにした人もいるらしい。
それをやってみようとも思ったが、後でgtk+のバージョンが上がったときに、もしパッチが当てられなくなったら手も足も出なくなりそうなのでパッチは嫌だなーと二の足を踏んでいたら、gtk+にパッチを当てなくても、偉い人がgtkimcocoaというgtk+のアドイン?を作っていて、これを使うと日本語入力できるらしいことを発見。
それを利用して、なんとか日本語入力できるところまで行ったので、後でもう一回出来るように記録を残します。
ただ、かなりややこしかったので、このページに検索で迷い込んできた人は、以下の俺のスペックを参考にやってみるか決めてください。
・ macを使い始めたばかりで、mac特有の仕組み等は全然わからない。
・ GTK+の仕組みについては全く知らない。
・ もちろん、GTK+の日本語入力の仕組みも知らない。
・ ソースをダウンロードしてビルドしてインストールとかは、変なオプションを駆使したりしないケースならできる。(./configure; make; make install; 位で勘弁してくれるeasyなケースね)
・ configureやmakeの途中でエラーで止まったりしたときは、エラーを見て足らないファイルをどこかから探して持ってくる位は出来ることが多い。
・ configureでエラーが出た時に、configure.acとかconfigure.inをいじってみたりすると、失敗することの方が多い。← configureについてちゃんと理解してない。
スペックを見て、こいつに出来るなら大丈夫そうだな等の参考にしてください。
ただ、なんのことやらわからない人は、手を出さない方がいいでしょう。
以下、やった作業をいろいろ書いていきますが、無駄な試行も含めてかなりいろいろやったので、全部は書ききれませんでした。なんとなくな書き方ですみません。(←性格の問題だろ)
また、自分がやった手順なので、無駄な手順も含まれていると思います。
大まかな順序は、
gtk+のビルド・インストール →
gtkimcocoaのビルド・インストール →
gtk-demoで日本語入力確認 →
gnucashのビルド・インストール →
gnucash環境下へのgtkimcocoaのビルド・インストール →
gnucash環境下のgtk-demoで日本語入力確認 →
gnucashで日本語入力確認
注意点: 現時点のgnucashは、ver.2.5.3(Unstable)で、Gtk+-2.24 を使っていますが、今後GTL+3系に移行する予定があるようです。その場合、そのあたりの手順が変更になります。
なお、当方のOSバージョンは、OS X 10.8.4 です。日本語入力には「ことえり」を使用しています。
◎ GTK+のビルド・インストール
GTK+のインストール前にやってだめだったこと。
brew install gtk+
homebrewで、インストールしたgtk+だと、GTK+日本語入力モジュールのgtkimcocoaのコンパイルがうまくいかず挫折した。
いきなり{jhbuildってなんじゃ}とつまづくが、GTK+そのものやGTK+を使用したアプリをbuildする環境らしい。
ホームディレクトリで作業した。 $ curl -s -O https://git.gnome.org/browse/gtk-osx/plain/gtk-osx-build-setup.sh $ sh gtk-osx-build-setup.sh ← これでjhbuildがインストールされる $ ~/.local/bin/jhbuild bootstrap $ ~/.local/bin/jhbuild build meta-gtk-osx-bootstrap $ ~/.local/bin/jhbuild build meta-gtk-osx-core
☆出会ったトラブルと対処
・ libffiのインストール時に、必要なダウンロードサイトがダウン(?)していてエラーで止まったが、エラー後のメニューで[4]を選択しjhbuildのシェルに入って、失敗したcurlコマンドのURLをググって他のサイトに変更しダウンロードする。ダウンロード後、そのshellでexitすると、先ほどのエラーメニューに戻るので[1]を選択すると次のステージに進む。
・ gettextのインストール(たぶん)で、autopointコマンドのエラーで止まったが、[4]shellから
autopoint --force
で切り抜ける。参考URL:http://lists.sourceforge.jp/mailman/archives/scim-imengine-dev/2007-March.txt
またexit→[1] で続行。
・ どこかで、configureの無限ループに落ち入るが、いっぺんctrl+cで強制終了して、もう一度
$ ~/.local/bin/jhbuild build meta-gtk-osx-core
の実行でなぜか切り抜ける。
◎ gtkimcocoaのビルド・インストール
テキトウにgitのsrcを展開するフォルダを作ってcdで移動 $ git clone git://github.com/ashie/gtkimcocoa.git $ cd gtkimcocoa $ ~/.local/bin/jhbuild shell $ ./autogen.sh $ ./configure ← メッセージの最後の方の GTK+2: yes を確認 $ make $ make install◎ gtkimcocoaの設定
$ gtk-query-immodules-2.0 > ~/gtk/inst/etc/gtk-2.0/gtk.immodules $ gtk-demo でデモ起動 OK「Text Widget」→「Hypertext」を開いても日本語入力できた。
gtkimcocoaが正しくインストールされていると、バイナリ配布のGTK+使用アプリでも日本語入力可になるはずらしいのだが、この時点でバイナリ配布のgnucashを動かしても日本語入力がされなかった。
バイナリ配布のgnucashが32bitコンパイルされているのが原因かもしれない。ここで、GTK+を32bitでコンパイルして試すか、gnucashを64bitでコンパイルするかの選択を迫られるが、前者の方が大変そうな予感がするので、gnucashのコンパイルに賭けることにした。
◎ gnucash-unstableのビルド・インストール
$ ホームディレクトリで作業した。 $ ホームディレクトリにある .jhbuildrc-custom をバックアップを取った後 https://raw.github.com/jralls/gnucash-on-osx/master/.jhbuildrc-custom を参考に編集 $ ~/.local/bin/jhbuild bootstrap $ ~/.local/bin/jhbuild build編集した.jhbuildrc-customを参考に置いておきます。(unstableのgnucash用です。)
☆出会ったトラブルと対処
・ 何度も
AM_CONFIG_HEADER を使うな AC_CONFIG_HEADER を使え!というエラーに遭遇して止まるので、その度に[4]shellからconfigure.acまたはconfigure.inのAM_CONFIG_HEADERをAC_CONFIG_HEADERに変更する。
・ gmpのconfigureで、OS or マシンのarchitecture の認識がうまくいかなくて止まる。オプションでarchitectureを指定してもconfigureは通るがmakeで止まるので、gmpのコンパイルをあきらめる。
gmpは、brew install gmp でインストールしてskip連打で次に進んだ。
本来ここで入るgmpとバージョンも結構違うのでどうかと思ったが、後でこれが問題になることはなく最後まで行った。
・ どこかで、configureの無限ループに落ち入るが、いっぺんctrl+cで強制終了して、もう一度
$ ~/.local/bin/jhbuild build
の実行でなぜか切り抜ける。
・ ビルド中に何度かエラーで止まって冷や汗をかくが、なぜかいっぺんctrl+cで強制終了して、また
$ ~/.local/bin/jhbuild build
の再実行で、止まらずに次に行けるという現象と数回遭遇する。
◎ gnucashの環境でもgtkimcocoaをインストール
上でgtkimcocoaをインストールしたときと同じフォルダに移動 $ ~/.local/bin/jhbuild shell $ ./autogen.sh $ ./configure ← メッセージの最後の方の GTK+2: yes を確認 $ make $ make install ← 今度はgnucash-unstableのフォルダの奥にインストールされる◎ gnucashの環境でgtkimcocoaの設定
$ gtk-query-immodules-2.0 > ~/gnucash-unstable/etc/gtk-2.0/gtk.immodules $ ~/gnucash-unstable/bin/gtk-demo でデモ起動 OK「Text Widget」→「Hypertext」を開いても日本語入力できた。
◎ GnuCashで日本語入力確認
$ ~/gnucash-unstable/bin/gnucash-launcher &でgnucash起動。
日本語入力できることを確認した。
うへー、結構長い道のりだった。
証拠写真は、これ。
ただし、まだ日本語入力周りが原因で落ちることがあるようですので、こまめに記録を取った方がいいでしょう。
2013年6月4日火曜日
PlayFramework2.1.1環境で、ScalaからJNAへセットしたコールバックが戻ってこなくなる件
先日の投稿で、scalaからJNAのコールバックを設定するところを
で、なんとなく次のように変えてみる。
ただ、コールバックのセットをし直すと、コールバックがまた返ってくるようになることを発見したので、症状が出る前と後で
c側でコールバックを保持しているのは、ただの関数ポインタなので、これではコールバックは返ってこない。
{これ、どうしてくれようか}
と思ったが、素直に下のようにしてみたら
私は、JVMやscalaのメモリ管理を詳しく知らないので、これで本当にアドレスが固定されるのか確信がないのだが、とりあえず今のところはアドレスが変ってしまうケースはなくなった。
なので、
「scalaからJNAのコールバックをセットする時は、コールバックをvalに入れておく」
をお勧めします。
追記 2013/06/19
後で気が付いたのですが、コールバックオブジェクトを変数に入れておかないと、そのオブジェクトはどこからも参照されていない状態になりGCが動いた時に掃除されてしまうので、コールバックが迷子になる。が正解っぽいです。
コールバックが迷子になるタイミングが不規則だったのは、GCが動くタイミングが不規則だからで、c側でコールバックを保持していてもJVMのメモリとは当然関係ないので、GCに片付けられてしまうということのようです。
object Tekito {
lib.setFunction(idx, new JnaCallback {
def onMessage(msg: String) = println("onMessage " + idx + ": " + msg)
})
}
こんな感じで書いていたんだけど、実際の環境で上の書き方でコールバックをセットした後、しばらくすると不規則なタイミングでコールバックが返ってこなくなるケースが多発して困っていた。で、なんとなく次のように変えてみる。
object Tekito {
def callback = new JnaCallback {
def onMessage(msg: String) = println("onMessage " + idx + ": " + msg)
}
lib.setFunction(idx, callback)
}
これでも状況は変わらず、しばらくするとコールバックが返ってこなくなる。ただ、コールバックのセットをし直すと、コールバックがまた返ってくるようになることを発見したので、症状が出る前と後で
println(Tekito.callback)してみると、
正常時 models.Tekito$$anon$1@5ca99bc コールバックが返ってこなくなった後 models.Tekito$$anon$1@3833089c{ぬおーっ!アドレス変ってるじゃないかー!}
c側でコールバックを保持しているのは、ただの関数ポインタなので、これではコールバックは返ってこない。
{これ、どうしてくれようか}
と思ったが、素直に下のようにしてみたら
object Tekito {
val callback = new JnaCallback {
def onMessage(msg: String) = println("onMessage " + idx + ": " + msg)
}
lib.setFunction(idx, callback)
}
こうしてみたら、Tekito.callbackのアドレスが固定されてコールバックが安定して返ってくるようになった。私は、JVMやscalaのメモリ管理を詳しく知らないので、これで本当にアドレスが固定されるのか確信がないのだが、とりあえず今のところはアドレスが変ってしまうケースはなくなった。
なので、
「scalaからJNAのコールバックをセットする時は、コールバックをvalに入れておく」
をお勧めします。
追記 2013/06/19
後で気が付いたのですが、コールバックオブジェクトを変数に入れておかないと、そのオブジェクトはどこからも参照されていない状態になりGCが動いた時に掃除されてしまうので、コールバックが迷子になる。が正解っぽいです。
コールバックが迷子になるタイミングが不規則だったのは、GCが動くタイミングが不規則だからで、c側でコールバックを保持していてもJVMのメモリとは当然関係ないので、GCに片付けられてしまうということのようです。
2013年5月30日木曜日
PlayFramework2.1.1で動かすakka ActorとWebSocketのサンプル
scala、PlayFramework、akka、WebSocketと初めてづくしで、自分的に、はまりポイント満載だったので、サンプルをあげておきます。
akkaとWebSocketが両方入っていて、サンプルとしては焦点が絞れてないけれど、二つ記事を書くのが面倒なので、そのまんまです。
環境は、PlayFramework2.1.1でscalaもakkaもplayに付属のもの。
まず、初心者がscala、PlayFramework、akkaで一番はまるポイントは、これらは、現在バリバリ進化中の技術なので、ググった情報が古くなってしまっていることが多い、ということ。たった半年前の記事でさえ、古いこともあるので注意が必要です。もちろん、この記事もすぐに古くなりそう。
コードは、PlayのアプリケーションとActorを書いたやつの2ファイル。
・ Playのアプリケーション側
上のコード、importがだらだらとあって省略していないけど、実はここが今回の最重要ポイント。
「webのサンプルと環境が同じはずなのに、コンパイル出来ねぇぜ。大体、こんなメソッドはドキュメントにも載ってないぞ」
とかいうscalaでありがちな状況は、importが足らないのが原因ということが多い。
akkaのActorを使う上で、最初参考にしたのが、
Scalaで並行処理#2 – AkkaのActorを使う
のページで、とてもわかりやすいサンプルと解説の素晴らしい記事。
で、!(投げっぱなし) !!(同期) !!!(非同期)を駆使してやるぞと意気込んでみたものの、!!と!!!のメソッドが見当たらない。
おまけにActor側のself.replyも見当たらない。どうやら仕様変更があった模様。
{まじすか、勘弁してくださいよ先生・・・}
とめげかけるが、akkaの公式ページに解答を発見。(Use With Actorsの項)
どうやら、Actorから、もしくはActorへの通信は、!(返事いらない) と?(返事欲しい)の2種類になったっぽい。たしかにこの表記の方がシンプルでわかりやすい。
前の!!のように、同期で返事を待ちたい場合は、?でもらえるFutureを使って、
Futureの使い方についてとても参考になったのは、
Starlight -Little Programmer’s Diary- Scala 2.10.0 Futures and Promises
のページです。サンプル多くてわかりやすいです。
あと、Actor側のself.replyもsender !になった。
{でも、!ってActorへのメッセージじゃなかったっけ?}
と思ったが、なんと?メソッドが、Actorにメッセージを投げる時に内部で一時的にActorを作ってくれるから、Actorからの戻しも!でいいとのこと。すげー。シンプルだ。
この、scalaとakka開発陣の「仕様変えるな、こら」という声に負けない攻めの姿勢は大好きです。
scalaのことだから、前の書き方でも、たぶん何かimportするだけで動くんだと思う(知らないけど)、これができるのも仕様変更に踏み切れる理由なんだろう。implicit conversion恐るべし。
ただ、上の?メソッドも、ActorRefにも、ScalaActorRefにも見当たらない、これは、コード10行目の import akka.pattern.ask すると使えるようになる。
このimportで、ActorRefがAskableActorRefに、implicit conversionで変身するので?が使用可能になる。これは、確かにわかりにくいが、scalaの拡張性やコードの簡潔さを支えているのが、良くも悪くもimplicit conversionだということがよくわかった。
あと、はまったのが、?メソッドに必要な、隠し変数timeout。scalaには、implicit parameterといって、メソッドに必要な引数を普通に引数として渡すのではなく、周りのコードの引数と同じ型のimplicit宣言された値から取ってくるという、ぶっ飛んだ機能があって、こいつを初めて見たので何のことやらさっぱりわからんかった。
確かにこれなら、せっかく?メソッドが演算子的にかっこ良く書けるのに、timeoutをどう渡すんだよという難問を解決できる。
明示的にtimeoutを渡したい時は、
implicit parameterについては、ひしだまさんのページに書かれた一連のサンプルが非常にわかりやすいです。そのページに限らずひしだまさんのページは、考え抜かれた短いサンプルが大量にあって、scalaを使うには欠かすことができません。scalaの神様です。
で、疲れてきたんだけど、WebSocketにまだ触れてないなこれ。
参考にしたページは、
Auto-Saving ... Done Play Framework 2.1のWebSocketで一対一通信
server側からclientに送信するには、onStartが呼ばれる時にやってくるchannelを使うので、WebSocketがつながっている間は、こいつを大事に取っておきましょう。
client側から何かを受信するたびに、Iteratee.foreach の中に入ってくるので、ここで簡単に受信データを処理できます。
scalaをいじっていて感じたのは、scala開発陣の、いかに簡潔なコードを作成可能な言語にするかという執念じみたものでした。その執念に、これからも期待したいです。
akkaとWebSocketが両方入っていて、サンプルとしては焦点が絞れてないけれど、二つ記事を書くのが面倒なので、そのまんまです。
環境は、PlayFramework2.1.1でscalaもakkaもplayに付属のもの。
まず、初心者がscala、PlayFramework、akkaで一番はまるポイントは、これらは、現在バリバリ進化中の技術なので、ググった情報が古くなってしまっていることが多い、ということ。たった半年前の記事でさえ、古いこともあるので注意が必要です。もちろん、この記事もすぐに古くなりそう。
コードは、PlayのアプリケーションとActorを書いたやつの2ファイル。
・ Playのアプリケーション側
package controllers
import play.api._
import play.api.mvc._
import models._
import play.api.libs.iteratee.Concurrent.Channel
import play.api.libs.concurrent.Akka
import akka.util.Timeout
import akka.actor._
import akka.pattern.ask // ? の使用に必要!!
import scala.concurrent._
import scala.concurrent.duration._ // 5 seconds の表現に必要
import ExecutionContext.Implicits.global // FutureのonSucceessを使うのに便利
import play.api.libs.iteratee._
import play.api.Play.current // Akka.system を使うのに必要
object AppHelloActor extends Controller {
val actor = Akka.system.actorOf(Props[HelloActor], name = "helloactor")
def index = Action {
Ok(views.html.test("test page."))
}
def actorWebSocketsSample() = WebSocket.using[String] {
request =>
def onStart: Channel[String] => Unit = {
channel => // このchannelを取っておくとclientにいろいろ送信できる
println("actorWebSocketsSample unicast onStart")
implicit val timeout = Timeout(5 seconds) // この下の?の隠れ引数のためにここで宣言?! こういう言語は初めてだぜ。
val future = actor ? "world"
//val future = actor ? 3.14159 // 上の行をコメントにして、こっちを生かすとonFailureでtimeoutを取れる
//val future = actor.?("world")(Timeout(5 seconds))
future.onSuccess {
case res: Array[String] =>
res.foreach(value => println("RESULT = " + value))
channel.push(res.mkString(" ")) // clientにメッセージ送信
channel.eofAndEnd()
}
future.onFailure {
case e =>
println("future.onFailure - " + e.getMessage())
channel.eofAndEnd()
}
}
def onError: (String, Input[String]) => Unit = {
(message, input) =>
println("actorWebSocketsSample unicast onError " + message)
}
def onComplete = println("actorWebSocketsSample unicast onComplete")
val enumerator = Concurrent.unicast[String](onStart, onComplete, onError)
val iteratee = Iteratee.foreach[String] {
rcvData =>
// 今回は、上のonStartで処理終了しちゃってるから何もしてないけど、
// ここでWebSocketクライアントから受信したデータを処理する。
} mapDone {_ => println("Disconnected")}
(iteratee, enumerator)
}
}
・ 次は、Actor側package models
import akka.actor.Actor
class HelloActor() extends Actor {
def receive = {
case s: String =>
sender ! Array(s"Hello, $s.", "Bye Bye.")
case _ =>
// timeoutさせたいので、何もしない
}
}
以上でコードはおしまい。以下、解説、はまったポイント等をだらだらと・・・・上のコード、importがだらだらとあって省略していないけど、実はここが今回の最重要ポイント。
「webのサンプルと環境が同じはずなのに、コンパイル出来ねぇぜ。大体、こんなメソッドはドキュメントにも載ってないぞ」
とかいうscalaでありがちな状況は、importが足らないのが原因ということが多い。
akkaのActorを使う上で、最初参考にしたのが、
Scalaで並行処理#2 – AkkaのActorを使う
のページで、とてもわかりやすいサンプルと解説の素晴らしい記事。
で、!(投げっぱなし) !!(同期) !!!(非同期)を駆使してやるぞと意気込んでみたものの、!!と!!!のメソッドが見当たらない。
おまけにActor側のself.replyも見当たらない。どうやら仕様変更があった模様。
{まじすか、勘弁してくださいよ先生・・・}
とめげかけるが、akkaの公式ページに解答を発見。(Use With Actorsの項)
どうやら、Actorから、もしくはActorへの通信は、!(返事いらない) と?(返事欲しい)の2種類になったっぽい。たしかにこの表記の方がシンプルでわかりやすい。
前の!!のように、同期で返事を待ちたい場合は、?でもらえるFutureを使って、
val result = Await.result(future, timeout.duration).asInstanceOf[String]みたいにすれば、結果来るまで待ってられるし、前の!!!のように非同期で結果待ちの時は上のサンプルのように、onSuccessなりonCompleteなり使えばいい。
Futureの使い方についてとても参考になったのは、
Starlight -Little Programmer’s Diary- Scala 2.10.0 Futures and Promises
のページです。サンプル多くてわかりやすいです。
あと、Actor側のself.replyもsender !になった。
{でも、!ってActorへのメッセージじゃなかったっけ?}
と思ったが、なんと?メソッドが、Actorにメッセージを投げる時に内部で一時的にActorを作ってくれるから、Actorからの戻しも!でいいとのこと。すげー。シンプルだ。
この、scalaとakka開発陣の「仕様変えるな、こら」という声に負けない攻めの姿勢は大好きです。
scalaのことだから、前の書き方でも、たぶん何かimportするだけで動くんだと思う(知らないけど)、これができるのも仕様変更に踏み切れる理由なんだろう。implicit conversion恐るべし。
ただ、上の?メソッドも、ActorRefにも、ScalaActorRefにも見当たらない、これは、コード10行目の import akka.pattern.ask すると使えるようになる。
このimportで、ActorRefがAskableActorRefに、implicit conversionで変身するので?が使用可能になる。これは、確かにわかりにくいが、scalaの拡張性やコードの簡潔さを支えているのが、良くも悪くもimplicit conversionだということがよくわかった。
あと、はまったのが、?メソッドに必要な、隠し変数timeout。scalaには、implicit parameterといって、メソッドに必要な引数を普通に引数として渡すのではなく、周りのコードの引数と同じ型のimplicit宣言された値から取ってくるという、ぶっ飛んだ機能があって、こいつを初めて見たので何のことやらさっぱりわからんかった。
確かにこれなら、せっかく?メソッドが演算子的にかっこ良く書けるのに、timeoutをどう渡すんだよという難問を解決できる。
明示的にtimeoutを渡したい時は、
val future = actor.?("world")(Timeout(5 seconds))
みたいにもできるが、見にくいし、かっこ悪い。implicit parameterについては、ひしだまさんのページに書かれた一連のサンプルが非常にわかりやすいです。そのページに限らずひしだまさんのページは、考え抜かれた短いサンプルが大量にあって、scalaを使うには欠かすことができません。scalaの神様です。
で、疲れてきたんだけど、WebSocketにまだ触れてないなこれ。
参考にしたページは、
Auto-Saving ... Done Play Framework 2.1のWebSocketで一対一通信
server側からclientに送信するには、onStartが呼ばれる時にやってくるchannelを使うので、WebSocketがつながっている間は、こいつを大事に取っておきましょう。
client側から何かを受信するたびに、Iteratee.foreach の中に入ってくるので、ここで簡単に受信データを処理できます。
scalaをいじっていて感じたのは、scala開発陣の、いかに簡潔なコードを作成可能な言語にするかという執念じみたものでした。その執念に、これからも期待したいです。
2013年5月24日金曜日
PlayFramework2.1.1環境で、ScalaからJNA経由でcを呼んだりコールバックセットしたりした
PlayFrameworkを使ったシステムをscalaで書いていて、cを呼びたくなった。
呼びたくなったというよりは、裏でc++でものすっごく激しい計算させるので呼ばざるを得ない。
google先生に聞いても、俺の検索力ではサンプルっぽいものは見つけられかった。
{くぅ。scalaも始めたばっかりで分けわからんし、どうしてくれようか・・・}
とコードをごねごねしていたらなんか動いたので、忘れる前に投稿してみた。
できてしまえば、かなりシンプルになった。もちろん一見シンプルに見えるのはscalaパワーのおかげ。
やりたかったことは、あるクラス(HelloData)の各インスタンスのもつクロージャ(?)をc側にコールバックとして登録して、それぞれのインスタンスからcのライブラリを呼んだ時に、ちゃんとコールバックが呼び出したインスタンスのクロージャに返ってくるようにするということ。
ソースのファイルは5つ
Playからindexが呼ばれる→HelloDataのインスタンス作成→HelloDataのコンストラクタ内でコールバック登録→HelloDataのメソッドからcの関数呼び出し→c側からコールバック呼び出し→コールバック内でprintln→c側関数が文字列を戻して終了→webにメッセージ出しておしまい
じゃ、Application.scalaから
HelloDataのインスタンスを3つ作って、ちゃんと区別されて返ってくるか実験する。
HelloData.scala
scala側とc側でデータの連携をとるために、ユニークなidxを持たせてある。
2013/6/4修正 callbackをvalに入れるようにしました。詳しくはこちらの投稿
HelloJna.scala
ライブラリファイルを変更してコンパイルし直しても、一度JVMを再起動(playを再起動すればいい)しないとライブラリをloadし直さないので注意(ここはまった)。JVMには、一度loadしたNativeのLibraryをunloadする機能はないらしい。←あったら誰か教えて
なお、途中のlibHelloJNA.soは、もっと下のJnaInterface.cppからつくったSharedObjectです。
index.scala.html
cの関数から戻ってきた文字列を出すだけ
JnaInterface.cpp
実験なのでidxが255超えたらどうすんのって突っ込みはなし
他の部分はc++で書いていてもここのところはcの関数的に宣言する必要あり(たぶん)。
あと、一番下にiostream閉じてる変なタグが見えたら、SystaxHilighterのバグなので気にしないこと。
下は、ブラウザに表示された結果
次は、printlnの出力
コロン前の数字の値は、各HelloDataインスタンス内にあるので、各インスタンス内のクロージャにちゃんとコールバックが戻っているのが確認できる。
呼びたくなったというよりは、裏でc++でものすっごく激しい計算させるので呼ばざるを得ない。
google先生に聞いても、俺の検索力ではサンプルっぽいものは見つけられかった。
{くぅ。scalaも始めたばっかりで分けわからんし、どうしてくれようか・・・}
とコードをごねごねしていたらなんか動いたので、忘れる前に投稿してみた。
できてしまえば、かなりシンプルになった。もちろん一見シンプルに見えるのはscalaパワーのおかげ。
やりたかったことは、あるクラス(HelloData)の各インスタンスのもつクロージャ(?)をc側にコールバックとして登録して、それぞれのインスタンスからcのライブラリを呼んだ時に、ちゃんとコールバックが呼び出したインスタンスのクロージャに返ってくるようにするということ。
ソースのファイルは5つ
- Application.scala Play側のmain的な入り口
- HelloData.scala テキトーなクラス。こいつのインスタンスからcを呼び出したり、ここのコールバックに戻したり、いろんなデータを持ってみたりしてみたい。
- HelloJna.scala JNAとの接合部分
- index.scala.html web出力のview部分
- JnaInterface.cpp c側のソース
Playからindexが呼ばれる→HelloDataのインスタンス作成→HelloDataのコンストラクタ内でコールバック登録→HelloDataのメソッドからcの関数呼び出し→c側からコールバック呼び出し→コールバック内でprintln→c側関数が文字列を戻して終了→webにメッセージ出しておしまい
じゃ、Application.scalaから
HelloDataのインスタンスを3つ作って、ちゃんと区別されて返ってくるか実験する。
package controllers
import play.api._
import play.api.mvc._
import models._
object Application extends Controller {
def index = Action {
val data = List(new HelloData(), new HelloData(), new HelloData())
val msg = data.map(_.callJnaHello)
Ok(views.html.index(msg))
}
}
HelloData.scala
scala側とc側でデータの連携をとるために、ユニークなidxを持たせてある。
2013/6/4修正 callbackをvalに入れるようにしました。詳しくはこちらの投稿
package models
class HelloData() {
private val lib = HelloJna.lib
private val idx = HelloData.cnt;
private val callback = new JnaCallback {
def onMessage(msg: String) = println("onMessage " + idx + ": " + msg)
}
HelloData.cnt += 1
lib.setFunction(idx, callback)
def callJnaHello: String = lib.getHello(idx)
}
object HelloData {
var cnt = 0;
}
HelloJna.scala
ライブラリファイルを変更してコンパイルし直しても、一度JVMを再起動(playを再起動すればいい)しないとライブラリをloadし直さないので注意(ここはまった)。JVMには、一度loadしたNativeのLibraryをunloadする機能はないらしい。←あったら誰か教えて
なお、途中のlibHelloJNA.soは、もっと下のJnaInterface.cppからつくったSharedObjectです。
package models
import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.Callback
object HelloJna {
val lib = Native.loadLibrary("/xxx/yyy/xxx/Debug/libHelloJNA.so", classOf[HelloJnaTrait]).asInstanceOf[HelloJnaTrait]
}
trait JnaCallback extends Callback {
def onMessage(msg: String): Unit
}
trait HelloJnaTrait extends Library {
def getHello(idx: Int): String
def setFunction(idx: Int, callback: JnaCallback)
}
index.scala.html
cの関数から戻ってきた文字列を出すだけ
@(messages: List[String]) <!DOCTYPE html> <html> <body> @for(msg <- data-blogger-escaped-messages="" data-blogger-escaped-p=""> @msg} </body> </html>
JnaInterface.cpp
実験なのでidxが255超えたらどうすんのって突っ込みはなし
他の部分はc++で書いていてもここのところはcの関数的に宣言する必要あり(たぶん)。
あと、一番下にiostream閉じてる変なタグが見えたら、SystaxHilighterのバグなので気にしないこと。
#includeusing namespace std; static int g_cnt = 0; static char g_msg[256]; static void (*g_callback[256])(const char *msg); extern "C" const char *getHello(int idx) { char callbackMsg[256]; sprintf(callbackMsg, "msg to callback %d", idx); g_callback[idx](callbackMsg); sprintf(g_msg, "Hello JNA idx = %d, cnt = %d.", idx, ++g_cnt); return g_msg; } extern "C" void setFunction(int idx, void (*func)(const char *msg)) { g_callback[idx] = func; }
下は、ブラウザに表示された結果
Hello JNA idx = 0, cnt = 1. Hello JNA idx = 1, cnt = 2. Hello JNA idx = 2, cnt = 3.
次は、printlnの出力
コロン前の数字の値は、各HelloDataインスタンス内にあるので、各インスタンス内のクロージャにちゃんとコールバックが戻っているのが確認できる。
onMessage 0: msg to callback 0 onMessage 1: msg to callback 1 onMessage 2: msg to callback 2
登録:
コメント
(
Atom
)


