gccのオプションなど自分なりのmemo
#include <stdio.h> 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
$ 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!
gccに "-E" or "-S" を指定する事で、成果物の段階を指定できる。
"-E"オプションを指定すると、プリプロセッサまでが実行される。"-o"をつけないと標準出力に出力される。
$ 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"オプションを指定してみる。
$ 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"コマンドの実行まで処理している事が確認できる。
$ 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"オプションを指定すると、アセンブラまでが実行される。
$ 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"オプションでオブジェクトファイルの生成までを行える。
$ 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
最後にオブジェクトファイルを入力として、実行形式のファイルを作成する。
$ 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!
"#include"パスの追加指定は"-I"オプションを使う。
gcc (...) -I/usr/include/xxxyyy -I/opt/include/zzzz (...)
コンパイル時の"*.so"のディレクトリ指定は"-L"オプションを使う。
gcc (...) -L/usr/lib/xxxyyyy (...)
"libxyz(.<major>.<minor>.<minor2>).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:
#include <stdio.h> #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:
int calc1(int a, int b); int calc2(int a, int b);
calc/calc1.c: (足し算)
int calc1(int a, int b) { return a + b; }
calc/calc1.c: (掛け算)
int calc2(int a, int b) { return a * b; }
calc1, calc2を含んだライブラリを静的・動的それぞれのパターンで作成し、call_calc.cとリンクさせてみる。
binutilsのarコマンドでlibcalc.aを生成する。"-r"で格納するアーカイブファイル名を指定する。"-s"オプションで、リンクを早くする為に予め索引を作っておく。作成された索引は "nm -s" で確認できる。
$ 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を後ろに指定する。
$ 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" 付で位置独立コードとしてコンパイルする。
$ 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があるディレクトリを指定し、実行する。
$ 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
gcc-4.1.2 のmanページから抜粋:
-Wa,option
option をアセンブラに対するオプションとして渡します。
option がコンマを含む場合は、そのコンマで区切られた複数のオプションとして与えられます。
-Wl,option
オプション option をリンカに渡します。
option がコンマを含む場合は、それらのコンマで複数のオプションとして分割されます。
他、書籍・雑誌記事・Webなどから拾い読みしたTIPSなど。
gccオプション:
-print-prog-name=XXXXX : gccがkickする外部コマンドの絶対パス表示 -Wall : 全ての警告を表示 -Werror : 警告をエラーと見なす
cppオプション:
-H : indent形式でインクルードの状況を表示 -M : Makefile形式で外部依存ファイルリストを表示 -dM : 全てのマクロ定義文表示。空のファイルを読ませれば、ビルトイン定義を表示してくれる。 -nostdinc : ヘッダーファイル検索パスを初期化 -v : 詳細表示