☆gcc
◆コンパイル
_◇コンパイル例
-g デバッグオプションつきでコンパイル
例)
_ % gcc -g test.c
-o 出力ファイル名の指定
例)
_ % gcc test.c -o 出力ファイル名
※C++ソースのコンパイル
g++ -o hello hello.cxx
※libm.soを使うプログラム
$ gcc calc.c -lm -o calc
⇒-lオプションでライブラリをリンクする場合、ライブラリ名先頭のlibは除く
⇒-lオプションとライブラリ名の間に空白はいれない
⇒-lオプションをコンパイルするプログラム calc.cよろ前に書いてはならない
※gccのコマンドラインの原則
①関数を使う側が前
②関数を提供する側が後ろ
⇒main()のあるファイルを先頭、ライブラリを末尾に
_◇オプション
-g デバッグ情報を含める
-Wall
一般的な警告オプションをすべてつける
⇒コンパイルがノーエラーで成功しても実行できない、動作がおかしいといった状況がありえるので、なるべく-Wallをつけて警告まで確認すること
⇒ヘッダファイルのインクルード忘れなども警告される
-Dmacro
マクロmacroを文字列`1’として定義
-Dmacro=defn
マクロmacroをdefnとして定義
※コマンドライン上にあるすべての`-D’オプションは、どの`-U’オプションよりも前に処理される
-Umacro
マクロmacroの定義を取り消す。
※`-U’オプションは、すべての`-D’オプションの評価が終わったあとで評価されるが、どの`-include’オプションや`-imacros’オプションよりも前に評価される。
※アセンブラコードの出力オプション
-S (-O0と併用するのが良い)
_ .sなる拡張子のアセンブラファイルが出力される。
_ インラインの__asm__に相当するコードは
_ #APP
_ #NO_APP
_ で囲まれている。
-dumpversion
バージョン番号を表示する
-o 出力ファイル名
出力ファイル名をデフォルトのa.outから変える
-O1 (-O)
最適化。弱い。
-O2
最適化。普通。
-O3
最適化。強力、ただしコンパイラのバグを引き当てることもある。。。
-l
_ ライブラリ指定
_ 例) -lm
_ 数値演算ライブラリ libm.a もしくはlibm.soを指定
※C標準ライブラリlibc.aは、常にリンクされる。
⇒stdio.hをインクルードしなくても。よって、プロトタイプ宣言だけすれば標準ライブラリ関数を使うことは原理的に可能
-v
_ コンパイル、アセンブル、リンクのメッセージを表示
_ ⇒コンパイルの途中のパスなどをアカラサマに見たいときに使うとよい。
-E プリプロセスだけ処理する
-c アセンブルし、オブジェクトファイル .o を生成する
-M 依存関係の生成
⇒Makeファイルの末尾に追加。(depend)
-fexceptions 関数ポインタを扱う関数が例外を通過させられるようにする
-fPIC PIC(Position Independent Code)でコンパイルする
-fpic 同じくpicだが、プロセッサによってはGOT(Global Offset Table)サイズに制限がある。(x86では差はない)
⇒共有ライブラリを作成する場合は、PICでコンパイルする
-fverbose-asm
アセンブリ言語に変換する際に、いろいろコメントで情報を出力する
-fomit-frame-pointer
フレームポインタを使用しないバイナリを作る
_◇ビルドの流れ
①プリプロセス
プリプロセッサ文の処理
⇒ gcc -E でプリプロセスのみの結果を標準出力に出力させることができる
②コンパイル
*.c をアセンブラソース、*.sに変換する
⇒実体はccl
⇒gcc -S でFILENAME.cをコンパイルすると、FILENAME.sが残される。
③アセンブル
*.sからオブジェクトファイル *.o に変換する
⇒実体はas、gccパッケージでなく、binutilsである
⇒Linuxでは ELF が使われる
⇒gcc -c でFILENAME.cを処理すると、FILENAME.oが残る
④リンク
_◇Makefile / Configureスクリプト
※Makefileのオプションコントロール
CFLAGS = -Wall -O2 -g
※configure スクリプトによる Makefile生成
./configure CFLAGS=”-Wall -O2 -g”
_◇リンク
リンクするライブラリを指定する場合は、-lオプション
⇒オプションとライブラリ名の間にスペースは不可
⇒ライブラリ名の先頭の「lib」はとる
例)libm.so をリンクする場合
-lm
となる
※gccのコマンドラインでは、ソース、オブジェクト、ライブラリとも
-
- 関数を使う側が前
- 関数を提供する側が後
という制約に従ってならべなければならない
⇒main()を含むファイルが先頭、ライブラリが末尾
例)
gcc calc.c -lm -o calc
_◇拡張子
.c Cソース
.C C++ソース
.cc C++ソース
.cxx C++ソース
.m Objective-Cソース
.i プリプロセッサ処理済Cソース
.ii プリプロセッサ処理済C++ソース
.s アセンブリ言語ソース
.S アセンブリ言語ソース
.h ヘッダ
.o オブジェクトファイル
.a アーカイブファイル
◆gcc拡張機能
_◇ビルトイン関数
GCCは、標準的な関数のいくつかを「ビルトイン関数」として持つ。
最適化によってはソース記載のライブラリ関数でなく、ビルトイン関数を呼ぶコードが生成される。
printfはターゲット
absなどの∂関数
isalphaなどの文字種判定
strcatなどの文字列操作
⇒制御ソース gcc/guiltins.c
⇒Other built-in functions provided by GCC
※ビルトイン関数の抑止
-fno-builtin
※動作時の状況を知るビルトイン関数/コンパイル時にヒントを与えるビルトイン関数
void *__builtin_return_address(unsigned int LEVEL)
引数に0を与えると、現在の関数のリターンアドレスを与える。
LEVELに数値を与えることで、呼び出し元をたどることができる
void *__builtin_frame_address(unsigned int LEVEL)
フレームポインタのアドレスを与える。0指定で現在の関数。
int __builtin_types_compatible_p(TYPE1, TYPE2)
通常マクロ内でタイプを判定して適切な関数を呼び出すために用いる
TYPE __builtin_choose_expr(CONST_EXP, EXP1, EXP2)
意味的には CONST_EXP ? EXP1 : EXP2 だが、コンパイル時に決まる
マクロ内部でスイッチする場合などに使える
int __builtin_constant_p(EXP)
EXPが定数か否かを判定する。引数が定数なら最適化する場合などに使う
long __builtin_expect(long EXP, long C)
EXPの値がCになることが多いという前提でブランチ最適化する
void __builtin_prefetch(const void *ADDR, int RW, int LOCALITY)
ADDRにあるデータをキャッシュにプリフェッチする
RW=1なら書き込み、RW=0なら読み込みの予告
LOCALITY=0~3 0なら直ぐに不要になる~3当分使い続ける
※演算用
int __builtin_clz(unsigned int x);
引数の先頭何ビットが0かを返す count-leading-zero
_◇アトリビュート
書式)
関数プロトタイプ宣言 __attribute__((アトリビュート));
あるいは
_attribute__((アトリビュート)) 関数定義
例)
int foo(int n) __attribute__((アトリビュート));
__attribute__((アトリビュート)) int foo (int n)
{
…
}
※アトリビュート
-
- constructor
- destructor
- cleanup
- section
- used
- weak
- alias
- visibility
- stdcall
- cdecl
- fastcall
- regparm
- vector_size
- dllimport
- dllexport
- pure
- const
- malloc
- noreturn
- noinline
- always_inline
- nothrow
- format
- format_arg
- nonnull
- unused
- deprecated
- warn_unused_result
- no_instrument_function
- ※データに対するアトリビュート
- aligned
- packed
- common
- nocommon
- shared
_◇インライン関数
C++ での inline修飾子と同様に、C でも関数呼び出しのところでコード展開されるインライン関数がしようできる。※最適化を有効にしないとインライン展開されない。
宣言例)
static __inline__ void atomic_inc(atomic_t *v)_◇インラインアセンブラ
asm(“アセンブリコード”);
__asm__(“アセンブリコード”);__asm__(“アセンブラテンプレート”
: 出力オペレンド設定
: 入力オペランド設定
: アセンブラにより変更されるもの)
⇒メモリが変更されるときは、”memory”と書く※変数にレジスタを割り当てる
%ESP, %EBPなどを変数としてもアクセスできるようにすると変数で参照できる
例)
register void *stack_pointer asm(“%esp”);※IA-32で使えるレジスタには%を付けて表記する。
%eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp
%cs, %ds, %ss, %es, %fs, %gs
%eflags
%eip※gccのインラインアセンブラは、AT&T表記を使っており、転送方向は左から右で、インテル表記とは逆になる。
※データサイズは、ニーモニック末尾にキーワードを付加して表す。(インテル表記と異なる)
b byte
w word(2 byte)
l long(4 byte)※レジスタ以外のオペランド記法
①即値
$数値 数値は10進、もしくは0x30などと16進
②ラベル
$ラベル名
③直接メモリ参照
ラベル名
④間接メモリ参照
disp(base,index,scale)
必要でない要素は省略できる。例)
data(0, %edx, 4)
→data + %edx*4 + 0※ディレクティブ
gcc/gasのディレクティブは、”.”ではじまる。例).global _start
_startというラベルを外部から参照できるようにする。※インラインアセンブラの記法
①ニーモニックが複数あるときは\n\tで区切ることで記述可能例)
“subl %2,%0\n\t”
“subbl %3,%1”※文字列を続けて記述すれば1つの文字列リテラルとして連結されるのはCの文法事項!
②レジスタの対応
__asm__(“ニーモニック” : 出力レジスタ : 入力レジスタ);※レジスタとCの変数の対応づけは
“レジスタ名” (変数名)
または
“=レジスタ名” (変数名) … 出力レジスタ
とする。例)
“=&S” (d0)
変数d0を%esiに割り当てる(出力)
⇒最初の制約であれば、アセンブラテンプレート内では%0と参照できる“0” (src)
⇒srcの値を制約0に割り当てる(制約0は変数d0なので、%esiに代入される)※x86におけるレジスタ名は
m メモリアクセス
g 任意の汎用レジスタ
f 浮動小数点レジスタ
a EAX
b EBX
c ECX
d EDX
D DI
S SI
⇒AはPentiumではEAXだが、AMD64ではRAXとなる③レジスタの展開
%0~%9で、出力レジスタ、入力レジスタを展開できる。
既に”=a”のように定義されている出力レジスタについても、入力レジスタ中に”0″ (変数名)と書くことで、%xのどれになるのか決められる。④実行後、出力レジスタの内容が変数に格納される。
_◇インラインアセンブラ例#include <stdio.h> static inline int test(int dst, int src) { __asm__ __volatile__ ( "addl %1, %0\n\t" : "=&a" (dst), "=&b" (src) : "0" (dst), "1" (src) ); return dst; } int main() { int a, b; a=123; b=3; printf("BEFORE: %d, %d\n", a, b); a=test(a, b); printf("AFTER : %d, %d\n", a, b); }
_◇ラベルの参照
※通常ラベル
goto error;error:
※GCCではラベルをvoid *型変数に代入できる
参照は&&演算子void *label;
label = &&error;goto *label;
error:
◆サンプル
_◇コマンドライン引数
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; printf("argc=%d\n", argc); for (i=0; i < argc; i++) { printf("argv[%d]=%s\n", i, argv[i]); } exit(0); }
_◇thread
#include <stdlib.h> #include <unistd.h> #include <pthread.h> void *thread_function1(void *arg) { int i; printf("Tread 1, ID=%d\n",pthread_self()); sleep(1); for ( i=0; i<3; i++) { printf("Running thread 1.\n"); sleep(10); } return NULL; } void *thread_function2(void *arg) { int i; printf("Tread 2, ID=%d\n",pthread_self()); sleep(1); for ( i=0; i<3; i++) { printf("Running thread 2.\n"); sleep(11); } return NULL; } int main(void) { pthread_t thread1; pthread_t thread2; printf("Main thread, ID=%d\n",pthread_self()); sleep(1); if ( pthread_create( &thread1, NULL, thread_function1, NULL)) { printf("Creation Error, Thread 1.\n"); abort(); } if ( pthread_create( &thread1, NULL, thread_function2, NULL)) { printf("Creation Error, Thread 2.\n"); abort(); } if ( pthread_join ( thread1, NULL )) { printf("Join Error, Thread 1.\n"); abort(); } if ( pthread_join ( thread2, NULL )) { printf("Join Error, Thread 2.\n"); abort(); } exit(0); }
◆gcc実体
_◇コンパイラ
/usr/lib/gcc-lib
または
/usr/libexec/gcc
の
cc1◆CとC++のプログラムリンク
※注意点
生成されたオブジェクトに含まれるシンボル名
C 基本的に関数名か、関数名にプリフィックスをつけたもの
C++ ネームマングリングされ、所属の名前空間と型情報がシンボルに含まれる
⇒そのままではうまくリンクできない_◇C++からCの関数呼び出し
C++側で、extern “C”を付加したCの関数プロトタイプを読む
例)
extern “C” void dbg(const char *s);
⇒extern “C” の関数は引数の型の一致が検査されない
⇒シンボルに型情報が含まれていないため、不一致でもリンクは成功する※CとC++の両方で利用できるヘッダファイル例
#ifdef __cplusplus
extern “C” {
#endif
void dbg(const char *s);
#ifdef __cplusplus
}
#endif_◇CからC++の関数呼び出し
① C++側の関数をCリンケージでコンパイルする
② リンクはg++を使うヘッダ:
#ifdef __cplusplus
extern “C”
#endif
関数プロトタイプCPPプログラム:
extern “C” {
ここにC++側の関数本体を記述
}C側は普通にヘッダをインクルードして関数を呼び出す
※C++の関数は例外をCの関数側に漏らしてはならない
⇒プロセスが異常終了したりすることがある。
⇒C++の関数全体をtry/catchで囲む※関数ポインタを扱うCの関数にC++の関数を引き渡す場合、C++の例外の通過は抑制できない
⇒対象のCの関数を -fexceptions つきでコンパイルする◆Tips
_◇シンボル衝突
①通常の.oファイルをリンカでリンク
⇒リンカーがエラーを検出する②共有ライブラリ.soを作る場合
⇒リンカーがエラーを検出する③arで静的ライブラリを作成する場合
⇒arはアーカイバなのでシンボル衝突を検出しない
⇒リンク時には先に見つかったものがリンクされる④複数の共有ライブラリ(同じスコープ)に同じシンボルがある場合
⇒先に見つかったものが使われる_◇weakシンボル
weak定義 通常の定義が存在しない場合に大域シンボルを定義
⇒通常の定義があれば無視される※インライン関数は weak定義となる
⇒クラス定義内の関数定義はインライン関数とみなされる
⇒クラス定義は複数のファイルにインクルードされるので、リンク時に重複を取り除き、一つにまとめる必要がある_◇PIC(PositionIndependent Code)と非PIC
※非PICでは、再配置が必要なエントリが生成される
⇒コードサイズはPIC版より小さくなる
⇒書き換えが発生するため、他のプロセスとテキストが共有できない
(共有ライブラリにする利点がなくなる)※PICでは、標準関数呼び出しなどもPLT(Procedure Linkage Table)経由となり、再配置が必要な部分は減る
⇒スタートアップコードなどのため再配置は0ではないかもしれない_◇文字列リテラルへのポインタ最適化
static const char *ptr = “xxx”;
では最適化は効かない。
最初のconstはポインタ変数がconstだと言っているだけで、変数の指している先がconstなのかどうかは不明のためstatic const char* const ptr = “xxx”;
とすれば、ポインタの指している先も変化しないことになり、定数に対する最適化が効く。
_◇関数コールとスタック
※関数コール時
①引数をスタックに積む
②関数をコール(戻り番地がスタックに積まれる)
③まずフレームポインタをスタックにPUSH
④そのときのスタック値をフレームポインタの新値とする
FP+0に上位FPの値が入る
FP+4に戻り番地
FP+8~に引数
⑤自動変数で消費する分、スタックを下げる
⇒以降SPの指す場所以下が作業領域
⇒以降自動変数はFP-でアクセス_◇AMD64 ABI レッドゾーン
スタックポインタの下128バイトは、スタックフレームをアロケートしなくても使ってよいレッドゾーン_◇x86_64
整数やポインタは giant word で扱われる
⇒64ビット_◇x86_64関数呼び出し
①整数型、ポインタ型の引数
左からrdi, rsi, rdx, rcx, r8, r9に格納される
②浮動小数点型の引数
xmm0, xmm1,..
※引数の数が多い場合、残りはスタックに格納される_◇i386関数呼び出し
①原則、引数はすべてスタックに積まれる
関数に入ってきた時点:
スタックの先頭はリターンアドレスなので+4したアドレスに第1引数がある
関数に入ってきた直後:
前フレームのeBPがスタックにプッシュされてからeSPがeBPにコピーされる
eBP +0 -> old eBP
+4 -> return address
+8 -> 一番左の引数例)
(gdb) p *(int*)($ebp+8)
⇒第一引数を整数として表示(gdb) printf “%.2f\n”, *(float*)($ebp+32)
⇒スタック上の引数をfloatとして表示(gdb) x/40w $ebp
⇒$ebpから40ワードダンプ_◇i386での引数のレジスタ渡し
ファーストコール__attribute__((regparam(3)))
引数をeax, edx, ecxを使って渡す⇒最大3個まで. long long型の場合は、eax, edxペアで渡される
_◇C++での関数への引数わたし
※インスタンスの数だけ異なる領域が確保される
※メンバ関数の呼び出し時には、各インスタンスの情報もわたされる。
⇒プロトタイプ宣言の引数+1個の引数が渡される。
⇒デバッグ時には、各インスタンスのアドレスを確認する必要がある。※コンパイル後のELFファイルでは、関数名はマングルされる
⇒マングルドシンボルのデマングル
c++filtまたは、nm -cオプション☆linker, Object Format
◆静的ライブラリ
static libraryファイル名: *.a
※arコマンドで作ったアーカイブファイルで、多数のオブジェクトファイルからなる。
⇒リンク時にライブラリからとりだされ、プログラムと連結される。(ビルド時にライブラリがあれば、実行時にはライブラリのファイルは無くてもよい)◆共有ライブラリ
shared libraryファイル名: *.so
あるいはバージョン N をいれて
*.so.N⇒全体が一つのオブジェクトファイル
⇒ビルド時には、関数の存在チェックのみでリンクされない
⇒実行時にリンクローダがメモリの上でコードを結合する※リンクローダ
/lib/ld-linux.so.2
⇒実行ファイルを処理すべきリンクローダの名前は実行ファイル内に記述されており、カーネルがプログラムの起動時に処理する。※lddコマンド
ダイナミックリンクされた共有ライブラリを表示する※fileコマンド
スタティック/ダイナミック・リンクの判別できる◆ダイナミックロード
dynamic load※プラグインなどで使われる
※すべてのリンク作業を実行時に行う
ビルド時にはライブラリまったく不要⇒実行中にリンクローダをもう一度動作させる
⇒Linuxの場合のAPI
dlopen()◆ELF
Executable and Linking Format
バイナリフォーマット※Linuxで使用
◆COFF
Common Object File Format◆a.out
assembler output◆BFDライブラリ
Binary File Descriptor LibraryGNUのバイナリオブジェクトファイル取扱いライブラリ
バイトオーダー、32ビット64ビットのような扱いの違いを吸収する◆PEiD
ファイルアナライザ、パッカー判定ソフトhttp://peid.has.it/
◆リソースエディタ
実行可能ファイルのリソースセクションを編集するエディタResource Hacker
XN Resource Editor
◆リバースエンジニアリング
_◇メッセージボックスセオリー
CDチェックの解除などで使われていた
①エラーを起こして警告メッセージを表示させる。
②参照文字列の参照箇所を逆アセンブルコード上で検索
③エラー出力の前のエラー判定部分を書き換えて回避_◇メッセージトラップセオリー
☆AT&T表記 アセンブリ言語
◆as
_◇オプション
-al アセンブルリスティングを得る
>as -al xxxx.s
-als シンボルリストを含めたアセンブリリスト
-v バージョン表示
-o オブジェクトファイル名指定
-L ローカルシンボルもシンボルテーブルに保存
-I path
.include命令で検索するリストにpath追加◆IA32
_◇ニモニック形式
オペコード 第1オペランド, 第2オペランド
オペコード 第1オペランド, 第2オペランド, 第3オペランド※インテル表記と異なり、第1がソース、第2がデスティネーション
_◇データサイズ
オペコードの最後に以下の文字をつけてデータサイズを表す
b バイト
w ワード
l ロング(ダブルワード)_◇レジスタ表現、メモリ参照、即値
※レジスタ名には % をつける
例)
%eax※アドレス参照は()で囲む
例)
(%eax)※数値には先頭に $ をつける
例)
$123 十進123
$0x1F 十六進01Fh※変数名は文字列で表現
⇒変数名に$をつけると、変数のアドレスを意味する
⇒変数値には何もつけない_◇コメント
#以降_◇FPU命令表記例
① FLD mem
memの値をFPUレジスタトップ ST にプッシュ② FSTP op1
FPUレジスタトップSTの値をop1にポップするfstpl -8(%ebp)
③ FADD reg1, reg2
re1とreg2を加算してSTに保存faddp %st, %st(1)
◆TIPS
_◇データ型
※符号付き整数の範囲 ダブルワード
-2147483648
+2147483647※2のマイナスべき乗
-1 0.5
-2 0.25
-3 0.125
-4 0.0625
-5 0.03125
-6 0.015625
-7 0.0078125
-8 0.00390625※単精度実数
-3.40282e38
+3.40282e38※倍精度実数
-1.79769e308
+1.79769e308☆プロファイラ
◆gprof
_◇gprof計測原理
10ミリ秒毎のタイマ割り込み
関数へのenter/exitフックとカウント※旧仕様では基本ブロック毎のカウンタもあったが、現在は記録されない
⇒gcovによるカバレッジ_◇コンパイルと実行
gccに-pgオプションをつける。-gオプションでデバッグ情報をつけると行毎の実行集計も可能となる。
⇒最適化しすぎるとコードが消えて、集計できないこともある。
⇒gprof用のカウンタコードにより通常より遅くなる。例)
gcc -g -pg ファイル.c
⇒生成されたa.outを実行するとgmon.outというプロファイリング結果が生成されるgprof a.out
⇒a.outとgmon.outからプロファイル情報が出力される関数毎の所要時間
コールグラフ_◇その他のオプション
-l デバッグシンボルが存在すれば行毎の所要時間を出力する
-l -A -x ソースコードを表示し、行毎の所要時間を出力
-F 関数名 特定の関数のコールグラフを見る_◇出力ファイル名の変更
GMON_OUT_PREFIX環境変数◆gcov
☆ランタイムツール
◆trace
MS-DOSのシステムコール監視ツール◆Spy
MS-Windows APIの監視ツール◆strace
Unixのシステムコール監視ツール◆tcpdump
ネットワークパケットの監視と表示◆WinDump
ネットワークパケットの監視と表示◆Xev
X Window◆Spy++
MS-Windows◆WireShark
プロトコルアナライザ
Gerald Combs氏作、NIS社時代にEtherealと呼ばれていたが、氏がCACE Technology社に移って、Wireshark と名称変更した。
~0.99.0 Ethereal
0.99.1~ Wireshark_◇操作方法
①パケット取り込み
-画面左上の “List the available cpture interface” ボタンをクリック
-パケットを取り込むインタフェースを選択
②取り込み停止は赤い×印が付いた停止ボタンをクリック_◇パケットの保存
①”Save As…”により取りこんだパケットをファイルに保存する事も可能。また、保存したファイルを “Open” で再び Wireshark に取りこんで解析出来る。他のキャプチャツールとも互換性あり。☆ビルドプロセス
◆ビルドプロセスの典型例
1.設定
_ ソフトウエアオプションの設定
2.依存関係の作成
_ ⇒依存関係グラフを作成できる
3.ツールのビルド
_ 例)imake (X Window Systemの場合)
4a.実行可能ファイルのビルド
4b.ドキュメントのビルド
5.インストール展開_◇ビルド環境で必要な主要設定
①ソースファイルのリスト
②インクルードパス
③ライブラリパス
④リンクするライブラリ
⑤マクロの値◆tarballからのインストール手順
_◇概要
①tarballをダウンロード
②解凍
_ .tar.bz2の場合(bzip2)
$ tar xjf xxx.tar.bz2
_ .tar.gzの場合(gzip)
$ tar xzf xxx.tar.gz
③xxxディレクトリに入りconfigure
$ cd xxx
$ ./configure オプション
④make
$ make
⑤テスト
$ make test
⑥インストール
$ sudo make install_◇読むべきファイル
INSTALL
README
_◇configure
環境のチェックをして、Makefileを作成する。
環境依存の処理は、config.hのようなファイルを生成することもある。
自動生成された巨大シェルスクリプト
実際に必要なライブラリをリンクしてみるような操作を繰り返して環境を確かめる。※必要なライブラリがインストールされていない場合など
⇒警告を出して終了
⇒ライブラリのインストール
⇒configureのオプション指定※configureスクリプトのオプション
–help
_ 指定可能なオプション引数の一覧–prefix
_ configure共通オプション
_ ⇒インストールのベースディレクトリを指定する。
_ ⇒root権限がない場合など
_ –prefix=/home/ユーザ名/などと指定–enable-xxx xxx有効化
–disable-xxx xxx無効化
–with-xxx xxxでインストールベースディレクトリを指定。※環境変数
CC コンパイルに使うCコンパイラ
CFLAGS コンパイルオプション_◇make
※configureが用意されているようなOSSでのmakeによるビルド失敗は、Cソースのレベルでの環境依存の問題
※makeの結果をとっておくのに、teeを使うのも有効
$ make | tee make-all.log
_◇make check / make test
バイナリの動作確認
checkなのか、testなのかはINSTALLファイルなどを読むこと。_◇make install
必要ファイルのみを所定のディレクトリにインストールする
⇒その後ビルドに使ったソースツリーを削除してよい。⇒いきなりのルート権限でのインストールで思ってもいないパスにインストールされても困るので一般ユーザ権限で確認してからの方がよい
$ make -n install
◆autotools
_◇autoconf
autoconfによるプログラムの移植性の向上
① ビルドや実行の失敗
② 原因の追究
③ 新たなconfigureをautoconfで生成
④ 新たなconfigureで得られる情報をプログラムで使うように書き換え_◇automake
◆configure
GNU autoconfツールで生成された設定用スクリプトチェックされる要素
①使用可能なプログラム
②ライブラリ
③ヘッダファイル
④型宣言
⑤構造体
⑥コンパイラ特性
⑦ライブラリ関数
⑧システムサービス⇒システムプローブの結果はconfig.logに格納される
⇒最終的な設定に使われるのはconfig.status│ ┌───────────┐┌───────────┐┏━━━━━━━━━┓
│ │config.h.in││Makefile.in│┃configure┃
│ └┬──────────┘└┬──────────┘┗┯━━━━━━━━┛
│ │┌───────────┘ ┌────────┘
│ ↓↓ │
│ ┏┷┷━━━━━━━━━━━┓ │ ┌────────────┐
│ ┃config.status┠←──┴─┬→┤config.cache│
│ ┗┯━━━━━━━━━┯━━┛ │ └────────────┘
│ │ │ │ ┌──────────┐
│ │ │ └→┤config.log│
│ │ │ └──────────┘
│ ↓ ↓
│ ┌┴───────┐┌┴───────┐┌────────────┐
│ │config.h││Makefile││SOURCE-FILES│
│ └───────┬┘└─┬──────┘└┬───────────┘
│ └──┐│┌───────┘
│ ↓↓↓
│ ┏┷┷┷━┓
│ ┃make┃
│ ┗━━━━┛◆cmake
※ビルド設定を記述するファイル
CMakeLists.txt_◇文法
cmake_minimum_required (VERSION 2.6)
_ 要求されるcmakeツールの最低のバージョン番号project (prog1)
_ プロジェクト名、プログラム名、フォルダ名とは無関係add_executable (prog1 prog1.cc)
_ 生成する実行ファイルと、その元となるソースプログラム名を指定
⇒複数のプログラムを生成する場合は、add_executableを繰り返せばよい
⇒複数のソースからプログラムが生成される場合は、下のようにソースを複数とする。
add_executable (prog3 prog3.cc distance.cc)外部ライブラリとリンクする場合
例)libm
target_link_libraries(prog5 m)
⇒ライブラリ名の先頭のlibは省略ライブラリの探索
find_package(OpenGL)
⇒ライブラリ情報は/usr/share/cmake/Modules/の 下にある Findライブラリ名.cmake
⇒上記ファイル内で定数などが定義される。_◇変数とその設定
※CMakeLists.txt中にsetコマンドで設定する
set(CMAKE_BUILD_TYPE Debug)
⇒デバッグ/リリースの切り替え変数をDebugにセット※コマンドラインから指定
cmake -DCMAKE_BUILD_TYPE=Debug ._◇メッセージと変数の表示
例)
message(STATUS “${CMAKE_CXX_FLAGS_RELWITHDEBINFO”)_◇使用方法
cmake . で Makefileを作成
make でビルド_◇TIPS
①cmakeが生成するMakefileでは通常 .SILENT指定によりコマンドエコーが抑制される
⇒コマンドエコーをイネーブルにするには VERBOSEに値を入れる。
例)
make VERBOSE=1◆make
通常 Makefile を読み込んで動作するが、Makefile無しでも定型的な動作はする
例)
make hello
⇒デフォルトのCコンパイラCCが -o helloオプションで実行される。
⇒環境変数 CC や CFLAGSの値を参照するので、セットしておくとよい。
⇒ソースが.ccや.cppだと、デフォルトでg++が起動される(GNU make)_◇コマンドラインオプション
※makeを引数なしで実行すると、最初のターゲットを生成しようとする。※2番目以降のターゲットを生成させるためには、makeコマンドの引数としてターゲットを与える
-f filename
_ Makefileの代わりに別のファイルを使う-n
_ コマンド列を展開するが実行しない(ドライラン)
_ ⇒お試し実行(おおきなmakeファイルの理解に役立つ)-s
_ 黙って実行する-k
_ 途中でエラーが起きても中断しない-p
_ あらかじめ定義されている規則、マクロを展開表示。-t
_ ターゲットにタッチ-e
_ make内定義より環境変数を優先する※マクロはコマンドラインからも与えることがでる
例)
$ make A=y_◇コメント
# から行の終りまで_◇マクロ定義
マクロを定義することで、同じことを何度も書かないで済ませられる。マクロは行頭から以下のように書く。マクロ名 = 値
例)
CC = gcc
OBJ = sub.o
OBJS = f1.o f2.o f3.o例)展開
$(cc)
⇒参照は $ に続けてマクロの名前を { }で囲っても良い。※$(NAME)の形でよく使われるユーザ変数
SRCS ソース
INCLUDES ヘッダ
OBJS オブジェクト
LIBS ライブラリ
CC Cコンパイラ
CPP Cプリプロセッサ
CFLAGS Cコンパイラフラグ
LFLAGS リンカのフラグ
INSTALL インストールプログラム
SHELL コマンドシェル_◇Makeで使えるパラメータ表記
$@ その規則が生成しようとするターゲット名
$< ターゲットが依存しているファイルの一つ ⇒ターゲットの変換元ファイルの名前 $> ターゲットのすべてのソースのリスト
⇒GNU makeでは $^
$* ターゲット名から先行するパスと.ext除いたもの
$? 依存ファイルで更新されたもの(ターゲットより新しいファイルの名前)$$ $記号
_◇生成規則定義部
依存関係行 ターゲットの名前が書いてある行
コンポーネント
依存関係行のコロンの右側に羅列されてあるもの
(シェル)コマンド行依存関係は行頭から
生成コマンドは行頭にタブ文字入れる。
⇒複数のターゲットが同じものに依存する場合は、コロンの左側に複数のターゲットを並べて書いてもよい。
⇒1つのターゲットに対して複数の依存関係行を書けるが、コマンド行はそのうち一つにだけ。ターゲット: ソース コマンド
例)
a.out: sub1.o \
sub2.o
cc -o a.out sub1.o sub2.o
strip a.out
※.C や .Oなどからの生成規則はmakeが知っていることがあり、省略されるかもしれない。
※コマンドで処理されるファイルにソースで指定されていないファイル が含まれていたり、逆にソースで指定されているのにコマンドで処理されないファイルがあったりしても良い。makeはターゲットとソースのタイムスタンプを比較してコマンドを実行するかどうか決定するだけ。
ターゲット:
コマンド
などと、ソースを省略すると必ずコマンドが実行される。
_◇サフィックスルール
.サフィックス1.サフィックス2
生成コマンドが省略されているばあい、サフィックス1のファイルからサフィックス2のファイルが生成できることを示す。
例)
.c.o:
$(CC) -o $<
※すべての依存関係にビルドルールが付随していなくとも良い。
⇒ソースのいずれかがターゲットよりも新しければ、ターゲットを別のルールをつかって再ビルドする必要がある、ということを示す
_◇疑似ターゲット名
ターゲットは実際に生成されるファイルである必要はない。
例)
all, build ターゲットを全てビルドする
doc ドキュメントのビルド
depend 依存関係情報を生成
test ビルド後の回帰テストの実行
install インストール手順を実行
clean ビルド中に生成されたファイルの削除
_◇TIPS
②行の継続
行末の\で行エスケープ可能だが、\の後は改行文字であること。
cat -t -e Makefile
とすると[TAB]と[行末]を可読キャラクタで表示する。
③デフォルトの値の表示
(GNUのmakeなど)
$ make -p
(BSDのmake)
$ make -d g1
④ターゲット名
clean
生成ファイルのクリーンナップ
all
全てのターゲットを生成
_◇終了ステータス
コマンド成功で0、失敗でそれ以外が返る。
※rm
ファイルが存在しない場合はエラーとなる。
必ず終了ステータスを0で終らせるためのオプション -f がある。
※エラーの無視
コマンドの前に – をつけるとそのコマンドが失敗しても無視して続きを実行する
_◇例
①
CC = gcc
all: calc calcg
calc: calc.o eval.o parse.o
${CC} -o calc calc.o eval.o parse.o -lm
calcg: calcg.o eval.o parse.o widget.o
${CC} -o calcg calc.o eval.o parse.o \
-L/usr/X11R6/lib -lXext -lX11 -lm
clean:
rm -f *.o calc calcg
②
# makefile for MD5
CC = gcc
OBJS = md5c.o mddriver.o
md5.exe: $(OBJS)
$(CC) -o $@ $(OBJS)
.c.o:
$(CC) -c -DMD=5 $<
md5c.o: global.h md5.h
mddriver.o: global.h md5.h
③
patch.exe: $(OBJS)
$(CC) $(OBJS) $(LIBS) -o $@ $(LDFLAGS)
http://www.notwork.org/~gotoken/mag/softwaredesign/