このページの管理者は、こんなアプリを作ってます →  imoco  choical  ZoomVolume 
tips  >> 02.プログラミングなど  >> C言語  >> C言語のLinux環境.txt [takaaki024]  [blog]  [フレームで表示]

C言語のLinux環境     


 UNIXプログラミングの道具箱   Inside Linux Software   ふつうのLinuxプログラミング


gccとかgdbとかgoogle-perftoolsとか、C言語のLinux環境関連のメモ


コンパイル

# バージョンを確認する
gcc -dumpversion

# オプションつけないでコンパイル
gcc xxx.c
    → a.out という名前の実行ファイルが出来る。実行権限もつけてくれるようだ。

# 実行ファイル名を指定したいとき
gcc -o xxx xxx.c
    → xxx という名前の実行ファイルが出来る

# その他のオプション
-Wall : 警告を全部みせる

-O1 (-O)  : ゆるい最適化
-O2       : 普通の最適化 (普通はこれをつかうそうだ)
-O3       : 強力な最適化 (コンパイラのバグを引き当てたりするそうだ)


-g (== -g2) : デバッグ用のシンボル
-g3         : マクロも展開する

-gdwarf-2

    -funroll-loops   : アンロール
    -ftree-vectorize : ベクタ化(SIMD化) ※ -funroll-loopsと一緒に使わないと効果なし


デバッグ


gdb

# コンパイル時に -g オプションが必要
gcc -Wall -g -o test test.c

# デバッグ
gdb ./test

# run  (例えば test -d fname.txt というコマンドをデバッグしたい場合)
(gdb) run -d fname.txt

    → エラーの場合例えばこんな感じに出る
        Program received signal SIGABRT, Aborted.
        0x00483402 in __kernel_vsyscall ()

# backtrace  (エラーが起こった状態から、呼び元を調べる)
(gdb) backtrace

    → 表示例
        #0  0x00a00402 in __kernel_vsyscall ()
        #1  0x0059fba0 in raise () from /lib/libc.so.6
        #2  0x005a14b1 in abort () from /lib/libc.so.6
        #3  0x005d5dfb in __libc_message () from /lib/libc.so.6
        #4  0x005de13c in _int_malloc () from /lib/libc.so.6
        #5  0x005defed in calloc () from /lib/libc.so.6
        #6  0x0804c1e3 in readCPoolDouble (cpool=0x810f034, ptr=0xbf94904c) at test.c:1419
          :
        #11 0x0804f2ef in main (argc=-1080781884, argv=0x0) at test.c:2442

# frame  (backtraceの結果の行の詳細を知りたいとき)
(gdb) frame 6    # 該当の行だけ見れる
(gdb) list       # その行の周りを見たいとき

# フレームを移動
(gdb) up         # 次の番号へ  (btで出てくる一覧でいうと↓の方向)
(gdb) down       # 前の番号へ

# 変数を知りたい  (例えば 変数名 xxx)
(gdb) print xxx

# 進める
(gdb) continue

# gdbを終了する
(gdb) quit

# 変数のwatchや、ブレークポイントの設定を解除する
(gdb) delete   ※ 番号を指定しないと全部消える


※何も入力せずにEnterを押すと、直前実行したコマンドを実行する

※省略形
    backtrace bt
    frame     f
    list      l
    print     p
    continue  c
    quit      q


変数を見たい
    printf "%d\n" xxxxx
    print /d xxxx


実行中のプログラムをデバッグしたいとき
    attach プロセスID
    detach
    kill

ブレークポイントの設定
    break [ソース名] 関数名  : 関数の入り口で停止
    break +5                 : 5行後ろで停止
    break [ソース名] 行番号  : 対応する行で停止 ※ 間にコロン( : )が要る?
    break xxx if xxxx        : 条件も指定できる
    
    clear xxx                : 削除
    delete                   : 全部削除 (番号で指定することも可)

ウォッチ・ポイントの設定
    watch 式    : 式の条件が真になったら停止
    rwatch 式   : 式の対象が読み込みアクセスされたときに停止
    awatch 式   : 式の対象が読み込みアクセスまたは書き込みアクセスされたときに停止
    
    ※ ウォッチポイントにクラスのメンバを指定したいときは
        xxx::Xxx::aaa という感じでネームスペースやクラスを指定する?
        ・・のかなと思ってやってみたら次のようなエラーが
        
        > Expression cannot be implemented with read/access watchpoint.
        
        ・・・出来ないのかな
        ※ privateとかpublicとかそういう問題ではないらしい

    

関数を呼ぶ
    call xxx

ステップ実行
    continue n  : n個分のブレークポイントを無視
    step n      : n行進む(関数の中まで入る)
    next n      : n行進む(関数の中には入らない)
    finish      : 現在の関数が終了するまで
    until       : ループ抜けるまで


TODO:分かったら書く
    関数呼び出しの最初と最後を標準出力に書き出す
    
    → ここの記事がそれっぽい
        ftrace
            http://dsas.blog.klab.org/archives/51025093.html
            http://dsas.blog.klab.org/archives/51024395.html
        hogetrace
            http://d.hatena.ne.jp/yupo5656/20071008/p1
        hogetraceから、tracefという名前に変更したらしい
            http://binary.nahi.to/tracef/
            
            インストール
                rpm -ivh http://binary.nahi.to/hogetrace/libdwarf-20070703-3.i386.rpm
                rpm -ivh http://binary.nahi.to/hogetrace/tracef-0.16-1.i386.rpm
            
            ※ libdwarf が必要
                rpm -ivh ftp://ftp.sourceforge.net/pub/sourceforge/o/op/openss/libdwarf-20060614-1.i386.rpm
    
    
    
    


最初から引数を渡したい
    gdb --args program --foo --bar


参考: tips
    http://0xcc.net/blog/archives/000126.html


実行時にセグメンテーション違反が出たときにバックトレースを出すように設定
    # export LD_PRELOAD=/lib/libSegFault.so
    
    # と打ってからセグメンテーション違反を起こすプログラムを実行(-gオプションでコンパイルしてあるもの)
    # すると、セグメンテーション違反が発生したときにバックトレースが出てくれる。
    
    → catchsegv コマンドを使った方が見やすい
    
        catchsegv xxxx
    
    ※ と、ここに書いてあった → http://0xcc.net/blog/archives/000067.html


任意の場所でバックトレースを出す (Javaでいうe.printStackTrace) 
    // 上の方でインクルードしておく
    #include <execinfo.h>
    
    // このコードを挟む
    void *trace[128];
    int n = backtrace(trace, sizeof(trace) / sizeof(trace[0]));
    backtrace_symbols_fd(trace, n, 1);
    
    → これだとバイナリ名とアドレスだけしか出てこないので、
        次のようにすると関数名や行番号が出るようになる。
    
        xxxx | egrep -o '0x[0-9a-f]{7}' | addr2line -f --demangle -e xxxx  # xxxx は実行ファイル名
    
    → それでも見づらいので、自前で作ったスクリプト demangle_backtrace.rb に渡すようにした
            
        xxxx | demangle_backtrace.rb
        
        ※ http://homepage2.nifty.com/takaaki024/tips/programs/ruby/devtool/demangle_backtrace.html


実行時に使われているダイナミックリンクライブラリを知りたい。
    export LD_DEBUG=libs
    
    と打ってからプログラムを実行。

    

「アボートしました」で落ちるときに、どこで落ちてるかしりたい。

    ⇒ 「アボートしました」は Segmentation Faultと違って、
        プログラムからわざわざ abort() を呼んだ結果なので、
        abort() をよんでるところ全てに printf, fflush すれば
        そのうち特定できると思う。



GDBリモートデバッグ

(1) 実行ファイルがある方の環境
    
    cd /xxx/xxx
    gdbserver 0.0.0.0:5555  testprogram testdata.dat


(2) 解析する方の環境

    arm--linux-gnueabi-gdb /home/takaaki/work/testprogram.nostrip   # stripしていないバイナリ
    
    (gdb) set sysroot /xxx/xxx              # 実行ファイルの置いてあるディレクトリを指定
    (gdb) target remote 192.168.x.x:5555    # gdbserverを起動しているマシンのIPを指定
    (gdb) c                                 # 実行




straceコマンド
    
    全部出力する
        strace ./hello > /dev/null
    出力を open,read,write,closeのみに限定
        strace -e trace=open,read,write,close ./hello > /dev/null
    




パフォーマンス測定、コールグラフを見る


google-perftools

# インストール
yum install google-perftools google-perftools-devel  # ← pprofコマンド
yum install graphviz     # ← 画像の出力用のもの。dotコマンドというのが入る

# コンパイル時に /usr/lib/libprofiler.so をライブラリパスに含める
#  ※ gccのオプションに -lprofiler
gcc -lprofiler .....

# 実行前に環境変数 CPUPROFILE を設定する
export CPUPROFILE=prof.out

# プログラムを実行
./test01

    → こんな行が出る
        PROFILE: interrupts/evictions/bytes = 5/0/188

# 結果の解析
pprof ./test01 prof.out

    → 対話画面になる
        (pprof) top
        (pprof) help  とか

# 画像を表示する
pprof --dot ./test01 prof.out > prof.dot
dot -T png prof.dot > prof.png



※ 出てきたコールグラフの見方

                |
                | [呼び出し回数]
                ↓
    ┌────────────┐
    |  [クラス名(あれば)]    |
    |  [メソッド名]          |
    |     [local time]       |
    |  of [cumulative time]  |
    └────────────┘
    
    local time      : 関数内での実行時間(サンプル数)
    cumulative time : 呼び出し先の時間も含めた時間

    ※ local time と cumulative time が同じ(関数呼び出し
        がないという状態)であれば1行にまとめられる
    ※ 「%」表示は、全サンプル数に対する割合
    ※ サンプル数は、1秒あたり100サンプル (デフォルト)
    

    http://code.google.com/p/google-perftools/wiki/GooglePerformanceTools



gcc

    gcc -pg test.c
    ./a.out
    gprof --brief


graphvizとコールグラフ

    http://www.ibm.com/developerworks/jp/linux/library/l-graphvis/index.html




valgrind というのが出すコールグラフは視覚的に工夫されてるらしい

    http://kcachegrind.sourceforge.net/cgi-bin/show.cgi


oprofileでもcall treeが見れるらしい

    



ソースを読むのに便利なものを探す


ctags (タグ)

インストール
    yum install ctags

tagsファイルの作成
    ctags *.cpp
    とか打つとカレントディレクトリに tagsファイルが作成される
    
    ctags -R : 再帰的に。

    C-] : 関数の定義に行く
    C-t : 戻る

vimで
    gd
    gD : 関数の定義に行く

TODO:関数の一覧とか出せる?


拡張子を追加で指定する
    ctags --langmap=PHP:.inc -R



gtags

    GNU global という名前

    このサイトが分かりやすい
        → http://uguisu.skr.jp/Windows/gtags.html

インストール
    yum install global    ※gtagsではない

gtagファイルの生成
    # ソースコードのあるトップのディレクトリで次のように打つ
    gtags -v

    → 以下のファイルが出来る
        GTAGS
        GRTAGS
        GPATH
        GSYMS
        
    # HTML化する
    htags -saF


vimで
    :global func01     # 検索
    :global -r func1   # 参照元一覧を表示

Emacsで
    M-x gtags-mode
    → そのうち試してみる

コマンドラインで
    global -t func01  # 定義を探す
    global -r func01  # 参照元表示
    global -x func01  # 詳細表示
    global -a func01  # 絶対パス表示


doxygen

# 設定ファイルの生成
doxygen -g

    → Doxyfile というファイルが作成される。

        OUTPUT_LANGUAGE = Japanese
        EXTRACT_ALL = YES
        INPUT = .
        FILE_PATTERNS = *.cpp
        HAVE_DOT = YES
        CALL_GRAPH = YES
        
        RECURSIVE = YES
        HTML_OUTPUT = html_doxygen

        
        OPTIMIZE_OUTPUT_FOR_C  = NO
        BUILTIN_STL_SUPPORT    = NO
        CPP_CLI_SUPPORT        = NO
    
    → うまくいかない

※ Windows版のGUIフロントエンドがあった
    http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc


プロファイラ

    VTune Performace Analyzer
        http://www.intel.com/cd/software/products/ijkk/jpn/vtune/index.htm
    AMD CodeAnalyst
        http://developer.amd.com/cawin.jsp
        紹介
            http://lucille.atso-net.jp/blog/?p=188
    google perftool (pprof)
        http://cell.fixstars.com/ps3linux/index.php/Google-perftools%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6CPU%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E3%81%A8%E3%82%8B
    gprof
        http://www.linux.or.jp/JM/html/GNU_binutils/man1/gprof.1.html
    oprofile
        http://cell.fixstars.com/ps3linux/index.php/OProfile%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6CPU%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E3%81%A8%E3%82%8B
        
        使い方が良く分からない。環境変数の設定とかが要る?
            # opcontrol --start
            # ./test
            # opcontrol --stop
            # opreport -l
    
    valgrind (callgrind)
        http://kcachegrind.sourceforge.net/cgi-bin/show.cgi
        
        コールグラフの視覚化されたのが見やすいんだとか。
        
        インストール
            yum install valgrind


ビルドシステム

    Automakeのドキュメント
        http://www.bookshelf.jp/texi/automake-ja/automake-ja_toc.html#SEC_Contents




リンカとかローダとか

    共有ライブラリ
        http://www.linux.or.jp/JF/JFdocs/Program-Library-HOWTO/shared-libraries.html




未整理


Q. gccでC++のプログラムをコンパイルしたい

A.
    方法1:  g++ -o aaa aaa.c
    方法2:  gcc -x c++ -o aaa aaa.c  ← うまくいかないときがある
    
    オプションつけずに次のようにやるとエラーが出る
        gcc -o aaa aaa.c
        
        In function '__static_initialization_and_destruction_0(int, int)':
            undefined reference to 'std::ios_base::Init::Init()'



Q. gcc -x c++ -o aaa aaa.cpp とやったら次のエラーが出た

    gcc: error trying to exec 'cc1plus': execvp: そのようなファイルやディレクトリはありません

A.
    gcc-c++ をインストールすればいい。
    
    yum install gcc-c++
    
    ※ gcc-objc とか gcc-objc++ とかは Macのやつかしら。


Q. makeしたら次のようなエラーが出る
    「g++: : そのようなファイルやディレクトリはありません」と出る
    
    ※ 通常は ":" と ":" の間にファイル名が出るんだけど、ファイル名が出ない。
    ※ たぶんコンパイルに失敗したファイルがあって、
        そのファイルの *.o がみつからない、みたいな状況のような気がする。
    ※ それ以前にコンパイルに失敗してるっぽいのに警告やエラーが出ないのが問題

A. 
    NFSでマウントしているディレクトリでビルドしたときに起きた問題。
    ローカルのディスク上でビルドしなおしたら正しくエラーが出るようになった。
    んむー。



実行ファイルのヘッダ情報?を見る

    readelf -h xxxxx



パスを設定したのにコマンドが見つからないとき

    rehash


シンボルとかデバッグシンボルとか

    ・-g でつくのは 「デバッグシンボル」 → 「シンボル」というのとは別
    ・「シンボル」を削除するには strip コマンド
        → なんでこんなことする必要があるのかと思ったら、
            組み込みとかでサイズ制限がある場合にサイズを減らすためにやるらしい
    ・nmコマンドで見れるのは「シンボル」の方


拡張子メモ
    ※ よくある「拡張子辞典」のサイトで載ってなかったりするので、まとめておく
    ※ 知ってる人には当たり前みたいな感じなのかなあ・・

    c, cpp, h, java, class, so, a, pl, rb, jar, war, js, vbs, html, php, sh, xml : 略
    png, tiff, swf, mp3, mpeg, mov, jpg, jpeg, at3, aac : 略

    pro      : Qtのプロジェクトファイル (qmakeが読む)
    pri      : ?
    qrc      : Qtのリソースコレクションファイル (qmake)
    
    mk       : makefile用
    
    m4       : m4マクロ
    
    vcproj   : Visual C++のプロジェクトファイル
    exp      : Visual C++でDLL作成するときの中間ファイル
    sln      : Visual C++のプロジェクトファイル
    
    idl      : インターフェース定義ファイル?
               Java用なのかC++用なのか分からないでいたら
               CORBAという、言語に依存しない仕様のものらしい。
               ※ http://www.techscore.com/tech/CORBA/index.html
    
    aidl     : Android Interface Definition Language
    order    : (Android) 関数名がずらーっと書いてあるけど何に使うファイルだろう
    
    pm       : Perlモジュール?
    
    mm       : Macの xcode? で使うファイルらしい。Objective-C
    m        : これもそう?
    mm       : ※ FreeMind..
    xcconfig : XCode用の設定ファイル
    pbxproj  : XCode用の何か
    lproj    : Cocoaのローカライズ用のディレクトリ
    nib      : CocoaのGUIのレイアウトファイル?
               ※ http://developer.apple.com/jp/Documentation/Cocoa/Conceptual/CocoaFundamentals/CoreAppArchitecture/chapter_7_section_8.html#//apple_ref/doc/uid/TP40002974-CH8-SW46
    jnilib   : MacでJNIするときに必要なファイルらしい
    
    
    m        : ?  ※SVG関連のファイルで、フィルタの定義をしている見たいな記述があるけども
    
    cg       : NVIDIAのシェーダ Cg のソース
    
    
    flv      : Flash Video?
    
    bkl      : wxWidgets用の何か
    bks,bkl  : ※ Beckyのバックアップファイル
    
    o        : gccでビルドした時のオブジェクトファイル?
    P        : ?




Q.
    ソースを呼んでいて、この関数がどこから呼ばれてるか探すのがめんどくさい。

A.
    (1) 名前が一意に定まるなら ctagsとか grep で。
    (2) VTuneとかgoogle-perftoolsとかでコールグラフが出せればそれで見る。
    (3) その関数をコメントアウトしてビルドしてエラーになった部分が呼んでる箇所。。
    
    → init() とか、いろんなオブジェクトに用意されてそうな名前の関数を探すときに (3) をやったりする。
    
    → という風にやってたけど、上の方にある「backtrace」を使うのが分かりやすい



Q. Makefile で printf みたいなことがしたい

A.
    dummy := $(shell echo XXXXXXX 1>&2)




valgrind
    
    不正なメモリアクセスをチェックする  ← Segmentation Fault(SIGSEGV)が出てるけど何でなのか分からないときに重宝
    メモリリークをチェックする
    
    valgrind xxxxxx  # xxxxxx は解析したいプログラム名
    
    次のようなメッセージが出る
        Conditional jump or move depends on uninitalised value(s)  ← 初期化してない領域へのアクセス
        Invalid read of size 1                                     ← free済みの領域へのアクセス



 UNIXプログラミングの道具箱 から

    TODO: 7章「CUnit」、8章「CppUnit」を読んでないので読む
    TODO: 9章「GDB」の Emacs連携の部分と11章「gprof」の「パフォーマンス改善」のところは手を動かして試してみる


make

    依存関係をみて更新が必要なファイルだけをビルドするためのもの(ビルド時間を短縮するためのもの)。
    make コマンドを実行すると Makefile の中の設定に従ってビルドが行われる。
    
    make コマンドのオプション
        -f : 「Makefile」以外の名前のファイルを指定する。「 make -f aaa.mk 」
        -k : エラーが発生しても途中で止めずに進める。 ※ -k ではなく -i な処理系もあるとか
        -n : コマンド名の表示のみ。コマンドの実行を行わない。
    
    Makefile の書式
        書式:
            ターゲット [...] : [依存コンポーネント [...]]
                コマンド
        
        例1: 1個のソースファイルから
            hello: hello.c
                cc -o hello hello.c
        
        説明1:
            ターゲット        : 生成される実行ファイル(またはライブラリ)。
            依存コンポーネント: ソース(*.c)またはライブラリ(*.o)。複数の場合はスペース区切り。
            コマンド          : ビルドするためのコマンド。行頭はタブ。
        
        
        例2: 複数のソースファイルから
            sample: sample1.o sample2.o sample3.o
                cc -o sample sample1.o sample2.o sample3.o
            
            sample1.o sample1.c sample1.h
                cc -c sample1.c 
            
            sample2.o sample2.c sample2.h
                cc -c sample2.c 
            
            sample3.o sample3.c sample3.h
                cc -c sample3.c 
        
        説明2:
            タイムスタンプを見て、変更のあったファイルに依存してるターゲットのみビルドするようだ。
            ※ じゃあ、ビルド中にソースファイルを変更したとすると、ソースが変更されてないように見なされたりする?
            
            最初に記載されているターゲットが作成しようとする
                → そのために必要な sample1.o, sample2.o, sample3.o が作成される
        
        
        例3: 仮想ターゲット
            all:sample     ※ : のあとにスペースを入れない
            
            ...
            
            clean:
                rm -f sample sample1.o sample2.o sample3.o
                rm -f *~
            
        説明3:
            上の all とか clean みたいに、ファイルを生成しないターゲットを「仮想ターゲット」というらしい。
            
            最初に記載されたターゲットでもなく、依存関係にも記載されていないターゲットは、実行されない。
            明示的に指定するには、make の引数で「 make clean 」という感じで指定する。
            
            作成したいターゲットを先頭に書きたくない場合(とか生成したいファイルが複数ある場合?とかマクロを設定する場合?)には
            「 all:sample 」という感じで仮想ターゲットを記載する。
        
        
        例4:マクロ
            CC=cc
            CFLAGS=
            
            hello: hello.c
                $(CC) $(CFLAGS) -o hello hello.c
        
        説明4:
            マクロ
                代入 : AAA=xxx
                追記 : AAA:=xxx
                参照 : $(AAA)
                
                この環境変数 AAA みたいなのを「マクロ」という。
                CC とか CFLAGS とか、お決まりの名前がありそうだ。
            
                ※ 「 = 」とか「 := 」の前後にスペース入るのはOK。
                
                ※「追記」はちょっと変なルール。追記なのに自分自身を書く必要がある。
                    
                    LS =  ls
                    
                    と定義したとして、
                    
                    ○ LS := $(LS) -l   # => ls -l
                    × LS := -l         # => -l    (上書きされちゃう)
                    × LS =  $(LS) -l   # => エラー:「 *** 再帰的変数 `LS' が(最終的に)それ自身を参照しています.  中止.」
                    
                    という感じ
                
                ※ make の引数で指定することも可能 :「 make CC=gcc 」
                
            特殊マクロ
                コマンド行で使えるもの
                    $@  : 現在のターゲット名
                    $?  : $? ターゲットよりタイムスタンプの新しい依存コンポーネント
                
                どこでも使えるもの
                    $$  : 文字 "$"
                
                拡張子ルール内で使えるもの
                    $<  : ソースコンポーネント名
                    $*  : コンポーネントのファイル名から拡張子を取り除いたもの
            
            デフォルト値の設定してあるマクロ
                CC
                CFLAGS
                MAKE
                ・・他にもある?
        
        
        例5:拡張子ルール
            all:sample
            
            sample1.o: sample1.c sample.h
            sample2.o: sample2.c sample.h
            sample3.o: sample3.c sample.h
            
            sample: sample1.o sample2.o sample3.o
                $(CC) $(CFLAGS) -o sample sample1.o sample2.o sample3.o
            
        説明5:
            これで動くのは、次のようにデフォルトで設定されているから。らしい。
            
            .c.o:
                $(CC) $(CFLAGS) -c $<
            
            「.c から .o の拡張子を生成するときは、このコマンドを使う」という意味のルール。
            こういうルールを「拡張子ルール」という。
            
            ※ ここで使える拡張子は「拡張子リスト」に設定してあるものでないといけない
                # うーむ。こっちはそのまま追記されるのか。。
                
                .SUFFIXES:                # 空にする
                .SUFFIXES: .o .c .cpp .h  # 書き換える
        
        
        例6:複数ディレクトリ
            SUBDIRS = sub1 sub2 sub3
            
            all:
                for d in $(SUBDIRS) ; do cd $$d ; $(MAKE) ; cd .. ; done
            
            install:
                for d in $(SUBDIRS) ; do cd $$d ; $(MAKE) install; ce .. ; done
        
        
        その他の文法
            インクルード     : include ファイル名
            コメント         : #
            行を分けたいとき : 行末に 「 \ 」
            コマンド行の先頭 : 「 - 」をつけるとエラーを無視。「 @ 」をつけるとコマンド名を表示しない。
            
            同じターゲットを複数に分ける : 区切りを「 :: 」とすると、1つのターゲットに複数のコマンドを定義できる
                $(LOGFILE):: test1
                    ./test1 >> $(LOGFILE)
                    
                $(LOGFILE):: test2
                    ./test2 >> $(LOGFILE)
        
        慣用表現?
            NULL=
            OBJECTS=\
                sample1.o \
                sample2.o \
                sample3.o \
                $(NULL)


Autoconf
    
    概要:
        configure
            コンパイルする環境に応じた Makefile や環境設定用のヘッダファイルを自動生成するスクリプト。
            使われ方:
                ./configure
                make
            
        Autoconf
            configure スクリプトを生成するツール
            configure.in, Makefile.in, xxx.h.in というファイルが入力。
        
        Automake
            Makefile.in を生成するツール(下記 (5))。
            Makefile.am というファイルが入力。
        
        ※ install コマンド
            ファイルをコピーし、その属性を設定するコマンド。
        
    
    手順:
        (1) Makefile を作成する
        
        (2) autoscan コマンドを実行 ⇒ 「 configure.scan 」という雛形が作成される
        
        (3) 「 configure.scan 」を「 configure.in 」にリネームして編集
            configure.in ファイル内の文法
                dnl ...         : コメント(「Delete through NewLine」の略なんだとか)
                AC_INIT(xxx.c)  : コンパイルするツリーの中の特徴的なファイルのファイル名を指定(・・?)
                AC_OUTPUT(xxx)  : ここで指定したファイル名のファイルが出力される(xxx.in ⇒ xxx)
                
                AC_PROG_CC      : Cコンパイラがあるかどうかチェック
                AC_PROG_INSTALL : install コマンドがあるかどうかチェック
                
                AC_CONFIG_HEADER(aaa.h) : 環境によって変えたいヘッダファイルを指定
                AC_CHECK_HEADER(xxx.h)  : 指定したヘッダファイルがあるかどうかチェック
        
        (4) autoconf コマンドの実行 ⇒ 「 configure 」スクリプトが作成される。
            ※ configure スクリプトは シェルスクリプトで書かれている
        
        (5) 「 Makefile 」を「 Makefile.in 」にリネームして、
            自動検知された値に置き換えたい部分を修正する
            
            CC=@CC@
            CFLAGS=@CFLAGS@
            ...
            
            ※ ここで参照可能な「出力変数」は以下のもの(意味は p.89 参照)
                bindir, configure_input, datadir, exec_prefix, includedir, infodir,
                libdir, libexecdir, localstatedir, mandir, oldincludedir, prefix, sbindir,
                sharedstatedir, srcdir, sysconfdir, top_srcdir,
                CC, CFLAGS, CPPFLAGS, CXX, CXXFLAGS, FFLAGS, DEFS, LDFLAGS, LIBS
            
            ※ 配布ファイル作成するときのために、不要ファイル削除用のルールを作っておく
                clean:
                    rm -f $(TARGETS)
                    rm -f *~
                    
                distclean: clean
                    rm -f Makefile config.status config.cache config.log
        
        
    場合によって必要なこと
        ・ install-sh (installコマンドが無いとき用のスクリプト)を
            Autoconf の配布ファイルの中からコピーする。
            ※ AC_PROG_INSTALL を指定している場合のみ
        
        ・ config.h.in
            AC_CONFIG_HEADER(config.h)
            AC_CHECK_HEADER(utmp.h)
            と configure.in に指定した場合の話。
            
            config.h.in に、「 #define HAVE_UTMP_H 0 」とか「 #undef HAVE_UTMP_H 」とか書いておくと
                utmp.h がある場合、「 #define HAVE_UTMP_H 1 」となって
                utmp.h がない場合は「 #define HAVE_UTMP_H 0 」とか「 /* #undef HAVE_UTMP_H */ 」
                と、(configureによって)書き換えられる。
            
            config.h.in の中では
                #if HAVE_UTMP.h
                #include <utmp.h>
                #else
                ...
                #endif
                という感じに書く。

    応用(この辺は必要になったらちゃんと読もう。いまはキーワードのみ。詳細: UNIXプログラミングの道具箱 の p.93〜)
        出力変数を手動でセットする
            XX1="hello"
            AC_SUBST(XX1)
                ⇒ Makefile.in では「 @XX1@ 」という風に参照出来る
        
        Cプリプロセッサシンボルをセットする
            AC_DEFINE(XX2, 10)
            AC_DEFINE_UNQUOTED(XX2, `...`)   ※ バッククオートとか ${環境変数} とか入れたいとき用
            
                ⇒ config.h.in には「 #undef XX2 」という風に記載する
            
        プログラムやファイル検出
            AC_CHECK_PROGS
            AC_PATH_PROGS
            AC_CHECK_FILES
            ※ それぞれ複数形と単数形の両方ある。複数の場合の引数はスペース区切り。 
        
        Cコンパイラの特性検出
            AC_CHECK_SIZEOF(型名, cross-size)
            AC_C_BIGENDIAN, AC_C_CONST, AC_C_INLINE, AC_C_CHAR_UNSIGNED, AC_C_LONG_DOUBLE, AC_C_STRINGSIZE
        
        ライブラリ関数検出
            AC_FUNC_XXXX
            HAVE_XXXX
            AC_REPLACE_FUNCS
        
        ライブラリ検出
            AC_CHECK_LIB
            AC_HAVE_LIBRARY
            AC_SEARCH_LIBS
        
        ヘッダファイル検出
            AC_EGRREP_HEADERS, AC_TRY_RUN, AC_CHECK_TYPE,
            AC_DECL_SYGLIST, SYS_SIGLIST_DECLARED
            AC_DIR_HEADER, DIRENT, SISNDIR, SYSDIR, NDIR
            AC_HEADER_DIRENT, HAVE_DIRENT_H, HAVE_SYS_NDIR_H, HAVVE_SYS_DIR_H, HAVE_NDIR_H
            AC_HEADER_MAJOR, MAJOR_IN_MKDEV, MAJOR_IN_SYSMACROS
            AC_HEADER_STDC, STDC_HEADERS
            AC_HEADER_SYS_WAIT, HAVE_SYS__WAIT_H
        
        構造体定義検出
            AC_HEADER_STAT, STAT_MACROS_BROKEN
            AC_HEADER_TIME, TIME_WITH_SYS_TIME
            AC_STRUCT_ST_BLKSIZE, HAVE_ST_BLKSIZE
            AC_STRUCT_ST_RDEV, HAVE_ST_RDEV
            AC_STRUCT_TM, TM_IN_SYS_TIME
            AC_STRUCT_TIMEZONE, HAVE_TZNAME
        
        型定義検出マクロ
            AC_TYPE_GETGROUPS, AC_TYPE_MODE_T, AC_TYPE_OFF_T, AC_TYPE_PID_T,
            AC_TYPE_SIGNAL, AC_TYPE_SIZE_T, AC_TYPE_UID_T
        
        高度な自動検出方法
            AC_EGREP_CPP, AC_EGREP_HEADER, AC_TRY_RUN
        
        独自オプション(--with-xxx)
            AC_ARG_WITH(...)



GDB

    (1) デバッグ情報入りのバイナリをコンパイル(-g オプションを付ける)
        
        gcc -o foo -g foo.c
    
        ※ デバッグ情報関連のコマンド
            strip      : デバッグ情報を除去(除去するのはサイズを小さくするため)
            install -s : インストール時にデバッグ情報を除去
            nm         : デバッグ情報を表示する
            
    
    (2) GDBの起動
    
        gdb foo
    
    
    (3) GDB実行中のコマンド
        
        (gdb) quit
        (gdb) set args a b c
        (gdb) run
        (gdb) list
        (gdb) list myputs        # myputs という関数定義へ(同じ関数名が複数ある場合は引数の型も指定)
        (gdb) list +20           # 20行うしろ
        (gdb) print s            # 変数 s を表示。(print は、p でもOK)
        (gdb) print /d s         # 変数 s を10進で表示。
        (gdb) backtrace          # スタックフレームを表示(呼び出し元の関数を辿ったもの) ※ where と同じ
        (gdb) frame 1            # スタックフレームの 1 番目へ移動
        (gdb) up                 # スタックフレームを 1 階層上がる
        (gdb) down               # スタックフレームを 1 階層下がる
        (gdb) break main         # 関数 main にブレークポイントを設定
        (gdb) next               # ブレークポイントで停止した状態から、次へ進める
        (gdb) break if i == 4    # 条件付きブレークポイント(i == 4 のときに停止する)を設定
        (gdb) jump 20            # 20行目に強制ジャンプ
    
    
    くわしく
        gdb コマンドのオプション
            gdb [オプション] [実行ファイル名 [コアファイル名 | プロセスID]]
            
                ・コアファイルを指定すると、落ちたプログラムの解析が出来る??
                ・起動中のプロセスをデバッグする場合は、プロセスIDを指定する。
            
            その他オプション:p.231
        
        .gdbinit
            .gdbinit ファイルをホームディレクトリか作業ディレクトリに置いとくと、
            そこに記述されたコマンドが実行される。
            同じような作業を繰り返している場合、毎回打つ手間が省ける。
        
        ファイル指定
            (gdb) file 実行ファイル名
            
            (gdb) core コアファイル名
            
            (gdb) exec 実行ファイル名            # 実行ファイルとシンボルファイルが分かれているとき用?
            (gdb) symbol シンボルファイル名      # というかそんなふうに作成出来るんだっけ?
            
            (gdb) attach プロセスID
            (gdb) detach
        
        シグナル
            (gdb) signal シグナル番号  # シグナルを送る
            (gdb) signal シグナル名
            
            (gdb) handle シグナル番号 処理...  # シグナルを受け取った際の処理
            (gdb) handle シグナル番号 処理...
                ※ print, noprint, stop, nostop, pass, nopass が指定できる
            
        ソースパス
            (gdb) directory ソースコードのパス  # ソースコードの検索パスに指定したパスを追加
            (gdb) show dir                      # 現在設定されている検索パスを表示
        
        ステップ実行
            (gdb) step        # 関数の中まで入って1ステップずつ実行
            (gdb) next        # 関数の中には入らず1ステップずつ実行
            
            (gdb) finish      # 関数の終了まで実行
            (gdb) return 値   # 関数の残りの処理を行わず関数を抜ける
            
            (gdb) continue    # 再開
            
                ※ これ、「ステップ・イン」、「ステップ・アウト」、「ステップ・オーバー」みたいな
                    VCの用語とマッピングしそうだ。整理しよう。
            
            (gdb) until 行    # 指定した行まで進む
            (gdb) jump 行     # 指定した行まで処理を飛ばす
        
        条件付きブレークポイント
            (gdb) break ... if 式
            (gdb) rbreak 関数名の正規表現
            (gdb) tbreak 行                 # 1回だけ停止して欲しいとき
            (gdb) watch 条件                # 条件を満たしたら停止
        
        ブレークポイントの管理
            (gdb) info break       # 一覧
            (gdb) delete 番号      # ブレークポイント番号を指定して削除
            (gdb) clear 行         # ブレークポイント位置を指定して削除
            
            (gdb) disable 番号     # 一時的に無効にしたい場合
            (gdb) enable 番号
            (gdb) enable once 番号 
            (gdb) enable del 番号
            (gdb) ignoree ブレークポイント番号 無視する回数
            
            (gdb) commands 番号    # 特定のブレークポイントで停止したときに実行するコマンドを指定する
            >[silent]
            >  ... コマンド ...
            >end
            
        変数の情報
            (gdb) info locals      # ローカル変数の一覧
            (gdb) info args        # 関数の引数情報を調べる
            
            (gdb) display 式       # 式の結果をブレークポイントに達するたびに表示する
            (gdb) undisplay 番号   # ※ 例えば「 display i 」とすれば i の値が毎回表示される。
            (gdb) disable disp 番号
            (gdb) enable disp 番号
        
        メモリの表示
            (gdb) x[/[繰り返し数][サイズ指定子][フォーマット指定子]] [アドレス] # ??
            (gdb) x/i $pc          # プログラムカウンタ = 次に実行する機械語 が表示される
        
        シンボル情報の表示
            (gdb) whatis シンボル  # 関数や変数の型を表示する
            (gdb) ptype シンボル   # whatis より詳しい情報(構造体の中身とか)
        
        変数の値の変更
            (gdb) print 変数名 = 式         # 値の変更。
            (gdb) set variable 変数名 = 式  # ※ 2つの違いは、結果が表示されるかされないかの違いだけ
        
        関数呼び出し
            (gdb) print 関数
            (gdb) call 関数
        
        機械語レベルの操作
            (gdb) disassenble 関数  # 逆アセンブル(機械語レベルのコードを表示)
            
            (gdb) stepi             # 機械語レベルでステップ実行
            (gdb) nexti
            
            (gdb) x $pc             # プログラムカウンタ  ← この4つの「汎用目的のレジスタ」は、値の変更可能。
            (gdb) x $fp             # フレームポインタ
            (gdb) x $sp             # スタックポインタ
            (gdb) p $ps             # プロセッサステータス
            
            (gdb) info registers    # レジスタの表示(上の4つより詳しい情報が出るが、変更不可)
        
        ヒストリ値
            print コマンド等で一度表示した変数は「 $番号 」で参照可能。
        
        コンビニエンス変数
            (gdb) set $変数名 = 値  # コンビニエンス変数に値をセット
            (gdb) show convenience  # コンビニエンス変数の一覧
                ※ 特殊なコンビニエンス変数 : $_, $__, $_exitcode, $bpnum
        
        ユーザ定義コマンド
            (gdb) define コマンド名      # ユーザ定義コマンドの定義
                ....                     # if, while が使える。end で終了。コマンド引数は $arg0 で参照。
            end
            
            (gdb) define hook-コマンド名 # あるコマンドが実行されたときに実行されるコマンド(hook)を設定する
                ....
            end
            
            (gdb) show user              # ユーザ定義コマンドの一覧(hookも含む)
            
            (gdb) document コマンド名    # ユーザ定義コマンドのヘルプ文字列を設定
               ヘルプ文字列              # ※ 自分たち用ライブラリとか作るときに必要?
            end
            
            (gdb) help コマンド名        # 上の document コマンドで設定したヘルプ文字列を表示
        
            (gdb) source ファイル名      # ユーザ定義コマンドを別ファイルに用意しておいてロードする
                                         # ※ もちろん .gdbinit に記述しても良い
            
            (gdb) # コメント             # コメント
        
        リモートデバッグ
            gdbserver 通信方法 コマンド名 [ コマンドの引数 ]
                                         # ※ 「通信方法」のところは「 ホスト名:ポート番号 」。
            
            (gdb) target remote 通信方法


DDD (Data Display Debugger)

    これは何?
        GDBのGUIのフロントエンドだそうだ。(この表現は冗長?)
    
    インストール
        yum install ddd
    
    実行
        ddd [実行ファイル [コアファイル|プロセス番号]]
    
    機能
        ボタンや右クリックの操作で gdb にある機能(ブレークポイントの追加とか、変数の表示とか)
        が出来るのが便利。
        
        あと
        ・「Data Window」というウィンドウにデータ構造が表示される
        ・ 配列を選択した状態で「Plot」ボタンを押すとグラフが表示される
            (・・はずなんだけど、gnuplot が意図したように起動してくれない、、、)


gprof

    (1) プロファイルコード入りの(?)バイナリをビルド(-pg オプションをつける)
        
        gcc -pg -o foo foo.c
    
    (2) 出来上がったバイナリを実行すると gmon.out というファイルが出来るので、
        gprof でテキストファイルに変換する。
        
        ./foo                            # => gmon.out が作成される
        gprof foo gmon.out > gmon.txt
    
    (3) 出力結果の見方
        
        call graph profile
            着目している関数が、
            ・どの関数から呼ばれたか
            ・呼び出された回数
            ・全体の実行に占める割合
            ・その関数からさらにどのような関数が呼び出されているか
            という情報が表示される。
            上が呼び出し元。したが呼び出されたもの。
            
        flat profile
            各関数の実行時間の
            ・全体に占める割合
            ・実行時間
            ・呼び出し回数
            などが実行時間順に表示される。
            
        Index by function name
            名前順に関数が並んでいるだけのリスト
        
        ※ .mcount は実行の計測を行なうための関数なので、無視して良い。



gcov

    これは何?
        カバレッジ計測用のプログラム。
        ソースファイルの、どの行が何回呼ばれたかを計測する。
        gcc に付属しているツール。
    
    手順
        (1) ビルドオプション -fprofile-arcs -ftest-coverage を付ける
        
            gcc -fprofile-arcs -ftest-coverage -o foo foo.c
        
        
        (2) 実行すると解析に必要なデータが作成される
        
            ./foo
                ⇒ foo.gcno, foo.gcda が作成される
        
        
        (3) 解析に必要なファイルの生成
        
            gcov foo.c
                ⇒「 Lines executed: xxx.xx % of xxx 」と表示され、foo.c.gcov ファイルが作成される。
            
            gcov -b foo.c
                ⇒ ブランチとコールについての情報が付加される。
        
        (4) foo.c.gcov ファイルを見ると、ソースコードと、行番号の左に実行回数が表示されている。
        
            ・ 実行回数: 各行番号の左に実行回数を表示
                          「 ##### 」と表示されていたら、その行は実行されていない
            ・ branch  : 分岐のところで何%がどっちに行ったか分かるようになっている
                          「never executed」 で1回も通ってない
            ・ call    : 関数呼び出しが戻ってきた割合を表示。
                          通常は 100% となる。


man

    man
        man コマンドの文書は nroff 形式で記載されたドキュメントを整形して
        ページャ(more とか less とか)に渡す仕組みになっている。
    
    roff
        文書表示用のシステム(nroff とか troff とか groff とか)。
        裏で使われてるということらしい。
    
    tips
        man -w xxx   # そのマニュアルがどこにあるかを表示
        
        man who | colcrt - > who.txt   # 画面ではなくファイルに書き出したいとき
            
            ※1「 - 」オプションはアンダーラインの行を消したい場合につける。
            ※2 col コマンドというのもある
    
    man の書き方
        p.312〜316


doxygen

    java でいう javadoc みたいなもの。
    必要になったら読もう。(p.319〜)




configure するときの環境変数

    CXX      : コンパイラ  (g++ とか)
    CXXCPP   : プリプロセッサ?(g++ -E とか)
    CPPFLAGS : Cプリプロセッサに渡すフラグ(pp は ++ ではない)(-I/usr/local/lib とか)
    LDFLAGS  : リンカに渡すフラグ(-L/usr/local/include とか)
    
    
    LIBS     : リンカ?に渡すフラグ(-ljpeg とか)
    



クロスコンパイル(クロスビルド)するときのメモ

(1) configure のオプションの確認

    cd xxxx
    ./configure --help
        
        # 関係ありそうな項目
        
        System types:
          --build=BUILD     configure for building on BUILD [guessed]
          --host=HOST       build programs to run on HOST [BUILD]
          --target=TARGET   configure for building compilers for TARGET [HOST]
        
        Some influential environment variables:
          CC          C compiler command
          CFLAGS      C compiler flags
          LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
                      nonstandard directory <lib dir>
          CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
                      you have headers in a nonstandard directory <include dir>
          CPP         C preprocessor
        
        
        --disable-xxxx とか
        --without-xxxx とか


(2) とりあえずビルドしてみる

    mkdir out
    ./configure --prefix=$PWD/out --host=arm-none-linux-gnueabi
        # arm-none-linux-gnueabi-gcc を呼んで欲しかったらこのように指定する
    make
    make install
        # prefix に指定したディレクトリ( out/ )にファイルが書き出される

    ⇒ 途中で「libaaaa がない」とエラーになったら、「libaaaa」を先にビルドする
    

(3) 必要だったライブラリをビルドしてみる

    cd ../aaaa
    mkdir out
    ./configure --prefix=$PWD/out --host=arm-none-linux-gnueabi
        # arm-none-linux-gnueabi-gcc を呼んで欲しかったらこのように指定する
    make
    make install

    ⇒ 途中で「libbbbb がない」とエラーになったら、「libbbbb」を先にビルドする
    ⇒ 以下 (3) を繰り返し


(4) 必要だったライブラリがうまくビルドできたら、できたライブラリをパスに指定する

    cd ../xxxx

    export CPPFLAGS="-I$PWD/../aaaa-1.2.3/out/include/ -I$PWD/../bbbb/out/include/"
    export LDFLAGS="-L$PWD/../aaaa-1.2.3/out/lib/ -L$PWD/../bbbb/out/lib/"
    export LIBS="-laaaa -lbbbb"
    
    mkdir out
    ./configure --prefix=$PWD/out --host=arm-none-linux-gnueabi
    make
    make install
    
    # 元に戻しておこう。
    # こうしとかないと
    # 「aaaa をビルドしようとして libbbbb が必要だったので bbbb をビルドした。
    #   bbbb のビルド時に libaaaa が無いと怒られた」みたいな状况になったりする。
    unset CPPFLAGS
    unset LDFLAGS
    unset LIBS
    
    ⇒ 以下 (3) と (4) を繰り返し



Makefile サンプル


PROGRAM = test_01
OBJS    = test_01.o

OPENCV_DIR = $(PWD)/../local/
OPENCV_INC = $(OPENCV_DIR)/include/opencv
OPENCV_LIB = $(OPENCV_DIR)/lib

CXX = gcc
CXXFLAGS = -g -O3 -I$(OPENCV_INC)
CXXLDFLAGS = -L$(OPENCV_LIB) -lcv -lcxcore -lhighgui -lcvaux -lml -lz -ljpeg

all:$(PROGRAM)

$(PROGRAM) : $(OBJS)
    $(CXX) $(CXXFLAGS) -o $@ $< $(CXXLDFLAGS)

clean:
    rm -f $(PROGRAM) $(OBJS) *~


※ 注意: 字下げは Tab で行う



「ここは違う」、「ここはこうするといいよ」等あったら下記フォームから連絡ください。
※ 何も来なさすぎて寂しいので、雑談とかグチのメールでも歓迎です。

お名前
e-mail
本文