一般tips

一般tips

  • [共有ワークスペース>一般Tips/共有ワークスペース]~

# etags, ctags, gtags

etags, ctagsはコードの読解補助ツールでタグツールと呼ばれます。 ソースコード読み会、また開発にはこれらのタグツールを用います。 etagsはemacs、ctagsはviに使うタグを生成します。 gtagsは設定により emacs , vi の両方で使用できます。 ここではetags とgtags(emacs) について説明します。

# etagsの使いかた

etagsの使い方はいたってシンプルです。 ターミナルから次をタイプしてみます。

% etags *.[ch]

すると、ディレクトリにTAGSファイルが現れます。 このファイルにemacsに使われるコード追跡データが入っています。

次はそのままemacsを実行します。開くファイルはとりあえずmain.cを 開くことにして話を進めましょう。

% emacs main.c

普通にmain.cが読み込まれemacsの画面に表示されます。

準備は整いました。では実際に使ってみます。 main.cのなかに、例えばsyokika()という関数があったとします。 このsyokika()関数が定義されている箇所へジャンプするときは、emacs上 のsyokikaの文字の上にカーソルをもってきて以下をタイプします。

M - .

ESCを押した後で . (ピリオド)です。 タイプするとemacsの下の部分にタグファイルの指定を聞いてきますので、 TAGSファイルのディレクトリを確認してからエンターで確定して下さい。 元の箇所へ戻るときは

M - *

ESCした後で*(アスター)です。

操作はこれだけ!簡単です。 他にも便利な使い方があると思いますのでウェブを検索して調べてみることをお薦めします。

# gtagsの導入方法(emacs)

gtagsを導入したい場合http://www.gnu.org/software/global/global.htmlのページを見れば導入方法が書いてあります。 ~ 英語で書かれている のでぜひ読んでほしい。(僕の友達は読みました。) ~上記のページを読んでもどうしても解らない場合、英語のページが読みたく無い場合、emacsを使用しての gtags 使用方法を下記に記す~ gtags のソースを上記ページの Download の方から download して install する。 install した後は .emacs ファイルに(無い場合は $HOME の下にでも作成する)

1
2
(setq load-path (cons " (gtags.el がある directory の path) " load-path))
(autoload 'gtags-mode "gtags" "" t)

追加する。 gtags.el は global-x.x.x 内にあるので任意の directory に copy しておく。

# gtagsの使い方(emacs)

Program source のある top の directory で

% gtags

を入力する。そしてemacs を起動して

M-x gtags-mode

を実行することで gtags のコマンドが使えるようになるので後は上記の etags の使い方に書いてあるのでそこを参照する。 ~emacs を起動する度、毎回 M-x gtags-mode を入力するのが面倒な場合は .emacs に

1
2
3
4
(setq c-mode-common-hook
         '(lambda ()
             (gtags-mode 1)
     ))

を追加しておけば、.c .cpp 等を emacs で開くと自動で gtags-mode が起動する。

# CVSの使い方

CVS は共同プロジェクトによるドキュメントやプログラム・コード等の管理を 行う便利なツールです。ゲーム班にまつわる全ては CVS によって管理されま すので、CVSで始まりCVSで終わるといっても過言ではないでしょう。

ここでは CVSの使い方を例を挙げて説明します。 ただ、CVSをコマンドから直接打ち込むと面倒なので、cvs-cr というスクリプ トを作って、それを使います。練習用のプロジェクトに Game_project/Test/ 以下を用意しましたのでそちらを御利用下さい。 実際のゲーム作りではGame_project/ 以下にプロジェクトを作ります。特に PS2 Linux向けのプロジェクトならば Game_project/ps2 を、GBA向けの プロジェクトならば Game_project/gba をお使い下さい。

ここでは Game_project/Test/ 以下に test_program という仮想のプロジェク トを作り、cvs-cr の使い方の例を挙げて説明することにしていきましょう。

# つーかCVSって何だば?

簡単に言えばプロジェクト運営用のツールで、データベースのような機能を提 供します。

例えば、プロジェクトとして複数人で一つのプログラムのコーディング作業を行ったら どうなると思いますか? もちろん誰が何を変更したか分かりませんので、 コーディングにバグが含まれていたら目も当てられませんね。 バグを忍ばせた人が誰なのかは全くわかりません。 よってチームの人間関係にヒビが入ります。

編集する前には cpコマンドとかで バックアップをとるのが妥当ですが、 cpでバックアップを毎回とるのですか? そいつはちと面倒です。 それ以前にバックアップ自体にバグが含まれていたら チームの人間関係に莫大なダメージを与えます。

それと、よくある失敗で、

% rm -rf * (メガンテ!!)

という自爆技があり、これによりチーム全員が自爆します。 ホームディレクトリでやるとその効果は絶大です。

ということを防ぐためにCVSを使いましょう。習得は楽なので恐れないで下さい。

# cvs-crの作りかた

奴はシェルスクリプトで、中身はこんな感じです。 locateかfindで探せば見付かるはずですが、まぁ取り敢えずここではcvs-crの作り方を説 明します。

cvs -d game@firefly.cr.ie.u-ryukyu.ac.jp:/home/one/CVS_DB $*

こんだけです。これを毎回打ち込むのはさすがに面倒なのでシェルスクリプトにするので す。ここでは説明しませんが多分 alias でもいけますよ。

とりあえずcvs-crの作り方を説明します。取り敢えずエディタでcvs-crを書きましょう。

% vi cvs-cr
もしくは
% emacs cvs-cr

これで上記の一行を書いて終了なのです。それから忘れずに実行権を与えましょう

% chmod +x cvs-cr   (ユーザの実行許可)

でもって ~/bin ディレクトリ作って cvs-cr を放りこんで下さい。

% mkdir ~/bin
% mv cvs-cr ~/bin

次に ~/bin に実行のパスを通してあげます。パスは tcsh なら ~/.tcshrc、 bash なら ~/.bashrc に書かれてますので、こやつに ~/bin の実行パスを追 加します。ここではtcshについて説明しますので適当にいじって下さい。

% emacs ~/.tcshrc  (tcshの場合)

でもって、以下の行を追加。

set path = ($path ~/bin)

編集が終わったら忘れがちなのがコレ!

% source ~/.tcshrc
% rehash

はい終了。簡単でした。でも実はこれだけじゃまだ設定不足で、環境変数の 設定が必要です。以下のcvsで用いる環境変数を読み下さい。

# cvsで用いる環境変数

PS2Linux で CVS を使うときは CVSの環境変数を /etc/bashrc , /etc/csh.cshrc で設 定しています。ただし、PS2 Linux以外の PC から CVS 使う場合は, ~/.bashrc か ~/.tcshrc で環境変数を設定しなければなりません。設定は以下のようになります。

こっちは bash の場合 export CVS_RSH=ssh export CVSEDITOR=/usr/bin/emacs

んで、こっちが csh/tcsh の設定です。 # CVS で用いるログインシェル. 本学科はsshを使うことになってます setenv CVS_RSH ssh

# CVS で用いる エディタ. vi でなく emacs とか書くと ログの書き
# 込み時に勝手に emacs が起動します。日本語化け対策はeucで保存す
# ればOK !
setenv CVSEDITOR vi

更に以下の環境変数が設定されていれば cvs-cr は必要ありません。

.bashrc

1
export CVSROOT=game@firefly.cr:/home/one/CVS_DB

.csh/.tcsh

1
setenv CVSROOT game@firefly.cr:/home/one/CVS_DB

# 新規プロジェクトを開始する

まず、cvsリポジトリの Game_project/Test/ 以下に test_program と いう新しいプロジェクトを作ります。新規プロジェクトを開始する場合 は import を使います。そのあとにオプションとして プロジェクト名、 ユーザ名、リリースタグを指定します。インポートするとエディタが起 動し、コメントを付けることができます。 以下を実行すると、カレントディレクトリ以下の(. .. 以外の) ファイ ル・ディレクトリが Game_project/Test/test_program にリポジトリと してに追加されます。

$ cvs-cr import Game_project/Test/test_program game start

# プロジェクトをチェックアウトする

cvsリポジトリよりプロジェクトを入手(チェックアウト)します。 checkout を使います。 以下を実行すると、カレントディレクトリに Game_project/Test/test_program ができます。また、ここで Game_project/Test/ を指定すると、test_program だけではなく、 Game_project/Test/ 以下の全てのプロジェクトをチェックアウトでき ます。

$ cvs-cr checkout Game_project/Test/test_program

または $ cvs-cr co Game_project/Test/test_program

# プロジェクトをコミットする

チェックアウトしたファイルなどに変更を加え、その変更をリポジトリ にも反映させたい場合は commit を使います。ただし、新しくファイル やディレクトリを追加した場合は add を用いてからコミットしてくだ さい。コミットしたときに指定したエディタが起動して、コメントを付 けることができるので、変更箇所などの情報を書くといいでしょう。 作業用ディレクトリ(チェックアウトした test_program) で以下を実行 すると、変更を加えたファイルだけをリポジトリに反映します。特定の ファイルだけをコミットしたい場合はオプションとしてファイル名 (file_name)を指定してください。

$ cvs commit [file_name]

CVSの-dオプションを用いることで、作業ディレクトリを好きな名前にすることが できます。例えば以下のようにタイプするとよいでしょう。

1
$ cvs-cr co -d my_1st_study Game_project/ps2/example/SimpleModel

# リポジトリの変更を自分の作業用ディレクトリに反映させる

自分がチェックアウトした後に他の人がリポジトリに変更をコミットし た場合、その変更を自分の作業用ディレクトリに反映させることができ ます。その場合は update を使います。

$ cvs update

もしくは

$ cvs up

しかし、これだとカレントディレクトリの反映しかされないので、 おまじないオプションをつけてあげます。

$ cvs up -dP

これでカレントディレクトリに存在する子ディレクトリの中身もアップデートされます。

# プロジェクトに新たにファイル・ディレクトリを追加する

プロジェクトに新たにファイルやディレクトリを追加する場合は作業用 ディレクトリで add を用いてからコミットします。add だけではリポ ジトリにファイルができないので、コミットすることを忘れないで下さ い。 以下のコマンドは、test_program 以下に新たに add_dir というディレ クトリと add_file_1.c というファイル、add_dir の下の add_file_2.c というファイルを追加します。

$ cvs-cr add add_dir add_file_1.c
$ cvs-cr add add_dir/add_file_2.c
$ cvs-cr commit

# プロジェクトからファイルやディレクトリを削除する

削除するにはremoveコマンドを用います。&color(red){ただし作業ディレクトリ上のファイルを消すのが先ですので御注意下さい!}; 以下に例を示します。

1
2
$ ls -f
./ ../ CVS/ Makefile a.out test.c main.c testlib/

a.outなどの実行ファイルはcommitしないようにしましょう. test.cは文字どおりテスト用なので用済みになったとしましょう。 最初に作業ディレクトリ上のファイルを削除します。 ファイルを削除するコマンドは、

1
$ rm a.out test.c

ですね。ではCVSリポジトリ上のa.out, test.cも削除します。

1
$ cvs remove a.out test.c

もしくは

1
$ cvs rm a.out test.c

でOKです。 ただし、removeしただけではCVSリポジトリにはまだ反映されていませんので、 最後にCVSリポジトリに更新を反映(commit)します。

1
$ cvs commit

または

1
$ cvs ci

これでファイルの削除は終了です。次にディレクトリの削除について説明します。 今ファイルは、

1
2
$ ls -f
./ ../ CVS/ Makefiel main.c testlib/

そしてtestlib/は

1
2
$ ls -f testlib/
./ ../ CVS/ object_tree.c object.c draw.c

となっています。testlib/は文字どおりテスト用のライブラリですので用済みになったとします。

testlib/を削除するには、まずtestlib/上のファイルを全て削除します。

1
2
$ cd testlib/
$ rm object_tree.c object.c draw.c

そして

1
2
$ cvs rm object_tree.c object.c draw.c
$ cvs ci

です。これでtestlib/を削除する準備が整いました。 ディレクトリを削除するコマンドはdeleteです。

1
2
$ cd ..
$ cvs delete testlib/

これでtestlib/が削除されます。 削除されない場合はtestlib/にファイルが残っている可能性があります。 隠しファイルかもしれませんので、

1
$ ls -a

を試して下さい。もし隠しファイルがあれば、 他のファイルと同様の手順で削除してから再度deleteコマンドを試して下さい。

&color(red){※ CVSリポジトリのディレクトリを削除するにはfirefly.crにログインしてからrmでディレクトリを削除する方法を教えました。それでもいいのですが、昔のリビジョンが必要になったときに困ることになります。なにせディレクトリはリポジトリ上から消し去られてしまったのですから復活しようがありませんね…今回説明した方法ならば、昔のリビジョンに戻ることが可能です。実はremoveコマンドやdeleteコマンドによって削除されたファイルは、削除されたファイルとしてCVSリポジトリ上に保存されているのです。ですから、もし昔のファイルやディレクトリが必要になったときに「よかった〜」と思えるはずです。};

# プロジェクトにタグ(マーク)をつける

プロジェクトをcheckoutする場合、開発における一定のポイントを取り出したいということが多々あります。そのとき、日付による取得とタグによる取得があります。ここでは、タグによる取得を紹介します。 ~~ 「あ、あのときのリリースバージョンとりたい!」ということが起きたとしましょう。そのとき、日付やタグによる取得をしらないと「えーっと、file_1.cはversion1.1で、file_2.cはversion1.2でfile_3,cはーえっと..???」なんてことになってしまいます。 ~ ~ なぜそんなことがおきるのか?そう、CVSのバージョン管理はファイル別で行われているので(リポジトリ別ではない)、ファイルによって最新バージョンがバラバラになっていることがあります(例えば、file_1.cはversion1.1、file_2.cはversion1.2の様に)。 ~ その問題を解決してくれるのが、タグ機能です。ある特定のポイントでタグをつけることにより、後でタグに指されたそれぞれバージョンのファイルをcheckoutすることができます。 ~ ~ さあ、使ってみましょう。現在、Game_project/Test/test_programをcheckoutして、そのディレクトリにいるとします。

  • 以下はタグを付けるコマンドです。tagの後ろにタグ名を付けて下さい。
1
cvs tag [tag_name]
  • 以下はタグの付いたポイントをcheckoutするコマンドです。
1
cvs-cr checkout -r [tag_name] Game_project/Test/test_program

# プロジェクトを最新の状態にする

タグなどによって古いバージョンに戻したあと、再びプロジェクトを最新の状態にしたいとき。

1
cvs up -A

オプション"A"を忘れずに付けましょう。

# CVSリンク

CVSの使い方~ CVS - Concurrent Versions System

CVSについてさらに知りたければ、研究室にCVS関連の本がありますのでどうぞ。もしくは Let’s google!!

# Doxygen

Linux向けに開発されたツールです。ソース・コードの中に埋め込まれたコメントから ドキュメントを生成します。生成できるドキュメントはHTML、TeX、manなどです。

tagsとソース・コードのコメントだけじゃ寂しいよ、と思う人はお試し下さいね。 ただし、Doxygen専用のダグをつけないとDoxygenのコメントとして認識しません。

Doxygen

はDoxygenの本家(ぃえいご)です。日本語のページはDoxygenで検索すればボロボロ でてきますが、

Let’s use doxygen!

が良いと思います。どちらのページからでもDoxygenを入手可能ですが、探せばRPMパッ ケージもあります。ちなみにVine Linuxなら

ftpサイト

の適当なFTPサーバの Vine Plusの項目を探せば見付かります。RPMを使うと依存関係の解決で他にも? いろいろ取ってこなきゃなりません。んで、

  • libexpat
  • graphviz
  • doxygen

ってなRPMパックをげっちゅーしてこの順番でインストールしましょう。

DoxygenによるとMaxOS Xにも イけるようなことが書かれています。

# パスワード無しでssh

ssh-agentを使って、guest@nw(ホスト)からguest@pstwo1にパスワード無しでログインする方法を説明します。

まずnwの設定

1
2
3
4
5
6
7
8
9
[guest@nw]% ssh-keygen -t rsa # RSA鍵を発行する
Genperating public/private rsa key pair.
Enter file in which to save the key (/home/guest/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): # ここにパスフレーズ
Enter same passphrase again: # 確認のため同じフレーズを入力
Your identification has been saved in /home/guest/.ssh/id_rsa.
Your public key has been saved in /home/guest/.ssh/id_rsa.pub.
The key fingerprint is:
66:bc:98:08:7f:9d:af:e1:a7:58:3f:c3:d2:cd:95:aaguest@nw.st.ie.u-ryukyu.ac.jp

ssh-keygenで生成したRSA公開鍵(id_rsa.pub)をguest@pstwo1にscp

1
[guest@nw]% scp ~/.ssh/id_rsa.pub guest@pstwo1:

それから、~/.loginと~/.logoutの設定を行ないます。ファイルが無い場合は新規に作成します。

.loginには以下を追加します。

1
2
3
4
5
6
7
# WinSCP/WinSCP2 に対応するための設定
if ($?SSH_CLIENT && ! $?SSH_TTY) exit

# for ssh-agent
if (! $?SSH_AGENT_PID) then
        eval `ssh-agent`
endif

.logoutには以下を追加します。

1
2
3
4
# for ssh-agent(1) (see ~/.login)
if ($?SSH_AGENT_PID) then
        eval `ssh-agent -k`
endif

次にguest@pstwo1の設定です。

1
[guest@pstwo1]% cat ~/id_rsa.pub >> ~/.ssh/authorized_keys2 # 上書きに注意!!

emacsやviで鍵をコピペするとダメです。

最後に、guest@nwで新しく端末を開いて

1
% ssh-add

# するとパスフレーズを訪ねられますので、 先ほど設定したパスフレーズを入力します。 ssh-add以降はguest@pstwo1へのログイン時のパスワード認証が自動で行なわれます。

guest@pstwo1からgame@fireflyへの設定も同じ要領でOKです。

guest@pstwo1で

1
2
3
4
[guest@pstwo1]% ssh-keygen -t rsa
* パスフレーズを入力します *
[guest@pstwo1]% scp ~/.ssh/id_rsa.pub game@firefly:
* 公開鍵をgame@fireflyにscpします *

そして~/.loginと~/.logoutを編集します。 更にssh-addをエイリアスするため、~/.tcshrcに以下を追加します。

1
2
# ssh-add
alias ssh-add 'ssh-add ~/.ssh/id_rsa'

次にgame@fireflyで

1
2
[game@firefly]% cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
* 書き込み先は~/.ssh/authorized_keysです。~/.ssh/authorized_keys2ではありません ! *

これで guest@pstwo1 で ssh-addによるパスフレーズ認証が可能になります。

# emacsの上でshell

emacsの上でshellを動かすことができます。emacsで次をタイプしてみて下さい。

1
M-x shell

#ref(emacs_shell.png,around,40%)

ESCを押した後でxを押し、続けてshellとタイプします。 するとお馴染みのshell画面が登場します。 ターミナルをいくつか開いて、こっちではemacs、あっちではshellとかやってて ターミナルを移動するのが面倒だという人は試して下さい。 使い方はemacsのままなので少し違和感があると思いますが、 まぁ慣れということで。

あと、emacsの上でemacsを走らせることもできます。それとsudoはあんまりお薦めしません。扱いが難しいのです。

#img(,clear)

# デバッグの手法

私が使っているデバッグの手法を紹介します。

# gdbを使ってみる

# gdbの紹介

gdbは The GNU Debuggerです。C言プログラムをgdbの上で走らせ、 特定の箇所で止めて周辺の値を調べたり、プログラムがどの辺りで止まったかを詳しくレポートさせたりします。

MacやLinuxには元から入っていますので、何もインストールする必要はありません。 難しく考えるかもしれませんが、要はプログラムを好きな場所で止めたり、 値を好きなように変更してみたり、もしくはプログラムの変数の中身を出力してみたりするだけです。

ただこれだけでも立派なデバッグ作業なのです。 使い慣れるとgdb無しではプログラムしたくなくなります。

# gdbを使う前に

gdbを使うには、実行ファイルにgdbに必要なデバッグ情報を付加してあげる必要があります。 デバッグ情報を付加するにはccに-gオプションを付けます。 では実際に試してみます。hello_gdb.c を適当なディレクトリに保存してコンパイルします。

1
cc hello_gdb.c -g

# gdbでよく使うコマンド

  • プログラムの実行

プログラムを実行するには run コマンドを使います。プログラムに引数

1
(gdb) run <option>

プログラムを(breakなどを用いて)一時停止し、再開するときには continue を使います。

1
(gdb) continue

一時停止したプログラムを一行だけ実行することもできます。step と next の二つがありますが、step は関数を呼び出すときにその関数内も一行づつ実行し、next は関数内には入りません。

1
2
(gdb) step
(gdb) next
  • ブレークポイント

プログラムを一時停止したい場合はブレークポイントを設けます。関数 <function_name> にブレークポイントを設けるには以下のように break コマンドを使います。関数 <function_name> が呼ばれると <function_name> の最初の行でプログラムが一時停止します。また、ファイル名 を指定したい場合は :<function_name> のようにコロンを挟んで指定します。

1
2
(gdb) break <function_name>
(gdb) break <file>:<function_name>

プログラム中の全関数を見たい場合は以下のコマンドを実行します。

1
(gdb) info functions

関数名ではなく、行番号 <line_num> を指定することもできます。方法は関数名と同じです。

1
2
(gdb) break <line_num>
(gdb) break <file>:<line_num>

ブレークポイントの一覧が見たい場合は以下のコマンドを使います。

1
(gdb) info breakpoints

ブレークポイントの削除には delete を使います。<break_number> は info breakpoints で確認できる、ブレークポイントの番号です。

1
(gdb) delete <break_number>
  • 表示

実行中のプログラムの変数を見たい場合は print を使います。 print は変数 やポインタが指す先の値 *,式 などを表示することができます。

1
2
3
(gdb) print <variable>
(gdb) print *<pointer>
(gdb) print <expression>

実行しているプログラムのソースコードを表示するには list を使います。引数を与えないと現在実行している行周辺を表示します。関数 を与えるとその関数を、行番号 <line_number> を与えるとその行番号周辺のソースコードを表示します。

1
2
3
(gdb) list
(gdb) list <function>
(gdb) list <line_number>

通常は10行づつ表示しますが、以下のように set を用いて 行づつ表示できるように変更できます。

1
(gdb) set listsize <number>
  • スタック・フレーム

現在実行している関数がどのようにして呼ばれたかを知りたい場合は where か backtrace を使います。

1
(gdb) where

where はスタックに詰まれた関数の層を表示します。この層の一つ一つをフレームといいます。現在プログラムが実行しているフレームを見るには frame を使います。frame に引数として各フレームに割り当てられている番号 <f_number> (whereで確認できる)を指定すると、そのフレームへ移動します。

1
2
(gdb) frame
(gdb) frame <f_number>

層になっているフレームは up と down を使うことで、上または下方向へ移動できます。引数として数字 を与えると 個分移動します。

1
2
(gdb) up <number>
(gdb) down <number>

# 参考文献

本ページは以下のページを参考にしました。より詳しくGDBを知りたい方は一読することをお推めします。

Debugging with GDB~

# 開発時のノウハウ

開発環境(Library) の導入をするときは必ずmanual を読むこと、manual はソースとは別途に用意されているのでちゃんと落とす。~ yum を使う場合はmanual も一緒に手に入るので幸せになれますが、iBook にはyum はありません。仕様です。ごめんなさいっ!

#include(一般Tips/共有ワークスペース)

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy