2014年1月7日火曜日

MacとLinuxの挙動の違いについて

昨日ポストした,mac上で作ったGtk+を使って計算するプログラムを,Linuxでも動かそうと思ってコンパイルしてみました.
プラットフォームに依存することはしていないので完全に互換のはず,と思って単純にコンパイルだけしました.

しかし,コンパイラではerrorもwarningも出なかったのですが,実行してみたらセグメンテーション違反になってしまう.
がっくりきて小一時間いろいろ試したら,動くようになりました.

理由が二つありました.


  1. パイプを使ってgnuplotを開くときのパスの指定の仕方
  2. ファイルオープンが失敗したときにfcloseするべきかどうか


前者は,mac上ではgnuplotにパスが通っていれば,

FILE *gp;
gp = popen("gnuplot", "w");

で動いたのですが,Linuxでは

FILE *gp;
gp = popen("/usr/bin/gnuplot", "w");

としないと動きません.
これはすぐに分かったのですが,問題は次のファイルオープンが失敗した時の処理です.

計算し終わったデータを格納するファイルが,同じファイル名で既に存在する場合,基本的にはアペンドモードで追記しているので問題ないのですが,念のため以下のように確認するダイアログを出していました.

  if((fp = fopen (filename, "r")) == NULL){
    fclose(fp);
    start_or_stop=1;
  }
  else{
  fclose(fp);
  GtkWidget *dialog;
  GtkWidget *parent;
  GtkWidget *labeld;
  gint response;
.
.
.
(以下にダイアログを出すコードが続きます.)
これは単純にファイルが存在するかどうかを確認するために付け加えたコードでした.
以前,c言語ではファイルのオープンに失敗しても,そのポインタにNULLが格納されて,以後書き込む時にNULLに書き込んでしまい危険だから云々...
と勉強した記憶があったので,fcloseを書いていました.

macではこれで実行しても問題ないし,linuxでもコンパイラではerrorもwarningも出なかったのですが,実行すると無情のセグメンテーション違反とのお答えが..

おかしい場所はここしかないと思ったので,fpがNULLのときのfcloseをコメントアウトすると,無事に動きました.

なぜでしょう??

2014年1月6日月曜日

Macでgtk2のテーマをかえてみたい!(finkです)

Finkでgtk+のテーマを変更する方法を見つけたのでメモしておきます.

まずは,finkでgtk-change-theme,gtk2-engineをインストール.
これで最低限テーマを変更できるようになります.
起動は,

$ gtk-chtheme

です.GUIのテーマセレクタが現れて,いくつか選べるようになります.



上の画像は,すでに他のテーマをいくつかインストールしたあとなので,選択肢が豊富です.
単純に,finkでgnome-themesとgnome-themes-glossy-pをインストールするだけでもかなりの数のテーマが使えるようになりますが,ウェブから落としてきたテーマを/sw/share/themes以下にコピーしても使えます.

見た目はかなりいじれるようになり,


こんな感じになったり,


こんな感じにすることも出来ます.

ちなみにこの画像は前のブログエントリで書いたマルチスレッドのGTKプログラムですが,fileメニューはただQuitだけがあるシンプルなものです.
グラフはgnuplotに描かせているのですが,これはプログラムの中からパイプで呼び出しています.
今回,gnuplotの出力ターミナルをwxtにしています.

これには理由が二つあり,

  1. 右クリックでグラフのレンジを変えられる(拡大が可能)
  2. デフォルトだとaquatermになってしまうので,プロットするたびにマウスフォーカスがaquaにうつってしまい,煩わしい(wxtならマウスフォーカスは常にX11のまま)

からです.



C言語で,Gtk+とgthread

gtk+2.0とgthreadでマルチスレッドのプログラムを作りたいのですが,意外と情報が少なく困っています.

たとえばGUIで測定プログラムを動かしていて,途中で電流値などのパラメータを変えたいと思っても,マルチスレッド化しなければ普通はループが終るまで変数の変更を許してくれません.

そこで,測定ルーチンは別のスレッドで無限ループにしておいて,メインのスレッドではボタンをクリックしたりentryウィジェットで数値を入力したりしてループ条件やパラメータを変更する,と言う風にスレッドを分けることが必要になります.

具体的には,メイン関数の中で
GThread* thread;

g_thread_init(NULL);
gdk_threads_init();

と初期化した後,
thread = g_thread_create ( thread_func, (gpointer)label3, FALSE, &error );
という風にしてthread_funcを別スレッドで立ち上げる.ここでlabel3を引数として与えているのは,thread_funcのなかでlabel3のテキストをリアルタイムで書き換えているからです.

thread_funcはgpointer型にする必要があるらしく,実際の中身は
static gpointer thread_func ( gpointer data )
{
  while( TRUE ){
  g_usleep(500000);
   
  if(start_or_stop != 0){
  .
  .
  .
  gtk_label_set_text(GTK_LABEL (data), buf);
  }
  
  }
} 
みたいな感じにしています.

ここで,start_or_stopはintで宣言していて,0のときは何も実行されない.
メイン関数のボタンをクリックするとstart_or_stopが0になったり1になったりする,という仕組みです.
gboolean型でも良かったのかもしれないのですが,caseで処理を分けるかもしれないことを考えて,intにしておきました.

実際はこんな感じ



これは実際に測定しているわけではなく,0.5秒おきにスピン1/2三角格子ハイゼンベルグ反強磁性体の帯磁率を1ケルビンおきに計算してプロットするというプログラムを測定ルーチンのかわりに入れています.

2013年12月4日水曜日

fink v0.36.*は既にMavericks対応済みらしい

finkの日本語ページは相変わらず更新遅いのですが,どうやら英語ページでは10/30付けでfinkのv0.36.0と0.36.1がリリースされていて,Mavericksに正式に対応しているようです.

ただ,私自身がrootをMavericks上でビルドできていないので,(というかホゲる気力が湧いてこない)まだiMacはMountain Lionのママです.

年明けくらいにはがんばってホゲろうとおもいます.

2013年10月31日木曜日

MacOSX 10.9 Mavericksにfinkを入れた

MacBookAirのSSDがいっぱいになってきたので,まっさらにして入れ直すついでに,Mavericksにしてしまいました.

ネットでいろいろ情報あたってみたところそれなりに簡単にfinkが動くらしいということで,ついでにアップグレード.

しかし,やっぱり落とし穴が....

Maverickにした後,まずはXcodeをダウンロードし,ライセンスを先にagreeする.

$ sudo xcodebuild -license

続いてcommand line toolsをダウンロード.

$ sudo xcode-select --install

そして,finkのソースを落としてきてbootstrapしようと思ったら.....

fink,ネットではそのまま動くと書いてあったので,あまり心配しないでさくっと/swディレクトリを削除してしまったのですが,bootstrapしようとするとうまく出来ません.

ここで勘違いに気づく.

つまり,Mavericksを上書きインストールした時はXQuartzの再インストール程度で動くのだが,Mavericks上でfink環境を構築しようとするとうまく行かない,ということらしい.

とバックアップしなかった自分のうかつさにびっくり.
でも,きっと同じように悩んでいる人はいっぱいいるだろうと,検索ちゃん.

ありました.

ありがたくそのまま使わせていただくことにしました.
さっそくtexliveをインストール.
しっかりTeXShopからコンパイル出来ました.

2013年10月28日月曜日

picocom: minicomよりもコンパクトなシリアル通信

picocomという,minicomよりもコンパクトで,シリアル通信に使えるコマンドを見つけました.
Scientific Linux 6.3上では普通にyumでインストールできますが,レポジトリはepelです.

使い方はminicomのように設定ファイルをあらかじめ用意する必要がなく,

$ picocom -r -l /dev/ttyUSB0

で直接シリアル通信できます.
ここで-rは終了時にリセットしないようにするオプション,-lはシリアルポートをオープンする前にlockしないようにするオプションです.

特に,一般ユーザで使用するときは,たとえdialoutグループに所属していたとしても,-lオプションを付けないとパーミッション関係のエラーが出て起動できなくなります.
(おそらく,一般ユーザでは/val/lock以下への書き込み権限がないため)

終了するときは,CTRL-a CTRL-xで終了です.


2013年9月19日木曜日

Linuxで,USB-RS232C変換ケーブルをつかってシリアル通信するときの注意点

以前購入しておいたUSB-シリアル変換アダプタをlinuxでつかう際にこまるのが,パーミッションの問題.

つかいはじめた頃は/dev/ttyUSB0にパーミッションを与えていたんだけど,スマートじゃない上に再起動したりアダプタをUSBポートから抜いたりすると,パーミッションも元に戻ってしまいます.

そこで,初心に立ち返って,自分のアカウントをグループに追加すれば良いはずだと思い立つ.

$ ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0  9月 19 18:08 2013 /dev/ttyUSB0

というわけで,dialoutグループに自分を追加.
すると無事再起動してもつなぎ変えても大丈夫になりました.

きっと三ヶ月もすると忘れるので,しっかりメモしておきましたとさ.