#navi_header|C言語系| gccのオプションなど自分なりのmemo #outline ---- * 基本 #code|C|> #include int main(int argc, char **argv) { printf("Hello, World!\n"); return 0; } ||< 何も指定しない場合はa.outで出力する。 $ gcc hello.c $ ls a.out* hello.c $ ./a.out Hello, World! 出力ファイル名を指定したい場合は、 "-o" オプションを使う。 $ gcc -o hello hello.c $ ls hello* hello.c $ ./hello Hello, World! オブジェクトファイル(*.o)までの生成にしておきたい場合は "-c" オプションを使う。 $ gcc -c hello.c $ ls hello.c hello.o "-c" オプションと "-o" オプションの併用例: $ gcc -c -o hello_obj.o hello.c $ ls hello.c hello_obj.o * コマンドラインオプション ** "--save-temps", "-v" : 途中成果物の保存と実行内容詳細表示 #pre||> $ gcc --save-temps -v hello.c Using built-in specs. Target: i386-redhat-linux (...) as -V -Qy -o hello.o hello.s GNU assembler version 2.17.50.0.6-6.el5 (i386-redhat-linux) using BFD version 2.17.50.0.6-6.el5 20061020 /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 (...) $ ls a.out hello.c hello.i hello.o hello.s $ ./a.out Hello, World! ||< ** "-E", "-S" : プリプロセスまで/アセンブルまで gccに "-E" or "-S" を指定する事で、成果物の段階を指定できる。 *** "-E" : プリプロセスまで "-E"オプションを指定すると、プリプロセッサまでが実行される。"-o"をつけないと標準出力に出力される。 #pre||> $ gcc -E hello.c # 1 "hello.c" (...) # 2 "hello.c" 2 int main(int argc, char **argv) { printf("Hello, World!\n"); return 0; } $ ls hello.c ||< "-o"オプションを指定してみる。 #pre||> $ gcc -E -o hello.i hello.c $ ls hello.c hello.i (プリプロセスの出力ファイルからコンパイルを継続することも出来る) $ gcc hello.i $ ls a.out* hello.c hello.i $ ./a.out Hello, World! ||< "-v"をつけてみると、cppパッケージの"cc1"コマンドの実行まで処理している事が確認できる。 #pre||> $ gcc -v -E -o hello.i hello.c Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 \ -E -quiet -v hello.c -o hello.i -mtune=generic 存在しないディレクトリ \ "/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../i386-redhat-linux/include" \ を無視します #include "..." の探索はここから始まります: #include <...> の探索はここから始まります: /usr/local/include /usr/lib/gcc/i386-redhat-linux/4.1.2/include /usr/include 探索リストの終わり $ ||< ※CentOS 5.2 の場合、cppコマンドは "cpp" というRPMパッケージに"cc1"と併せて収録されている。では"cpp"パッケージは"gcc"とは別物か?となるが、RPMパッケージ情報を調べると下記の通り Source RPMは"gcc"になっている。RPMパッケージングの際に、バージョニングの都合などで分離されたものと思われる(cc1まで入れてしまったら分離する意味が無いような気もするが・・・)。 $ rpm -qi cpp Name : cpp Relocations: (not relocatable) Version : 4.1.2 Vendor: CentOS Release : 42.el5 Build Date: 2008年05月27日 07時17分35秒 Install Date: 2008年08月02日 13時40分43秒 Build Host: builder16.centos.org Group : Development/Languages Source RPM: gcc-4.1.2-42.el5.src.rpm ^^^^^^^^^^^^^^^^^^^^^^^^^ *** "-S" : アセンブラまで "-S"オプションを指定すると、アセンブラまでが実行される。 #pre||> $ ls hello.c hello.i $ gcc -v -S hello.i Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) /usr/libexec/gcc/i386-redhat-linux/4.1.2/cc1 -fpreprocessed hello.i -quiet \ -dumpbase hello.i -mtune=generic -auxbase hello -version -o hello.s GNU C version 4.1.2 20071124 (Red Hat 4.1.2-42) (i386-redhat-linux) compiled by GNU C version 4.1.2 20071124 (Red Hat 4.1.2-42). GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64436 Compiler executable checksum: 6b8fcfb678815bd99e272234accc87cd $ ls hello.c hello.i hello.s ||< この後、"-c"オプションでオブジェクトファイルの生成までを行える。 #pre||> $ gcc -v -c hello.s Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) as -V -Qy -o hello.o hello.s GNU assembler version 2.17.50.0.6-6.el5 (i386-redhat-linux) using BFD version 2.17.50.0.6-6.el5 20061020 $ ls hello.c hello.i hello.o hello.s ||< 最後にオブジェクトファイルを入力として、実行形式のファイルを作成する。 #pre||> $ gcc -o hello hello.o Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure --prefix=/usr (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 (...) $ ls hello* hello.c hello.i hello.o hello.s $ ./hello Hello, World! ||< ** "-I", "-L", "-l"オプション "#include"パスの追加指定は"-I"オプションを使う。 gcc (...) -I/usr/include/xxxyyy -I/opt/include/zzzz (...) コンパイル時の"*.so"のディレクトリ指定は"-L"オプションを使う。 gcc (...) -L/usr/lib/xxxyyyy (...) "libxyz(...).so"を指定したい場合は、"-l"オプションで"xyz"の部分だけを指定する。 gcc (...) -lxyz (...) "-I", "-L", "-l" 共に、値との間に空白は挟まない。 NG: gcc (...) -I /usr/include/xxyyzz (...) ^ ** ライブラリの作成とリンク例 静的・動的のそれぞれの作成とリンクのサンプルを載せる。(なお、以降出てくるgccのオプションで"-Wall"が付いていないのはサンプルだから、ということでご了承願います) ソースコード構成: $ ls calc/ call_calc.c $ ls calc/ calc.h calc1.c calc2.c call_calc.c: #code|c|> #include #include "calc.h" int main(int argc, char **argv) { int x = 1; int y = 2; int z1 = calc1(x, y); int z2 = calc2(x, y); printf("calc1(%d, %d) = %d\n", x, y, z1); printf("calc2(%d, %d) = %d\n", x, y, z2); return 0; } ||< calc/calc.h: #code|c|> int calc1(int a, int b); int calc2(int a, int b); ||< calc/calc1.c: (足し算) #code|c|> int calc1(int a, int b) { return a + b; } ||< calc/calc1.c: (掛け算) #code|c|> int calc2(int a, int b) { return a * b; } ||< calc1, calc2を含んだライブラリを静的・動的それぞれのパターンで作成し、call_calc.cとリンクさせてみる。 *** 静的ライブラリの作成とリンク binutilsのarコマンドでlibcalc.aを生成する。"-r"で格納するアーカイブファイル名を指定する。"-s"オプションで、リンクを早くする為に予め索引を作っておく。作成された索引は "nm -s" で確認できる。 #pre||> $ cd ./calc $ ls calc.h calc1.c calc2.c $ gcc -c -o calc1_nofpic.o calc1.c $ gcc -c -o calc2_nofpic.o calc2.c $ ar -s -r libcalc.a calc1_nofpic.o calc2_nofpic.o ar: creating libcalc.a $ ar t libcalc.a calc1_nofpic.o calc2_nofpic.o [msakamoto@akane calc]$ nm -s libcalc.a Archive index: calc1 in calc1_nofpic.o calc2 in calc2_nofpic.o calc1_nofpic.o: 00000000 T calc1 calc2_nofpic.o: 00000000 T calc2 $ ls calc.h calc1.c calc1_nofpic.o calc2.c calc2_nofpic.o libcalc.a ||< 続いてcall_calc.cをコンパイル・リンクする。"-I"でcalc.hのあるディレクトリを指定する。リンク時には、libcalc.aを後ろに指定する。 #pre||> $ cd ../ $ ls calc call_calc.c $ gcc -Wall -I./calc -c -o call_calc.o call_calc.c $ ls calc call_calc.c call_calc.o $ gcc -v -o call_calc_static call_calc.o ./calc/libcalc.a Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 \ (...) -o call_calc_static (...) call_calc.o ./calc/libcalc.a (...) $ ls calc call_calc.c call_calc.o call_calc_static* $ ./call_calc_static calc1(1, 2) = 3 calc2(1, 2) = 2 ||< *** 動的ライブラリの作成とリンク calc1.c, calc2.cを "-fPIC" 付で位置独立コードとしてコンパイルする。 #pre||> $ cd ./calc $ ls calc.h calc1.c calc1_nofpic.o calc2.c calc2_nofpic.o libcalc.a $ gcc -fPIC -c -o calc1_pic.o calc1.c $ gcc -fPIC -c -o calc2_pic.o calc2.c $ gcc -shared -o libcalc.so calc1_pic.o calc2_pic.o $ ls calc.h calc1.c calc1_nofpic.o calc1_pic.o calc2.c calc2_nofpic.o calc2_pic.o libcalc.a libcalc.so* ||< ※今回のサンプルでは"-Wl,-soname=xxxx"は使わない。後日このオプションについて検証する。 続いてcall_calc.cをコンパイル・リンクする。"-I"でcalc.hのあるディレクトリを指定する。リンク時には、"-L"でlibcalc.soの存在するディレクトリを指定し、"-l"でライブラリ名("calc")を指定する。今回はシステムのライブラリディレクトリにはインストールしないので、一時的にLD_LIBRARY_PATHでlibcalc.soがあるディレクトリを指定し、実行する。 #pre||> $ cd ../ $ ls calc call_calc.c call_calc.o call_calc_static* $ gcc -v -L./calc -lcalc -o call_calc_so call_calc.o Using built-in specs. Target: i386-redhat-linux コンフィグオプション: ../configure (...) スレッドモデル: posix gcc バージョン 4.1.2 20071124 (Red Hat 4.1.2-42) /usr/libexec/gcc/i386-redhat-linux/4.1.2/collect2 (...) \ -o call_calc_so (...) -L./calc (...) -lcalc call_calc.o (...) $ export LD_LIBRARY_PATH=./calc; ./call_calc_so calc1(1, 2) = 3 calc2(1, 2) = 2 ||< ** "-Wa,...", "-Wl,..." gcc-4.1.2 のmanページから抜粋: -Wa,option option をアセンブラに対するオプションとして渡します。 option がコンマを含む場合は、そのコンマで区切られた複数のオプションとして与えられます。 -Wl,option オプション option をリンカに渡します。 option がコンマを含む場合は、それらのコンマで複数のオプションとして分割されます。 * TIPS 他、書籍・雑誌記事・Webなどから拾い読みしたTIPSなど。 gccオプション: -print-prog-name=XXXXX : gccがkickする外部コマンドの絶対パス表示 -Wall : 全ての警告を表示 -Werror : 警告をエラーと見なす cppオプション: -H : indent形式でインクルードの状況を表示 -M : Makefile形式で外部依存ファイルリストを表示 -dM : 全てのマクロ定義文表示。空のファイルを読ませれば、ビルトイン定義を表示してくれる。 -nostdinc : ヘッダーファイル検索パスを初期化 -v : 詳細表示 #navi_footer|C言語系|