ビルド処理
著者: 大和 正武 <yamato@redhat.com>生成日時: 20151102-17:59
Copyright © 2013 Red Hat, K.K. Copyright © 2015 Red Hat, K.K.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
アウトライン
• gccのコマンドライン • ビルド処理を理解するために知っておく必要がある。 • 読解を補助するのに小さなプログラムを書くことがある。 これをビルドするのにも役 立つ。 • ビルドツール • 読むべきソースコードを割り出すための予備知識として必要である。 • ソフトウェアによる違いが大きく、(C言語と比べて)解説した書籍も少ない。 • makeについて説明する。 • ライブラリgccのコマンドライン
• プリプロセス• コンパイル • リンク
gccのコマンドライン:プリプロセス
-Eオプションを使うとプリプロセスだけを実行できる。gccのコマンドライン:コンパイル
foo.cというソースコードファイルをコンパイルしてオブジェクトファイルfoo.oを得る ための 典型的なコマンドラインを示す。厳密には-Iと-Dはプリプロセッサ への指示である。
$ gcc -c -g -O2 -I. -I../include -DDEBUG=1 foo.c
-c リンク処理を実行せずコンパイル処理だけを実行する。 すなわちfoo.cからfoo.oを作成する。 -g デバッガが使うデバッグ情報を盛り込む。 -On 最適化を実施する。nが大きいほど激しく最適化する。 nに0を指定すると最適化しない。 5
gccのコマンドライン:コンパイル
インクルードファイルの探索パス
#include "FILE" #include <FILE> ファイルのインクルードの指示があった場合、次の場所を順番に探す。 1. "FILE"についてはカレントディレクトリ 2. gccに内蔵されたデフォルトの探索パス 3. -I オプションで指定されたパス$ gcc -c -g -O2 -I. -I../include -DDEBUG=1 foo.c
カレントディレクトリと親ディレクトリ下にあるincludeディレクトリから インクルードファ イルを探せという意味になる。
gccのコマンドライン:コンパイル
デフォルトの探索パス
空のファイルを用意して-vオプションをつけてgccを実行すると デフォルトの探索パスを確認 できる。 $ touch baz.c $ gcc -v baz.c#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/include /usr/local/include
/usr/include
End of search list.
gccのコマンドライン:コンパイル
マクロ定義
ソースコード上と同様にコマンドラインからマクロ定義できる。 #define DEBUG 1 をコマンドラインで定義すると次のようになる: -DDEBUG=1 次のような条件付きコンパイル箇所を制御するのに良く使われる。 #ifdef DEBUG #include <stdio.h>#define LOG(X) fprintf(stderr, "LOG: %s\n", X) #else
#define LOG(X) #endif
...
gccのコマンドライン:リンク
(この説明では共有ライブラリを想定している。)オブジェクトファイルとライブラリを連結して実行ファイルを生成する為の典型的な 典型的な コマンドラインを示す。
$ gcc -o my_app -L . -L ../libs -lmy_cypto -lmy_algorithm foo.o bar.o baz.o
-o 生成する実行ファイルの名前 -lNAME リンクするライブラリの名前 libNAME.soがリンクの対象となる。 -LDIR ライブラリファイルを探索するパス みつからないとデフォルトのライブラリ探索パスから探す。 実行ファイルの生成にあたり、実行ファイル中から参照されている全ての変数、 関数について 定義を発見できない場合、リンク処理は失敗する。 9
gccのコマンドライン:リンク
デフォルトのライブラリ探索パス
オプション -print-search-dirs をつけてgccを呼び出すと、gccに内蔵された デフォルトのラ イブラリパスを確認できる。 $ gcc -print-search-dirs ... libraries: =/usr/lib/gcc/x86_64-redhat-linux/4.7.2/:...gccのコマンドライン:リンク
リンクされているライブラリの確認
lddコマンドを使うとあるプログラムにどのようなライブラリが リンクされているか確認でき る。 $ ldd /usr/bin/vi linux-vdso.so.1 => (0x00007ffffaccd000) libselinux.so.1 => /lib64/libselinux.so.1 (0x0000003894800000) libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00000038a5c00000)libacl.so.1 => /lib64/libacl.so.1 (0x00000038a5800000) libc.so.6 => /lib64/libc.so.6 (0x0000003893000000)
libdl.so.2 => /lib64/libdl.so.2 (0x0000003893c00000) /lib64/ld-linux-x86-64.so.2 (0x0000003892c00000)
libattr.so.1 => /lib64/libattr.so.1 (0x00000038a4c00000)
ビルドツール
• gccなどのコマンドを呼び出してプログラム/ライブラリをビルドする。 • 手順を記したスクリプト(ビルドスクリプト)を入力とする。
ビルドツール: makeとMakefile
• コマンド名: make • 特に指定しない場合 Makefile をビルドスクリプトとして使う。 • 読むべきソースコードを割り出すのにMakefileを読まないといけないことがある。 • Makefileに記載したルールに基づいてビルドする。 • ファイルの更新時刻を比較して必要な部分だけをビルドする。 13ビルドツール: make
ルール
Makefileには、ビルドの各ステップ(ルール)を以下の書式で記述します。 成果物: 入力 ... 入力から成果物を得るコマンドライン ... • 「成果物」のことをターゲットと呼ぶ。 • 「入力から成果物を得るコマンドライン」のことをアクションと呼ぶ。 • あるルールでのターゲットが別のルールでの入力となっていても良い。ビルドツール: make
ビルド
• makeの引数にターゲットを指定すると現在のディレクトリからMakefileを探し、 ターゲット をビルドしようとする。 • ターゲットを省略した場合Makefile中の最初のルール中のターゲットを ビルドしょうとする。 $ make [ターゲット] • ターゲットに必要な入力が存在しない場合、あるいはターゲットよりも入力の方が 新しい場 合、まず入力をターゲットとしてビルドを実施する。 15ビルドツール: make
Makefileの例
myapp: foo.o bar.o
gcc -o myapp foo.o bar.o foo.o: foo.c gcc -c foo.c bar.o: bar.c gcc -c bar.c • myappを作るのにfoo.oとbar.oが必要である。 • foo.oが無ければまずfoo.oをターゲットとする。 • bar.oが無ければまずbar.oをターゲットとする。 • myappが存在しなければ、foo.oとbar.oをリンクして生成する。 • myappが存在してもfoo.oやbar.oよりも古ければリンクして生成する。 • foo.oを作るにはfoo.cが必要である。 • foo.oが無ければfoo.cを引数にgccを呼び出してfoo.oを生成する。 • foo.oがfoo.cよりも古い場合にもgccを呼び出してfoo.oを生成する。
• bar.oを作るにはbar.cが必要である。 ...
ビルドツール: make
変数
Makefile中での初期化 VAR = VALUE 参照 $(VAR) 例 CFLAGS = -O2myapp: foo.o bar.o
gcc -o myapp foo.o bar.o foo.o: foo.c
gcc -c $(CFLAGS) foo.c bar.o: bar.c
gcc -c $(CFLAGS) bar.c
ビルドツール: make
コマンドラインからの変数の指定
• コマンドラインからMakefile中で指定した変数の初期値を指定できる。 • Makefile中の記載に優先する。
make VAR1=VALUE1 VAR2=VALUE2 ... [target]
make CFALGS="-g -DDEBUG=1" myapp
ビルドツール: make
自動変数
• 値が文脈によって決まる特別な変数がある。 $@ そのルールのターゲットの名前 $< 先頭の入力 $^ 全ての入力 • 利用例 CFLAGS = -O2myapp: foo.o bar.o
gcc -o $@ $^ foo.o: foo.c
gcc -c $(CFLAGS) $< bar.o: bar.c
ビルドツール: make
内蔵ルール
• 典型的なルールはmakeコマンド内に定義されている。 CFLAGS=-g
myapp: foo.o bar.o
gcc -o $@ $^
• make -p -f /dev/nullとすると内蔵ルールの一覧が表示される。 • .cから.oを生成する内蔵ルールの抜粋
CC = cc
OUTPUT_OPTION = -o $@
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c .c.o:
$(COMPILE.c) $(OUTPUT_OPTION) $<
ビルドツール: make
makeの呼び出し元
• makeをどのように呼び出すか、ということはどのような目的でビルドするのか によって異な る。 • Fedoraに同梱されているパッケージについては、specファイルに記載した コマンドラインで makeを実行する。 • src.rpmをインストールするとspecファイルが ~/rpmbuild/SPECS以下に配置される。ライブラリ
ファイルの役割
• .hファイル(ヘッダファイル) • 変数や関数の宣言および型の定義が記載されている。 • コンパイル処理に必要となる。 • プログラムの実行時には必要ない。 • .soファイル • ライブラリに関連する変数や関数の定義が記載されている。 • リンク処理及び実行時に必要となる。 23ライブラリ
エクスポート
• ライブラリのソースコード中で「プログラム全域」のスコープを持つ変数と関 数だけが「エ クスポート」される。 • そのライブラリにリンクするアプリケーションやライブラリは「エクスポート」された 変数 と関数だけを利用できる。 • 「エクスポート」された変数、関数はヘッダファイルに宣言されているはず。ライブラリ
nmコマンド
nmコマンドを使うとライブラリから何が「エクスポート」されているかわかる。 $ nm -D /usr/lib/libz.so.1 ... U close 42681e30 T compress 42681d40 T compress2 U free ... T エクスポートされている関数 U 未定義の名前 B, D エクスポートされている変数 25ライブラリ
パッケージング
• 実行時に必要のあるファイルとコンパイル時に必要なファイルを分けて2つの バイナリパッ ケージが用意されている。 • ヘッダファイルを含むバイナリパッケージの名前には-develというサフィックスが付く。 • ソースパッケージは共通である。ライブラリ
develパッケージの例
$ rpm -qi zlibName : zlib ...
Summary : The zlib compression and decompression library $ rpm -ql zlib /lib64/libz.so.1 /lib64/libz.so.1.2.5 ... $ rpm -qi zlib-devel Name : zlib-devel ...
Summary : Header files and libraries for Zlib development $ rpm -ql zlib-devel
/usr/include/zlib.h ...